harris角点检测

来源:互联网 发布:英国人 知乎 编辑:程序博客网 时间:2024/04/30 06:46

原理:

Harris角点检测最直观的解释是:在任意两个相互垂直的方向上,都有较大变化的点---harrisA combined corner and edge detector这篇文章中提出来的。


moravec角点检测中,w(x,y)的取值是二元的,在窗口内部就取值为1,在窗口外部就取值为0,在harris的角点检测中,使用的是高斯窗口,所以w(x,y)表示的是高斯窗口中的权重。此时 当uv取两组相互垂直的值时,E(u,v)都有较大值的点。

公式推导:

根据二阶taylor展开式得出:

如何考虑E(u,v)在两个相互垂直的方向上都取得最大值呢?我们可以先求出E(u,v)在一个方向上的最大值为r1,即E(u1,v1) = r1,然后求其垂直方向上的值r2,我们意外的发现这里的r1r2分别对应M的两个特征值,对应的向量(u1,v1),(u2,v2)M的特征向量,此处的M被称为Hessian矩阵。

判断是否为角点的标准:

r1,r2都很小,对应于图像中的平滑区域

r1,r2都很大,对应于图像中的角点

r1r2一个很大,一个很小,对应于图像中的边缘

Harris角点量计算公式: R = det(M) – a*trace(M)^2,其中a为经验值,取值范围介于[0.04, 0.06],另一种角点量计算方法:R = det(M)/trace(M)—这个公式自由发挥,只要能反应角点的特征就可以了

其中det(M) = r1*r2 = AB –C^2

    Trace(M) = r1+r2 =A+B (其中A=Ix^2;;  B = Iy^2;;; C=IxIy

角点检测的步骤

根据上述的讨论,harris角点检测的步骤可以总结为:

         <1>计算图像I(x,y)在x和y两个方向的梯度Ix,Iy:

         <2>计算梯度方向的乘积

    <3>使用高斯核对Ix^2,Iy^2,IxIy进行加权,计算矩阵M的元素A,B,C


    <4>根据计算角点量,并设定阀值,当角点量小于阀值,不是候选角点

    <5>进行局部极大值抑制

代码:

[cpp] view plaincopyprint?
  1. #include <iostream>  
  2. #include "cv.h"  
  3. #include "cxcore.h"  
  4. #include "highgui.h"  
  5. using namespace std;  
  6.   
  7.   
  8.   
  9. //harris 角点检测需要的参数  
  10. typedef struct HARRISPARAMS  
  11. {  
  12.     int gaussSize; //高斯窗口  
  13.     float gaussSigma; //高斯方差  
  14.     double threshold; //对角点量设定的阈值  
  15.     int maximumSize; //局部极大值抑制时的窗口大小  
  16.       
  17. }HARRISPARAMS,*PHARRISPARAMS;  
  18.   
  19.   
  20. /******************************* 
  21. *对源图像进行卷积运算 
  22. *输入项 
  23. *srcFloat    源图像 
  24. *Ix          卷积的结果 
  25. *dxTemplate  卷积模板 
  26. *widthTemplate 模板的宽度 
  27. *heightTemplate 模板的高度 
  28. ********************************/  
  29. void convolution(IplImage* srcFloat,IplImage* Ix,double* dxTemplate , int widthTemplate,int heightTemplate);  
  30.   
  31.   
  32. /*************************** 
  33. *harris角点检测函数 
  34. *输入项 
  35. *srcIn   源图像 
  36. *params  harris角点检测需要的参数 
  37. *corners 存放harris角点坐标 
  38. ****************************/  
  39. void getHarrisPoints(IplImage* srcIn,PHARRISPARAMS params,CvSeq* corners);  
  40.   
  41. //主函数  
  42. int main(int argc, char* argv[])  
  43. {  
  44.   
  45.     //相关变量  
  46.     IplImage* src,*srcGray;  
  47.     CvMemStorage* mem = cvCreateMemStorage(0);  
  48.     CvSeq* harrisPoints;  
  49.     HARRISPARAMS harrisParams;  
  50.   
  51.     src = cvLoadImage("E:\\study_opencv_video\\lesson17_2\\2.jpg");//源图像  
  52.       
  53.     srcGray = cvCreateImage(cvGetSize(src),8,1);        // 灰度图像  
  54.       
  55.     if(!src)  
  56.     {  
  57.         cout << " src is null";  
  58.         return 0;  
  59.     }  
  60.       
  61.     cvCvtColor(src,srcGray,CV_BGR2GRAY);  
  62.   
  63.     //harris角点保存的空间  角点坐标保存在一个序列中  
  64.     harrisPoints = cvCreateSeq(0,sizeof(CvSeq),sizeof(CvPoint),mem);  
  65.       
  66.     //设置相关参数  
  67.     harrisParams.gaussSize = 5;   // 高斯窗口的大小  
  68.     harrisParams.gaussSigma = 0.8;  
  69.     harrisParams.threshold = 1000;  
  70.     harrisParams.maximumSize = 21;  
  71.   
  72.     //进行harris角点检测  
  73.     getHarrisPoints(srcGray,&harrisParams,harrisPoints);  
  74.       
  75.     //获取每一个角点的坐标  
  76.     for(int x=0;x<harrisPoints->total;x++)  
  77.     {  
  78.         //获取第x个角点的坐标  
  79.         CvPoint* pt = (CvPoint*)cvGetSeqElem(harrisPoints,x);  
  80.   
  81.         //以角点坐标为中心  绘制一个半径为5的圆  
  82.         cvCircle(src,*pt,2,cvScalar(255,0,255,0));  
  83.     }  
  84.   
  85.     //cvSaveImage("dst.jpg",src);  
  86.   
  87.     //显示图像  
  88.     cvNamedWindow("dst");  
  89.     cvShowImage("dst",src);  
  90.     cvWaitKey(0);  
  91.   
  92.     //释放资源  
  93.     cvReleaseImage(&src);  
  94.     cvReleaseImage(&srcGray);  
  95.     cvReleaseMemStorage(&mem);  
  96.     return 0;  
  97. }  
  98.   
  99. /*************************** 
  100. *harris角点检测函数 
  101. *输入项 
  102. *srcIn   源图像 
  103. *params  harris角点检测需要的参数 
  104. *corners 存放harris角点坐标 
  105. ****************************/  
  106. void getHarrisPoints(IplImage* srcIn,PHARRISPARAMS params,CvSeq* corners)  
  107. {  
  108.     int x,y;  
  109.   
  110.     IplImage* srcFloat;  
  111.       
  112.     srcFloat = cvCreateImage(cvGetSize(srcIn),32,1);  
  113.       
  114.     cvConvertScale(srcIn,srcFloat);  
  115.       
  116.     IplImage *Ix,*Iy,*IxIx,*IyIy,*IxIy,*A,*B,*C,*cornerness;  
  117.     double *gaussWindow = new double[sizeof(double)*params->gaussSize*params->gaussSize];  
  118.     //水平方向差分算子并求Ix  
  119.      double dxTemplate[9]={-1,0,1,  
  120.                            -1,0,1,  
  121.                            -1,0,1};  
  122.   
  123.     //垂直方向差分算子并求Iy  
  124.      double dyTemplate[9]={-1,-1,-1,  
  125.                             0, 0, 0,  
  126.                             1, 1, 1};  
  127.       
  128.      //此处内存用得有点奢侈 请大家自行修改 节省内存  
  129.      //下面变量的含义与 第二十四集harris角点检测数学原理 的文档资料中定义的变量含义是一样的  请参阅  
  130.     Ix = cvCreateImage(cvGetSize(srcFloat),32,1);  
  131.     Iy = cvCreateImage(cvGetSize(srcFloat),32,1);  
  132.     IxIx = cvCreateImage(cvGetSize(srcFloat),32,1);  
  133.     IyIy = cvCreateImage(cvGetSize(srcFloat),32,1);  
  134.     IxIy = cvCreateImage(cvGetSize(srcFloat),32,1);  
  135.     A = cvCreateImage(cvGetSize(srcFloat),32,1);  
  136.     B = cvCreateImage(cvGetSize(srcFloat),32,1);  
  137.     C = cvCreateImage(cvGetSize(srcFloat),32,1);  
  138.     cornerness = cvCreateImage(cvGetSize(srcFloat),32,1); //保存角点量  
  139.   
  140.     convolution(srcFloat,Ix,dxTemplate,3,3); //计算Ix  
  141.     convolution(srcFloat,Iy,dyTemplate,3,3); //计算Iy   
  142.   
  143.     //计算Ix2、Iy2、IxIy  
  144.     for(y=0;y<srcFloat->height;y++)  
  145.     {  
  146.         for(x=0;x<srcFloat->width;x++)  
  147.         {  
  148.             float IxValue,IyValue;  
  149.               
  150.             IxValue = cvGetReal2D(Ix,y,x);  
  151.             IyValue = cvGetReal2D(Iy,y,x);  
  152.   
  153.             cvSetReal2D(IxIx,y,x,IxValue*IxValue);  
  154.             cvSetReal2D(IyIy,y,x,IyValue*IyValue);  
  155.             cvSetReal2D(IxIy,y,x,IxValue*IyValue);  
  156.   
  157.               
  158.         }  
  159.     }  
  160.   
  161.     //计算高斯窗口  
  162.     for( y=0;y<params->gaussSize;y++)  
  163.     {  
  164.         for( x=0;x<params->gaussSize;x++)  
  165.         {  
  166.               
  167.             float dis,weight;  
  168.               
  169.             dis = (y-params->gaussSize/2)*(y-params->gaussSize/2)+(x-params->gaussSize/2)*(x-params->gaussSize/2);  
  170.             weight = exp(-dis/(2.0*params->gaussSigma));  
  171.             *(gaussWindow+y*params->gaussSize+x)=weight;       
  172.               
  173.         }  
  174.     }  
  175.        
  176.     convolution(IxIx,A,gaussWindow,params->gaussSize,params->gaussSize);//计算IxIx与高斯的卷积  
  177.     convolution(IyIy,B,gaussWindow,params->gaussSize,params->gaussSize);//计算IyIy与高斯的卷积  
  178.     convolution(IxIy,C,gaussWindow,params->gaussSize,params->gaussSize);//计算IxIy与高斯的卷积  
  179.   
  180.     //计算角点量  
  181.     for(y=0;y<srcFloat->height;y++)  
  182.     {  
  183.         for(x=0;x<srcFloat->width;x++)  
  184.         {  
  185.             double cornernessValue,Avalue,Bvalue,Cvalue;  
  186.             Avalue = cvGetReal2D(A,y,x);  
  187.             Bvalue = cvGetReal2D(B,y,x);  
  188.             Cvalue = cvGetReal2D(C,y,x);  
  189.               
  190.             cornernessValue = (Avalue*Bvalue-Cvalue*Cvalue)/(Avalue+Bvalue+0.0000001);  
  191.               
  192.             cvSetReal2D(cornerness,y,x,fabs(cornernessValue));    
  193.         }  
  194.       
  195.     }  
  196.   
  197.     //计算局部极大值 及 极大值是否大于阈值  
  198.     int beginY,endY,beginX,endX;  
  199.     int halfWinSize = params->maximumSize/2;  
  200.   
  201.     beginY = halfWinSize;  
  202.     endY = cornerness->height - halfWinSize;  
  203.   
  204.     beginX = halfWinSize;  
  205.     endX = cornerness->width - halfWinSize;  
  206.       
  207.     for(y=beginY;y<endY;)  
  208.     {  
  209.         for(x=beginX;x<endX;)  
  210.         {  
  211.             //寻找局部极大值 及其位置信息  
  212.             float maxValue=0;  
  213.             int flag = 0 ;  
  214.             CvPoint maxLoc;  
  215.             maxLoc.x = -1;  
  216.             maxLoc.y = -1;  
  217.   
  218.             //首先计算以点(x,y)位中心的maximumSize*maximumSize的窗口内部的局部极大值  
  219.             for(int winy=-halfWinSize;winy<=halfWinSize;winy++)  
  220.             {  
  221.                 for(int winx=-halfWinSize;winx<=halfWinSize;winx++)  
  222.                 {  
  223.                     float value ;  
  224.                     value = cvGetReal2D(cornerness,y+winy,x+winx);  
  225.                       
  226.                     //计算该窗口内 最大值 保存到max 并保存其坐标到maxLoc  
  227.                     if(value>maxValue)  
  228.                     {  
  229.                         maxValue = value;  
  230.                         maxLoc.x = x+winx;  
  231.                         maxLoc.y = y+winy;  
  232.                         flag = 1;  
  233.                     }  
  234.                 }  
  235.             }  
  236.   
  237.               
  238.             //如果找到局部极大值 并且该值大于预先设定的阈值 则认为是角点  
  239.             if(flag==1 && maxValue>params->threshold)  
  240.             {  
  241.                 cvSeqPush(corners,&maxLoc);  
  242.               
  243.             }  
  244.                       
  245.             x = x+params->maximumSize;  
  246.   
  247.         }  
  248.           
  249.         y = y + params->maximumSize;  
  250.   
  251.     }  
  252.       
  253.     delete []gaussWindow;  
  254.     cvReleaseImage(&Ix);  
  255.     cvReleaseImage(&Iy);  
  256.     cvReleaseImage(&IxIx);  
  257.     cvReleaseImage(&IyIy);  
  258.     cvReleaseImage(&IxIy);  
  259.     cvReleaseImage(&A);  
  260.     cvReleaseImage(&B);  
  261.     cvReleaseImage(&C);  
  262.     cvReleaseImage(&cornerness);  
  263.     cvReleaseImage(&srcFloat);  
  264. }  
  265. /******************************* 
  266. *对源图像进行卷积运算 
  267. *输入项 
  268. *srcFloat    源图像 
  269. *Ix          卷积的结果 
  270. *dxTemplate  卷积模板 
  271. *widthTemplate 模板的宽度 
  272. *heightTemplate 模板的高度 
  273. ********************************/  
  274. void convolution(IplImage* srcFloat,IplImage* Ix,double* dxTemplate , int widthTemplate,int heightTemplate)  
  275. {  
  276.     int x,y,beginY,endY,beginX,endX;  
  277.       
  278.     beginY = heightTemplate/2;  
  279.     endY = srcFloat->height - heightTemplate/2;  
  280.       
  281.     beginX = widthTemplate/2;  
  282.     endX = srcFloat->width - widthTemplate/2;  
  283.       
  284.     for(y=beginY;y<endY;y++)  
  285.     {  
  286.         for(x=beginX;x<endX;x++)  
  287.         {  
  288.       
  289.             int i,j;  
  290.             double curDx=0;  
  291.               
  292.   
  293.             for(i=0;i<heightTemplate;i++)  
  294.             {  
  295.                 for(j=0;j<widthTemplate;j++)  
  296.                 {  
  297.                     curDx += cvGetReal2D(srcFloat,y+i-heightTemplate/2,x+j-widthTemplate/2)**(dxTemplate+i*widthTemplate+j);  
  298.                 }  
  299.             }         
  300.             cvSetReal2D(Ix,y,x,curDx);  
  301.           
  302.         }  
  303.           
  304.     }  
  305. }  
http://blog.csdn.net/lu597203933/article/details/15088485

作者:小村长  出处:http://blog.csdn.net/lu597203933 欢迎转载或分享,但请务必声明文章出处。 (新浪微博:小村长zack, 欢迎交流!)
0 0
原创粉丝点击