Harris corner detection


1 Harris corner demo

opencv_tutorials.pdf中的例子:

/**
 * @function cornerHarris_Demo.cpp
 * @brief Demo code for detecting corners using Harris-Stephens method
 * @author OpenCV team
 */

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>

using namespace cv;
using namespace std;

/// Global variables
Mat src, src_gray;
int thresh = 124;
int max_thresh = 255;

const char* filename = "Sydney_opera_house.jpg";
const char* source_window = "Source image";
const char* corners_window = "Corners detected";

cv::RNG rng(12345);

/// Function header
void cornerHarris_demo(int, void*);

/**
 * @function main
 */
int main(int, char** argv)
{
    /// Load source image and convert it to gray
    src = imread(filename, CV_LOAD_IMAGE_ANYCOLOR);
    if (src.empty()){
        cout << "Can't load the image." << endl;
        return -1;
    }

    if (src.channels() == 3){
        cvtColor(src, src_gray, COLOR_BGR2GRAY);
    }
    else{
        src_gray = src.clone();
    }

    /// Create a window and a trackbar
    namedWindow(source_window, WINDOW_AUTOSIZE);
    createTrackbar("Threshold: ", source_window, &thresh, max_thresh, cornerHarris_demo);
    imshow(source_window, src_gray);

    cornerHarris_demo(0, 0);

    waitKey(0);
    return(0);
}

/**
 * @function cornerHarris_demo
 * @brief Executes the corner detection and draw a circle around the possible corners
 */
void cornerHarris_demo(int, void*)
{
    Mat dst, dst_norm, dst_norm_scaled;
    dst = Mat::zeros(src.size(), CV_32FC1);

    /// Detector parameters
    int blockSize = 2;
    int apertureSize = 3;
    double k = 0.04;

    /// Detecting corners
    cornerHarris(src_gray, dst, blockSize, apertureSize, k, BORDER_DEFAULT);

    /// Normalizing
    normalize(dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat());
    convertScaleAbs(dst_norm, dst_norm_scaled);

    cv::Mat drawing;
    src.copyTo(drawing);
    /// Drawing a circle around corners
    for (int j = 0; j < dst_norm.rows; j++)
    {
        for (int i = 0; i < dst_norm.cols; i++)
        {
            if ((int)dst_norm.at<float>(j, i) > thresh)
            {
                circle(drawing, Point(i, j), 4, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255), 255)
                    , 2, 8, 0);
            }
        }
    }
    /// Showing the result
    namedWindow(corners_window, WINDOW_AUTOSIZE);
    imshow(corners_window, drawing);
    //imwrite("corner.png", drawing);
}

检测效果图:
这里写图片描述


2 Harris corner detection(source code analysis in OpenCV )

关于Harris角点检测的具体内容可以参考: Corner detection(Wikipedia)Harris角点检测原理与流程.ppt,主要分析Harris 角点检测在OpenCV中是如何实现的:

Step 1

Harris 角点检测接口cornerHarris()

void cv::cornerHarris( InputArray _src, OutputArray _dst, int blockSize, int ksize, double k, int borderType )
{
    Mat src = _src.getMat();
    _dst.create( src.size(), CV_32F );
    Mat dst = _dst.getMat();
    cornerEigenValsVecs( src, dst, blockSize, ksize, HARRIS, k, borderType );
}

Step 2

OpenCV 内部调用cornerEigenValsVecs()实现Harris焦点检测:

static void
cornerEigenValsVecs( const Mat& src, Mat& eigenv, int block_size,
                     int aperture_size, int op_type, double k=0.,
                     int borderType=BORDER_DEFAULT )
{
#ifdef HAVE_TEGRA_OPTIMIZATION
    if (tegra::cornerEigenValsVecs(src, eigenv, block_size, aperture_size, op_type, k, borderType))
        return;
#endif

    int depth = src.depth();
    double scale = (double)(1 << ((aperture_size > 0 ? aperture_size : 3) - 1)) * block_size;
    if( aperture_size < 0 )
        scale *= 2.;
    if( depth == CV_8U )
        scale *= 255.;
    scale = 1./scale;

    CV_Assert( src.type() == CV_8UC1 || src.type() == CV_32FC1 );

    Mat Dx, Dy;
    if( aperture_size > 0 )
    {
        Sobel( src, Dx, CV_32F, 1, 0, aperture_size, scale, 0, borderType );
        Sobel( src, Dy, CV_32F, 0, 1, aperture_size, scale, 0, borderType );
    }
    else
    {
        Scharr( src, Dx, CV_32F, 1, 0, scale, 0, borderType );
        Scharr( src, Dy, CV_32F, 0, 1, scale, 0, borderType );
    }

    Size size = src.size();
    Mat cov( size, CV_32FC3 );
    int i, j;

    for( i = 0; i < size.height; i++ )
    {
        float* cov_data = (float*)(cov.data + i*cov.step);
        const float* dxdata = (const float*)(Dx.data + i*Dx.step);
        const float* dydata = (const float*)(Dy.data + i*Dy.step);

        for( j = 0; j < size.width; j++ )
        {
            float dx = dxdata[j];
            float dy = dydata[j];

            cov_data[j*3] = dx*dx;
            cov_data[j*3+1] = dx*dy;
            cov_data[j*3+2] = dy*dy;
        }
    }

    boxFilter(cov, cov, cov.depth(), Size(block_size, block_size),
        Point(-1,-1), false, borderType );

    if( op_type == MINEIGENVAL )
        calcMinEigenVal( cov, eigenv );
    else if( op_type == HARRIS )
        calcHarris( cov, eigenv, k );
    else if( op_type == EIGENVALSVECS )
        calcEigenValsVecs( cov, eigenv );
}
}

这一部分通过Sobel算子计算得到在每个像素点处的x/y方向的梯度,并将x/y处的偏导数保存在与原图size相同,但depth = 3的矩阵cov中,最后调用calcHarris()cov进行处理。

Step 3

static void
calcHarris( const Mat& _cov, Mat& _dst, double k )
{
    int i, j;
    Size size = _cov.size();

    if( _cov.isContinuous() && _dst.isContinuous() )
    {
        size.width *= size.height;
        size.height = 1;
    }

    for( i = 0; i < size.height; i++ )
    {
        const float* cov = (const float*)(_cov.data + _cov.step*i);
        float* dst = (float*)(_dst.data + _dst.step*i);
        j = 0;

        for( ; j < size.width; j++ )
        {
            float a = cov[j*3];
            float b = cov[j*3+1];
            float c = cov[j*3+2];
            dst[j] = (float)(a*c - b*b - k*(a + c)*(a + c));
        }
    }
}

计算了Harris角点检测原理与流程.ppt中每个像素的角点响应函数:

R=detMk(traceM)2

其中 M Step 2计算:
M=x,yw(x,y)[I2x IxIyIxIyI2y]

NOTE: Source code path: D:\opencv\sources\modules\imgproc\src\corner.cpp


猜你喜欢

转载自blog.csdn.net/wwchao2012/article/details/51303993