Moravec角點檢測

#include <opencv2\opencv.hpp>
#include "cv.h"
#include "cxcore.h"
#include "highgui.h"

/**********************************************************************************
*函數 int getMoravec(IplImage* src,CvSeq* corners)
*輸入:
*src : 單通道圖像
*corners : 用來保存提取到的角點
*threshold : 角點量的閾值 (具體函數 請看視頻)
*輸出
*corners : 用來保存提取到的角點
*返回值
*角點的個數
***************************************************************************************/
int getMoravec(IplImage* src,CvSeq* corners , float threshold)
{
	//窗口大小
	const int winSize=5; 
	int x,y,halfWinSize=winSize/2;

	//保存最小的變化量
	IplImage* diffDst = cvCreateImage(cvGetSize(src),32,1);
	cvZero(diffDst);

	//保存角點個數
	int cornersCount=0;

	//1.計算圖像上每一個點上的 在4個方向上的變化量 並計算出最小值 保存在矩陣diffDst中
	for(y=halfWinSize;y<src->height-halfWinSize;y++)
	{
		for(x=halfWinSize;x<src->width-halfWinSize;x++)
		{
			//compute the reaction in the four directions(0,45,90,135)
			int winx;

			//數組reaction[4] 用於保持 在四個方向上的灰度值變化量 
			//minValue用於保存4個變化量中的最小值
			float reaction[4],minValue;
			reaction[0]=0;
			reaction[1]=0;
			reaction[2]=0;
			reaction[3]=0;

			//提示  下面的4個循環 可以綜合成一個循環

			//0 度方向的變化量保存在reaction[0]中
			for( winx=-halfWinSize;winx<halfWinSize;winx++)
			{
				reaction[0] = reaction[0] + pow( cvGetReal2D(src,y,x+winx)-cvGetReal2D(src,y,x+winx+1), 2 );
			}

			//45 度方向的變化量保存在reaction[1]中
			for( winx=-halfWinSize;winx<halfWinSize;winx++)
			{
				reaction[1] = reaction[1]+pow(cvGetReal2D(src,y+winx,x+winx)-cvGetReal2D(src,y+winx+1,x+winx+1),2);
			}

			//90 度方向的變化量保存在reaction[2]中
			for( winx=-halfWinSize;winx<halfWinSize;winx++)
			{
				reaction[2] = reaction[2]+pow(cvGetReal2D(src,y+winx,x)-cvGetReal2D(src,y+winx+1,x),2);
			}

			//135 度方向的變化量保存在reaction[3]中
			for( winx=-halfWinSize;winx<halfWinSize;winx++)
			{
				reaction[3] = reaction[3]+pow(cvGetReal2D(src,y+winx,x-winx)-cvGetReal2D(src,y+winx+1,x-winx-1),2);
			}

			//計算4個量中最小值  保存到minValue
			minValue = reaction[0];
			minValue = minValue > reaction[1] ? reaction[1] : minValue;
			minValue = minValue > reaction[2] ? reaction[2] : minValue;
			minValue = minValue > reaction[3] ? reaction[3] : minValue;

			//將最小的變化量保存到矩陣
			cvSetReal2D(diffDst,y,x,minValue);
		}
	}

	//2.獲取角點座標
	for(y=halfWinSize;y<src->height-halfWinSize;)
	{
		for(x=halfWinSize;x<src->width-halfWinSize;)
		{
			float max=0;
			int flag = 0 ;
			CvPoint maxLoc;
			maxLoc.x = -1;
			maxLoc.y = -1;

			//首先計算以點(x,y)位中心的winSize*winSize的窗口內部的局部極大值
			for(int winy=-halfWinSize;winy<=halfWinSize;winy++)
			{
				for(int winx=-halfWinSize;winx<=halfWinSize;winx++)
				{
					float value ;
					value = cvGetReal2D(diffDst,y+winy,x+winx);

					//計算該窗口內 最大值 保存到max 並保存其座標到maxLoc
					if(value>max)
					{
						max = value;
						maxLoc.x = x+winx;
						maxLoc.y = y+winy;
						flag = 1;
					}
				}
			}

			//如果找到局部極大值 並且該值大於預先設定的閾值 則認爲是角點
			if(flag==1 && max>threshold)
			{
				cvSeqPush(corners,&maxLoc);
				cornersCount++;	
			}

			//下一個窗口
			x=x+halfWinSize;

		}

		//下一行的第一個窗口
		y=y+halfWinSize;
	}

	cvReleaseImage(&diffDst);

	return cornersCount;
}


int main(int argc, char* argv[])
{
	IplImage* src;
	//加載源圖像
	src = cvLoadImage("3.jpg",CV_LOAD_IMAGE_GRAYSCALE);
	if(!src)
	{
		printf("圖像加載失敗");
	}

	//用於保存最終角點的空間
	CvMemStorage* mem = cvCreateMemStorage(0);

	//角點將會保存在一個CvSeq中
	CvSeq* corners;
	corners = cvCreateSeq(0,sizeof(CvSeq),sizeof(CvPoint),mem);

	//角點的個數
	int cornersCount;

	//調用函數getMoravec計算角點
	cornersCount = getMoravec(src,corners,25000);

	//圖像show用於顯示角的提取結果
	IplImage* show= cvCreateImage(cvGetSize(src),8,3);
	cvCvtColor(src,show,CV_GRAY2BGR);

	//獲取每一個角點的座標
	for(int x=0;x<cornersCount;x++)
	{
		CvPoint* pt = (CvPoint*)cvGetSeqElem(corners,x);

		//以角點座標爲中心  繪製一個半徑爲5的圓
		cvCircle(show,*pt,10,cvScalar(255,0,0,0));
	}

	//顯示結果
	cvNamedWindow("dst");
	cvShowImage("dst",show);
	cvWaitKey(0);

	cvReleaseImage(&src);
	cvReleaseImage(&show);
	cvReleaseMemStorage(&mem);

	return 0;
}


運算結果:



角點的數量取決於所設定的閾值的大小。

閾值越小,角點數量越多,精度越低~

【1】moravec角點檢測步驟:
(1)對於每一個像素點,計算在E(u,v),在我們的算法中,(u,v)的取值是((1,0), (1,1), (0,1), (-1, 1).當然,你自己可以改成(1,0),(1,1),(0,1),(-1,1),(-1,0),(-1,-1),(0,-1),(1,-1) 8種情況
(2)計算最小值對每個位置minValue = min{E(u,v)},其中(u,v) = (1,0), (1,1), (0,1), (-1, 1).

(計算每個像素點的興趣值, 即以該像素點爲中心, 取一個w*w(如:5x5)的方形窗口, 計算0度、45度、90度、135度四個方向灰度差的平方和, 取其中的最小值作爲該像素點的興趣值。)
(3)對每個位置minValue 進行判斷,是不是大於設定閾值,如果是大於設定閾值,接着判斷是不是局部極大值


【2】Moravec角點檢測算法原理
Moravec角點檢測算法是最早的角點檢測算法之一。該算法將角點定義爲具有低“自相關性”的點。算法會檢測圖像的每一個像素,將像素周邊的一個鄰域作爲一個patch,並檢測這個patch和周圍其他patch的相關性。這種相關性通過兩個patch間的平方差之和(SSD)來衡量,SSD值越小則相似性越高。
如果像素位於平滑圖像區域內,周圍的patch都會非常相似。如果像素在邊緣上,則周圍的patch在與邊緣正交的方向上會有很大差異,在與邊緣平行的方向上則較爲相似。而如果像素是各個方向上都有變化的特徵點,則周圍所有的patch都不會很相似。
Moravec會計算每個像素patch和周圍patch的SSD最小值作爲強度值,取局部強度最大的點作爲特徵點。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章