opencv学习_11 (moravec角点检测及缺点)

(1)首先我们来看三幅图片理解什么是角点:

opencv学习_11 (moravec角点检测及缺点)_第1张图片


我们在图片以某像素点为中心,取一窗口,当窗口向各个方向移动时,其内部灰度值变化不是很明显,则该点即处在平坦区域(如左边图);当其内部灰度值只在几个固定的方向上变化较为明显,那么该点则处在边缘区域(如图中间部分);当向各个方向移动,其变化都是很明显,则该点为角点(如图右)。

当然,上面所说的变化明显与否,是与我们事先设定的阀值进行对比的。

(2)moravec算法对角点定义:

窗口在各个方向上移动,窗口内的灰度值都会产生较大的变化。但实际程序中,这里的各个方向实际只有8个方向。即米形0°,45°,90°,135°,180°,225°,270°,315°。

例如:

这里我们为了简单起见,我们只取了四个方向(0°,45°,90°,135°),取一个w*w(如:5x5)的方形窗口, 计算0度、45度、90度、135度四个方向灰度差的平方和, 取其中的最小值作为该像素点的兴趣值(如下图)。

公式:    

opencv学习_11 (moravec角点检测及缺点)_第2张图片



(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;



}
 效果:

opencv学习_11 (moravec角点检测及缺点)_第3张图片

附加:简单解释下代码中的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, 欢迎交流!)





你可能感兴趣的:(opencv,角点检测,Moravec)