(1)首先我们来看三幅图片理解什么是角点:
我们在图片以某像素点为中心,取一窗口,当窗口向各个方向移动时,其内部灰度值变化不是很明显,则该点即处在平坦区域(如左边图);当其内部灰度值只在几个固定的方向上变化较为明显,那么该点则处在边缘区域(如图中间部分);当向各个方向移动,其变化都是很明显,则该点为角点(如图右)。
当然,上面所说的变化明显与否,是与我们事先设定的阀值进行对比的。
(2)moravec算法对角点定义:
窗口在各个方向上移动,窗口内的灰度值都会产生较大的变化。但实际程序中,这里的各个方向实际只有8个方向。即米形0°,45°,90°,135°,180°,225°,270°,315°。
例如:
这里我们为了简单起见,我们只取了四个方向(0°,45°,90°,135°),取一个w*w(如:5x5)的方形窗口, 计算0度、45度、90度、135度四个方向灰度差的平方和, 取其中的最小值作为该像素点的兴趣值(如下图)。
公式:
(3)moravec角点检测实现:
步骤:
<1>对于每一个像素点,计算在E(u,v),在我们的算法中,(u,v)的取值是((1,0), (1,1), (0,1), (-1, 1),这里只取了四个方向
<2>计算最小值对应的每个位置minValue = min{E(u,v)}
<3>对每个位置minValue进行判定,是不是大于设定的阀值,其中还有个过程是判断其是否为局部最大值以防止产生重复的角点
代码:
- #include <iostream>
- #include "cv.h"
- #include "highgui.h"
- #include "cxcore.h"
-
- using namespace std;
-
- int getMoravec(IplImage *src, CvSeq *corners, float threshold)
- {
- int winSize = 5;
- int y, x;
- int halfwin = winSize/2;
- int win;
- IplImage *diffDst = cvCreateImage(cvGetSize(src), 32, 1);
- int cornersCount = 0;
- for(y = halfwin; y < src->height - halfwin; y++)
- {
- for(x = halfwin; x < src->width - halfwin; x++)
- {
- float cornersResult[4];
- cornersResult[0] = 0;
- cornersResult[1] = 0;
- cornersResult[2] = 0;
- cornersResult[3] = 0;
- float minValue;
- for(win = -halfwin; win < halfwin; win++)
- {
- cornersResult[0] += pow(cvGetReal2D(src, y, x+win) - cvGetReal2D(src, y, x+win+1), 2);
- cornersResult[1] += pow(cvGetReal2D(src, y+win, x+win) - cvGetReal2D(src, y+win+1, x+win+1), 2);
- cornersResult[2] += pow(cvGetReal2D(src, y+win, x) - cvGetReal2D(src, y+win+1, x), 2);
- cornersResult[3] += pow(cvGetReal2D(src, y+win, x-win) - cvGetReal2D(src, y+win+1, x-win-1),2);
- }
- minValue = cornersResult[0];
- minValue = minValue < cornersResult[1] ? minValue : cornersResult[1];
- minValue = minValue < cornersResult[2] ? minValue : cornersResult[2];
- minValue = minValue < cornersResult[3] ? minValue : cornersResult[3];
- cvSetReal2D(diffDst, y, x, minValue);
- }
- }
- int yywin, xxwin, maxValue;
- CvPoint resultLoc;
- for(y = halfwin; y < src->height - halfwin; )
- {
- for(x = halfwin; x < src->width - halfwin;)
- {
- resultLoc.x = -1;
- resultLoc.y = -1;
- maxValue = 0;
- for(yywin = -halfwin; yywin <= halfwin; yywin++)
- {
- for(xxwin = -halfwin; xxwin < halfwin; xxwin++)
- {
- if(cvGetReal2D(diffDst, y+yywin, x+xxwin) > maxValue)
- {
- maxValue = cvGetReal2D(diffDst, y+yywin, x+xxwin);
- resultLoc.y = y+yywin;
- resultLoc.x = x+xxwin;
- }
- }
- }
- if(maxValue > threshold)
- {
- cvSeqPush(corners, &resultLoc);
- cornersCount ++;
- }
- x += winSize;
- }
- y += winSize;
-
- }
- cvReleaseImage(&diffDst);
- return cornersCount;
- }
- int main()
- {
- IplImage *src = cvLoadImage("E:\\study_opencv_video\\lesson17_1\\1.bmp", 0);
- if(!src)
- {
- cout << "No Image loading..." << endl;
- return 0;
- }
- CvSeq *corners;
- CvMemStorage *mem = cvCreateMemStorage(0);
- corners = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvPoint), mem);
- float threshold =30000;
-
- int cornersCount = getMoravec(src, corners, threshold);
-
-
- IplImage* show= cvCreateImage(cvGetSize(src),8,3);
- cvCvtColor(src,show,CV_GRAY2BGR);
-
-
-
- for(int i = 0; i < cornersCount; i++)
- {
-
- CvPoint *pt = (CvPoint *)cvGetSeqElem(corners, i);
- cvCircle(show, *pt, 5, cvScalar(0,0,255));
- }
- cvNamedWindow("show");
- cvShowImage("show", show);
- cvWaitKey(0);
- cvReleaseImage(&src);
- cvReleaseImage(&show);
- cvReleaseMemStorage(&mem);
- cvDestroyWindow("show");
- return 0;
-
-
-
- }
效果:
附加:简单解释下代码中的cvSeq和cvMemStorage,我用的不是太熟,当做笔记了哈哈~~:
- CvMemStorage *mem = cvCreateMemStorage(0);
- CvSeq*corners = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvPoint), mem);
- cvSeqPush(corners, &resultLoc);
- CvPoint *pt = (CvPoint *)cvGetSeqElem(corners, i);
- cvReleaseMemStorage(&mem);
- cvSeqSort(corners,cmpFunc,0);
-
- static int cmpFunc(const void* _cur , const void* _next , void* userdata)
- {
- PHARRISPOINT cur = (PHARRISPOINT)_cur;
- PHARRISPOINT next = (PHARRISPOINT)_next;
-
- return cur->cornerness < next->cornerness ? 1 : -1;
- }
(4)moravec角点检测的缺点
moravec角点检测主要有两个缺点:
一:不具有旋转不变性
二:对边缘点的反应比较强烈
转自:
http://blog.csdn.net/lu597203933