Opencv2.4学习::角点检测(一)

角点检测(一)


1、moravec角点

2、

3、


基本原理:

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


基本步骤:

(1) 在当前像素点取一窗口,如3*3,当前像素为中心点

(2)计算当前窗口的兴趣值:

选定方向下的兴趣值:即为窗口内,按某方向的相邻像素灰度值之差的平方再取和。

如下图选定窗口为3*3红色黄色像素点为中心像素,那么

水平方向的兴趣值:为左下图蓝色框内相邻像素灰度值之差的平方再取和

垂直方向的兴趣值:为右下图蓝色框内相邻像素灰度值之差的平方再取和

计算公式:

由于窗口有多个方向可移动,因此u,v有(0,1),(1,0),(1,1),(-1,0)……等

最终的兴趣值取各个方向下计算出来的最小值。

(3)将计算出来的兴趣值与设定阈值比较,大于阈值则为角点


 实现代码:

#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
//MoravecCorners角点检测
Mat MoravecCorners(Mat srcImage, int kSize, int threshold)
{
	Mat resMorMat = srcImage.clone();
	//获取原图像信息
	int r = kSize / 2;//选定窗口的边界限定
	const int nRows = srcImage.rows;
	const int nCols = srcImage.cols;
	int nCount = 0;
	CvPoint *pPoint = new CvPoint[nRows*nCols];
	//图像遍历
	for (int i = r; i < srcImage.rows - r; i++){
		for (int j = r; j < srcImage.cols - r; j++){
			int wV1, wV2, wV3, wV4;
			wV1 = wV2 = wV3 = wV4 = 0;//4个方向的兴趣值初始化
			//计算水平方向窗口内的兴趣值
			for (int k = -r; k < r; k++){
				wV1 += (srcImage.at<uchar>(i, j + k) -
					srcImage.at<uchar>(i, j + k + 1))*
					(srcImage.at<uchar>(i, j + k) - 
					srcImage.at<uchar>(i, j + k + 1));
			}
			//计算垂直方向窗口内的兴趣值
			for (int k = -r; k < r; k++){
				wV2 += (srcImage.at<uchar>(i+k, j) -
					srcImage.at<uchar>(i+k+1, j))*
					(srcImage.at<uchar>(i+k, j) -
					srcImage.at<uchar>(i+k+1, j));
			}
			//计算45度方向窗口的兴趣值
			for (int k = -r; k < r; k++){
				wV3 += (srcImage.at<uchar>(i + k, j+k) -
					srcImage.at<uchar>(i + k + 1, j+k+1))*
					(srcImage.at<uchar>(i + k, j+k) -
					srcImage.at<uchar>(i + k + 1, j+k+1));
			}
			//计算135度方向窗口的兴趣值
			for (int k = -r; k < r; k++){
				wV4 += (srcImage.at<uchar>(i + k, j - k) -
					srcImage.at<uchar>(i + k + 1, j - k - 1))*
					(srcImage.at<uchar>(i + k, j + k) -
					srcImage.at<uchar>(i + k + 1, j - k - 1));
			}
			//取四个方向下的最小值作为最终兴趣值
			int value = min(min(wV1, wV2), min(wV3, wV4));
			//若兴趣值大于阈值,则将该点【窗口中心点】的坐标存入
			if (value > threshold){
				pPoint[nCount++] = cvPoint(j, i);
			}
		}
	}
	//绘制兴趣点
	for (int i = 0; i < nCount; i++){
		circle(resMorMat, pPoint[i], 5, Scalar(0, 0, 255));
	}
	return resMorMat;
}

void main()
{
	Mat srcImg = imread("F:\\opencv_re_learn\\flash.jpg");
	if (!srcImg.data){
		cout << "failed to read" << endl;
		system("pause");
		return;
	}
	Mat srcGray;
	cvtColor(srcImg, srcGray, CV_BGR2GRAY);
	Mat result = MoravecCorners(srcGray, 5, 1000);
	imshow("src", srcImg);
	imshow("result", result);
	waitKey(0);
}

实现效果:

可以看见,在某个方向检测到的角点偏多,这也是MOravec这个算法的缺点之一;对于斜边缘的响应较强烈。

虽然该算法效果一般,但是是接下来两个算法的基础。个人认为,需理解这个算法。

猜你喜欢

转载自blog.csdn.net/dieju8330/article/details/83586443
今日推荐