opencv中的harris角点检测函数

来源:互联网 发布:netbeans php下载 编辑:程序博客网 时间:2024/05/17 18:02

函数接口

//! computes Harris cornerness criteria at each image pixelCV_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 voidcornerEigenValsVecs( 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<iostream>#include<opencv2/opencv.hpp>#include<opencv2/imgproc/imgproc.hpp>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<Point2d> 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;y<dst_normScale.rows;y++){       unsigned char *ptr=dst_normScale.data+y*dst_normScale.cols;       for(int x=0;x<dst_normScale.cols;x++){           if(*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;}

这里写图片描述

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

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

这里写图片描述

原创粉丝点击