opencv中的harris角点检测函数

函数接口

//! computes Harris cornerness criteria at each image pixel
CV_EXPORTS_W void cornerHarris( InputArray src, OutputArray dst, int blockSize,
                                int ksize, double k,
                                int borderType=BORDER_DEFAULT );

参数说明

src —— 待检测图像,单通道灰度图
dst —— 角点响应值,类型CV_32FC1
blockSize —— 论文中窗口大小,下面细说
ksize —— sobel窗口大小
k —— 原始论文里的调节参数 0.04到0.05之间
borderType —— 边界处理方式

其实写这个我想说明的就是这个blockSize和ksize的意义,查看源码

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 );//参数ksize
        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 );//参数blockSize

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

}

标出了使用两个参数的位置,其中ksize是sobel算子窗体大小就不用多说了,越大抗噪声能力越强,但模糊也更加严重。opencv用sobel来计算dx和dy,进而求得dx*dy dx*dx dy*dy,也即求得原方法中的海森矩阵。在论文中二次型参数M,是一个窗口内的海森矩阵加权和。窗口可以为方形或者高斯,opencv使用了boxFilter函数(窗口大小由blocksize控制)来实现方形窗口。论文这么实现应该主要还是为了抗噪。不要让噪声成为角点被检测出来,另外也可以用这两个参数来控制角点对比度。所以值的选取要看具体的应用场景中噪声的特性了。

示例代码

#include
#include
#include
using namespace std;
using namespace cv;

int thres;
int blockSize;
int kSize;
void harrisCorner(int,void *){
   Mat srcImg;
   Mat grayImg,dst_norm,dst_normScale;
   Mat responseImg = Mat::zeros( srcImg.size(), CV_32FC1 );
   vector vConners;
   //1.读取图片
   srcImg=imread("box.png");
   cvtColor(srcImg,grayImg,CV_RGB2GRAY);
   //2.检查参数
   if(blockSize<2)
       blockSize=2;
   if(kSize<3)
       kSize=3;
   //3.计算角点可能性
   cornerHarris(grayImg,responseImg,blockSize,kSize,0.04); //  sobel size
   cv::normalize(responseImg,dst_norm,0,255,NORM_MINMAX,CV_32FC1);
   cv::convertScaleAbs(dst_norm,dst_normScale);//归一化到0~255
   //4.根据阈值记录角点
   for(int y=0;yunsigned char *ptr=dst_normScale.data+y*dst_normScale.cols;
       for(int x=0;xif(*ptr>thres){
               vConners.push_back(Point2d(x,y));
           }
           ptr++;
       }
   }
   //5.显示
   for(auto &p : vConners){
       circle(srcImg,p,5,Scalar(0,0,0));
   }
   imshow("showConners",srcImg);
}

int main(){
    namedWindow("showConners");
    thres=100;
    blockSize=2;
    kSize=3;
    createTrackbar("thres","showConners",&thres,255,harrisCorner);
    createTrackbar("blockSize","showConners",&blockSize,10,harrisCorner);
    createTrackbar("kSize","showConners",&kSize,10,harrisCorner);
    waitKey(0);
    return 0;
}

opencv中的harris角点检测函数_第1张图片

另外一些离的很近的角点可以用非极大值抑制来消除,窗体大小可参考blockSize的大小,一种实现如下

   //4.根据阈值记录角点
   for(int y=1;y1;y++){
       unsigned char *ptrT=dst_normScale.data+(y-1)*dst_normScale.cols;
       unsigned char *ptrC=dst_normScale.data+y*dst_normScale.cols;
       unsigned char *ptrB=dst_normScale.data+(y+1)*dst_normScale.cols;
       for(int x=1;x1;x++){
           if(*ptrC>thres){
               if(ptrC[0]1]||ptrC[0]1])
                   goto CON;
               if(ptrC[0]1]||ptrC[0]1]||ptrC[0]0])
                   goto CON;
               if(ptrC[0]1]||ptrC[0]1]||ptrC[0]0])
                   goto CON;
               vConners.push_back(Point2d(x,y));
           }
           CON:
           ptrC++;
           ptrB++;
           ptrT++;
       }
   }

opencv中的harris角点检测函数_第2张图片

你可能感兴趣的:(图像处理)