1、Moravec角点检测算法

一、相关原理

Moravec是最早的角点检测算法之一,它将角点定义为具有低“自相关性”的点。针对图像的每个像素,算法将像素周边的一个邻域作为一个patch,并检测这个patch和周围其他patch的相关性。这种相关性通过两个patch间的SSD(平方差之和)来衡量,SSD值越小则相似性越高。

一幅图像可分为区域、边缘和角点三个部分。如图1所示,如果像素位于平滑图像区域内,周围的patch都会非常相似。如果像素在边缘上,则周围的patch在与边缘正交的方向上会有很大差异,在与边缘平行的方向上则较为相似。而如果像素是各个方向上都有变化的特征点,则周围所有的patch都不会很相似。Moravec计算每个像素patch和周围patch的SSD最小值作为强度值,取局部强度最大的点作为角点。

                                                                                             图1

首先,计算每个像素点的兴趣值,即以该像素点为中心,取一个w*w(如:5x5)的方形窗口,计算0度、45度、90度、135度四个方向灰度差的平方和,取其中的最小值作为该像素点的兴趣值。

E(u,v)=\sum_{x,y} \omega (x,y)\left [ I(x+u,y+v)-I(x,y) \right ]^2      (1.1)

如图2所示,以3x3窗口为例,黑色窗口为I(x,y),红色窗口为I(x+u,y+v),其中四种移位(u,v)= (1,0), (1,1), (0,1), (-1, 1)。w(x,y)为方形二值窗口,若像素点在窗口内,则取值为1,否则为0。

                                                                                               图2

然后,使用非极大值抑制找到局部最大值(此时局部窗口大小可另行设定),将局部最大值与设定的阈值比较,最终确定角点。

此外,度量图像块A与图像块B之间的差异性(或相似性)有以下几种方法:

1)SAD(Sum of Absolute Difference),即两个小块的差的绝对值之和:

S(A,B)_{SAD}=\sum_{i,j}\left | A(i,j) -B(i,j)\right |        (1.2)

2)SSD(Sum of Squared Distance),即两个小块之间差的平方和:

S(A,B)_{SSD}=\sum_{i,j}(A(i,j)-B(i,j))^2       (1.3)

3)NCC(Normalized Cross Correlation,归一化互相关),这种方式比前两种方法要复杂,它计算两个小块的相关性,所以相关性接近0表示不相似,而接近1表示相似。前两种距离形式恰好相反,距离越小越相似。

S(A,B)_{NCC}=\frac{\sum_{i,j}A(i,j)B(i,j)}{\sqrt{\sum_{i,j}A(i,j)^2\sum_{i,j}B(i,j)^2}}        (1.4)

二、基本步骤

输入:源单通道图像、窗口大小、阈值

输出:角点

算法具体步骤:

1)对于每个像素点,计算E(u,v)的值。如果是3*3,(u,v)的值为4种情况,(1,0),(1,1),(0,1),(-1,1);如果是5*5的窗口,(u,v)的取值为8种情况,(1,0),(1,1),(0,1),(-1,1),(-1,0),(-1,-1),(0,-1),(1,-1)。

2)计算E(u,v)的最小值minValue;

3)对于每个位置minValue进行判断,是不是大于设定的阈值,如果大于设定的阈值,就进行非局部极大值抑制,判断是不是局部极大值。如果是局部极大值则为角点,否者不是角点。

算法结束。

                                                                                        图3 算法流程图

注:为什么要进行非局部极大值抑制?因为在一个窗口内,中心点附近的值也可能大于阈值,导致角点聚集现象。所以要在这个窗口内排除这些值,确定局部的最大值,而进行非局部极大值抑制。

三、缺点分析

1、对边缘点的反应比较强烈

强度值的计算并不是各向同性的(各向异性),只有离散的8个角度方向被考虑。moravec算法对角点的定义是:窗口在各个方向的移动,窗口内的灰度值都会产生较大的变化。而其实这里的“各个方向”,最多也就只有8个方向。所以,如果边缘的方向是这8个方向以外的方向,那么,就会被认为是角点。

                                                                                                 图4

2、不具备旋转不变性

因为moravec算法只计算最多八个方向的灰度值差的平方和,所以可能会出现原来的一条边缘在这8个方向之上而旋转之后却不在了,也有可能是相反的情况。这种旋转不变性进一步抑制了moravec算法的实用性。

3、窗口是方形且是二元的

在moravec中,使用的滑动窗口是正方形的、以及窗内的各个像素权重同质性(应该是中心像素权重大,距离中心越远,权重越小),并且窗口值是二元的,在窗口内,窗口值是1,在窗口外,窗口值是0。为了达到精确估计局部灰度值的变化程度,圆形的窗口才是理想的。圆形的窗口,使得中心点到窗口的每一个边缘点的欧式距离基本是相等的,以及赋予离中心更近的点更大的权重。

4、离散点(噪声点)与角点有相同的角点性(cornerness),因此Moravec算子对噪声敏感,但是通过增大滑动窗口的大小可以对噪声起到一定的抑制作用,同时增加了计算量。另一方面,通过设定一个阈值T来对cornerness map进行二值化,小于阈值T的cornerness map设置为0,从而对离散点的局部极大值进行抑制。

5、对于图像的一些边界区域像素,没有计算E(u,v)值。

四、代码分析

注意在实际使用时还要进行非局部极大值抑制,本代码未实现。

/**********************************************************************************
*函数 Mat MoravecCorners(cv::Mat SrcImage, int kSize, int threshold)
*输入:
     *SrcImage : 单通道图像
     *kSize : 窗口尺寸
     *threshold : 阈值 
*输出
     *MorImage : 提取到角点的图像
***************************************************************************************/
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;

Mat MoravecCorners(cv::Mat SrcImage, int kSize, int threshold)
{
	Mat MorImage = SrcImage.clone();
	// 获取初始化参数信息
	int r = kSize / 2;
	const int nRows = SrcImage.rows;
	const int nCols = SrcImage.cols;
	int nConut = 0;
	CvPoint *pPoint = new CvPoint[nRows*nCols];
	
	// 图像遍历
	for (int y = r; y < SrcImage.rows - r; y++)//行(y轴--v轴)
	{
		for (int x = r; x<SrcImage.cols - r; x++)//列(x轴--u轴)
		{
			int wV1, wV2, wV3, wV4;
			wV1 = wV2 = wV3 = wV4 = 0;
			// 计算水平(0度)方向窗内兴趣值
			for (int k = -r; k < r; k++)//k=-2,-1,0,1
				wV1 += (SrcImage.at<uchar>(y, x + k) - SrcImage.at<uchar>(y, x + k + 1))*
				(SrcImage.at<uchar>(y, x + k) - SrcImage.at<uchar>(y, x + k + 1));
			// 计算垂直(90度)方向窗内兴趣值
			for (int k = -r; k < r; k++)
				wV2 += (SrcImage.at<uchar>(y + k, x) - SrcImage.at<uchar>(y + k + 1, x))*
				(SrcImage.at<uchar>(y + k, x) - SrcImage.at<uchar>(y + k + 1, x));
			// 计算45度方向窗内兴趣值
			for (int k = -r; k < r; k++)
				wV3 += (SrcImage.at<uchar>(y + k, x + k) - SrcImage.at<uchar>(y + k + 1, x + k + 1))*
				(SrcImage.at<uchar>(y + k, x + k) - SrcImage.at<uchar>(y + k + 1, x + k + 1));
			// 计算135度方向窗内兴趣值
			for (int k = -r; k < r; k++)
				wV4 += (SrcImage.at<uchar>(y + k, x - k) - SrcImage.at<uchar>(y + k + 1, x - k - 1))*
				(SrcImage.at<uchar>(y + k, x - k) - SrcImage.at<uchar>(y + k + 1, x - k - 1));
			// 取其中的最小值作为该像素点的最终兴趣值
			int value = min(min(wV1, wV2), min(wV3, wV4));

			//若兴趣值大于阈值,则将点的坐标存入数组中
			if (value > threshold)
			{
				pPoint[nConut] = cvPoint(x, y);
				nConut++;
			}
		}
	}
	//绘制兴趣点
	cout << "kSize :5*5" << endl;
	cout << "threshold : 5000" << endl;
	cout << "corners :" << nConut << endl;
	for (int i = 0; i < nConut; i++)
		cv::circle(MorImage, pPoint[i], 3, cv::Scalar(255, 0, 0));
	return MorImage;
}

int main()
{
	cv::Mat SrcImage = imread("3.jpg");
	if (!SrcImage.data)
		return -1;
	cv::Mat srcImage;
	cvtColor(SrcImage, srcImage,CV_RGB2GRAY);
	//窗口设置为5*5,阈值设置为5000
	double time0 = static_cast<double>(getTickCount());
	cv::Mat MorImage = MoravecCorners(srcImage, 5, 5000);
	time0 = ((double)getTickCount() - time0) / getTickFrequency();
	cout <<"runtime :"<< time0 << "s" << endl;
	cv::imshow("MorMat", MorImage);
	cv::waitKey(0);
	return 0;
}

输入:lena.jpg,窗口大小5*5,阈值5000

输出:角点检测图(由于没有实现非局部极大值抑制,所以出现角点粘连现象)

                                                                                      图5 实验结果图

 

  • 6
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: Moravec角点检测是一种计算机视觉中用于检测图像中角点的算法。实现该算法的Python代码如下: ```python import cv2 import numpy as np def moravec_corner_detection(img, window_size=3, threshold=100): # 计算梯度 dx = cv2.Sobel(img, cv2.CV_32F, 1, 0) dy = cv2.Sobel(img, cv2.CV_32F, 0, 1) Ixx = dx ** 2 Ixy = dx * dy Iyy = dy ** 2 height, width = img.shape corner_map = np.zeros((height, width)) offset = window_size // 2 for y in range(offset, height - offset): for x in range(offset, width - offset): # 计算每个像素点的角点响应函数 M = np.array([[np.sum(Ixx[y-offset:y+offset+1, x-offset:x+offset+1]), np.sum(Ixy[y-offset:y+offset+1, x-offset:x+offset+1])], [np.sum(Ixy[y-offset:y+offset+1, x-offset:x+offset+1]), np.sum(Iyy[y-offset:y+offset+1, x-offset:x+offset+1])]]) det = np.linalg.det(M) trace = np.trace(M) corner_map[y, x] = det - 0.05 * trace ** 2 # 根据阈值筛选角点 corners = [] for y in range(offset, height - offset): for x in range(offset, width - offset): if corner_map[y, x] > threshold and \ corner_map[y, x] == np.max(corner_map[y-offset:y+offset+1, x-offset:x+offset+1]): corners.append((y, x)) return corners ``` 该函数接受一张灰度图像,以及窗口大小和阈值作为参数。它首先使用Sobel算子计算输入图像的水平和垂直梯度,然后计算每个像素点的角点响应函数。最后,它根据阈值和角点响应函数的最大值筛选角点,并返回一个角点列表。 ### 回答2: Moravec角点检测是一种在计算机视觉领域中广泛使用的角点检测算法。该算法通过检测图像中窗口内灰度变化最大的位置来确定角点的位置。 要实现Moravec角点检测算法的Python代码,我们可以按照以下步骤进行: 1. 首先,我们需要加载图像并将其转换为灰度图像。可以使用Python的图像处理库(如PIL或OpenCV)来实现这一步骤。 2. 接下来,我们需要定义一个窗口大小,该窗口将在图像上滑动。可以根据需求来选择窗口大小。 3. 在定义了窗口大小后,我们需要遍历图像的每个像素。对于每个像素,我们需要计算其在窗口内灰度变化的总和。 4. 然后,我们可以根据窗口内灰度变化的总和来计算一个角点响应函数。在Moravec角点检测中,常用的响应函数是灰度变化总和的平方。 5. 最后,我们可以根据阈值来筛选具有高角点响应的像素,并将它们标记为角点。 以上就是实现Moravec角点检测算法的基本步骤。当然,根据具体的需求,我们还可以添加一些额外的步骤,如非最大抑制等来优化角点检测的结果。 需要注意的是,Moravec角点检测算法是一种基于计算灰度变化的算法,对于噪声较大或亮度不均匀的图像可能效果不佳。因此,在实际应用中,我们可能需要结合其他的角点检测算法来获得更好的结果。 ### 回答3: Moravec角点检测是一种在计算机视觉中常用的角点检测算法。这个算法可以用Python来实现。 实现Moravec角点检测的方法如下: 1. 首先,将图像转换为灰度图像,这是因为角点检测算法对于灰度图像更为适用。 2. 然后,对于每个像素点,计算其在x和y方向上的梯度,可以使用Sobel算子等滤波器来计算梯度。 3. 接下来,对于每个像素点,计算其与其周围窗口中的像素点的差异度量。 - 可以使用简单平方差(Sum of Squared Differences, SSD)或小波变换等方法计算差异度量。 - 可以指定一个窗口大小,通常是3x3或5x5大小的窗口。 4. 根据差异度量,判断当前像素是否为角点。 - 如果差异度量高于一定的阈值,即认为当前像素为角点。 - 可以根据具体应用场景和对角点检测的要求来确定阈值的选择。 以下是一个简单的Python代码实现Moravec角点检测的示例: ```python import cv2 import numpy as np def moravec_corner_detection(image, window_size=3, threshold=100): gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) height, width = gray_image.shape corners = [] for y in range(window_size//2, height-window_size//2): for x in range(window_size//2, width-window_size//2): min_diff = np.inf for dy in [-1, 0, 1]: for dx in [-1, 0, 1]: if dy == 0 and dx == 0: continue diff = np.sum(np.square(gray_image[y:y+window_size, x:x+window_size] - gray_image[y+dy:y+dy+window_size, x+dx:x+dx+window_size])) min_diff = min(min_diff, diff) if min_diff > threshold: corners.append((x, y)) return corners # 读取图像 image = cv2.imread('image.jpg') # 调用角点检测函数 corners = moravec_corner_detection(image) # 在图像上绘制角点 for (x, y) in corners: cv2.circle(image, (x, y), 3, (0, 255, 0), -1) # 显示图像 cv2.imshow('Corners', image) cv2.waitKey(0) cv2.destroyAllWindows() ``` 以上代码中,`window_size`表示窗口大小,`threshold`表示角点的阈值。通过调整这两个参数的值,可以得到不同的角点检测效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值