(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); // 将角点加入到corners中 这个函数需要记住*******
cornersCount ++;
}
x += winSize; // ++ 可能会出现多个corners
}
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); // corners指向该内存序列 角点将会保存在一个CvSeq中
float threshold =30000;
// 调用函数计算角点
int cornersCount = getMoravec(src, corners, threshold);
//图像show用于显示角的提取结果
IplImage* show= cvCreateImage(cvGetSize(src),8,3);
cvCvtColor(src,show,CV_GRAY2BGR);
// 获取每一个角点的坐标
for(int i = 0; i < cornersCount; i++)
{
// 以角点坐标为中心, 绘制一个半斤为5的圆
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); // corners指向内存序列
cvSeqPush(corners, &resultLoc); // 将点加入到内存序列中
CvPoint *pt = (CvPoint *)cvGetSeqElem(corners, i); // 获得seq中第i个元素
cvReleaseMemStorage(&mem); //释放内存序列空间
cvSeqRemove(corners,i); // 移除第i个点
cvSeqSort(corners,cmpFunc,0);// 对内存序列中的点进行排序
//对seq排序时的比较函数
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 欢迎转载或分享,但请务必声明文章出处。 (新浪微博:小村长zack, 欢迎交流!)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)