(1)Moravec角点检测算法原理
Moravec角点检测算法是最早的角点检测算法之一。该算法将角点定义为具有低“自相关性”的点。算法会检测图像的每一个像素,将像素周边的一个邻域作为一个patch,并检测这个patch和周围其他patch的相关性。这种相关性通过两个patch间的平方差之和(SSD)来衡量,SSD值越小则相似性越高。
如果像素位于平滑图像区域内,周围的patch都会非常相似。如果像素在边缘上,则周围的patch在与边缘正交的方向上会有很大差异,在与边缘平行的方向上则较为相似。而如果像素是各个方向上都有变化的特征点,则周围所有的patch都不会很相似。
Moravec会计算每个像素patch和周围patch的SSD最小值作为强度值,取局部强度最大的点作为特征点。
(2)Moravec角点检测示意图:

(3)将moravec角点检测方法公式化:
Moravec 在1981年提出Moravec角点检测算子,并将它应用于立体匹配。
首先, 计算每个像素点的兴趣值, 即以该像素点为中心, 取一个w*w(如:5x5)的方形窗口, 计算0度、45度、90度、135度四个方向灰度差的平方和, 取其中的最小值作为该像素点的兴趣值。

如图以3x3为例 黑色窗口为I(x,y) 红色窗口为I(x+u,y+v)
其中四种移位 (u,v) = (1,0), (1,1), (0,1), (-1, 1). w(x,y)为方形二值窗口,若像素点在窗口内,则取值为1, 否则为0 。
(4)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).
Moravec角点检测算法是最早的角点检测算法之一。该算法将角点定义为具有低“自相关性”的点。算法会检测图像的每一个像素,将像素周边的一个邻域作为一个patch,并检测这个patch和周围其他patch的相关性。这种相关性通过两个patch间的平方差之和(SSD)来衡量,SSD值越小则相似性越高。
如果像素位于平滑图像区域内,周围的patch都会非常相似。如果像素在边缘上,则周围的patch在与边缘正交的方向上会有很大差异,在与边缘平行的方向上则较为相似。而如果像素是各个方向上都有变化的特征点,则周围所有的patch都不会很相似。
Moravec会计算每个像素patch和周围patch的SSD最小值作为强度值,取局部强度最大的点作为特征点。
(2)Moravec角点检测示意图:
(3)将moravec角点检测方法公式化:
Moravec 在1981年提出Moravec角点检测算子,并将它应用于立体匹配。
首先, 计算每个像素点的兴趣值, 即以该像素点为中心, 取一个w*w(如:5x5)的方形窗口, 计算0度、45度、90度、135度四个方向灰度差的平方和, 取其中的最小值作为该像素点的兴趣值。
如图以3x3为例 黑色窗口为I(x,y) 红色窗口为I(x+u,y+v)
其中四种移位 (u,v) = (1,0), (1,1), (0,1), (-1, 1). w(x,y)为方形二值窗口,若像素点在窗口内,则取值为1, 否则为0 。
(4)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).
(3)对每个位置minValue 进行判断,是不是大于设定阈值,如果是大于设定阈值,接着判断是不是局部极大值
下面放上源代码:
#include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> using namespace std; using namespace cv; //***********moravec角点检测函数******************* //第一个参数srcImage表示输入的图 //第二个参数表示核的边长 //第三个参数表示设定的阈值的大小 //************************************************* Mat MoravecCorners(Mat srcImage, int kSize, int threshold); int main() { Mat srcImage = imread("1.jpg"); if (!srcImage.data) { printf("could not load image...\n"); return -1; } Mat srcGray; cvtColor(srcImage, srcGray, CV_BGR2GRAY); Mat resMorMat = MoravecCorners(srcGray, 5, 10000); imshow("srcGray", srcGray); imshow("resMorMat", resMorMat); waitKey(0); return 0; } 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; //计算水平方向窗内的兴趣值 for (int k = -r; k <= r; k++) { for (int m = -r; m <= r; m++) { //判断移动的过程中是否越界,越界的话就跳过当前的循环,以免出错 int a = i + k ; int b = j + m + 1; if (b>=srcImage.cols) { continue; } wV1 += (srcImage.at<uchar>(i + k, j + m + 1) - srcImage.at<uchar>(i + k, j + m)) *(srcImage.at<uchar>(i + k, j + m + 1) - srcImage.at<uchar>(i + k, j + m)); } } //计算垂直方向窗内的兴趣值 for (int k = -r; k <= r; k++) { for (int m = -r; m <= r; m++) { int a = i + k + 1; int b = j + m ; if (a >=srcImage.rows) { continue; } wV2 += (srcImage.at<uchar>(i + k + 1, j + m) - srcImage.at<uchar>(i + k, j + m)) *(srcImage.at<uchar>(i + k + 1, j + m) - srcImage.at<uchar>(i + k, j + m)); } } //计算45°方向窗内的兴趣值 for (int k = -r; k <= r; k++) { for (int m = -r; m <= r; m++) { int a = i + k + 1; int b = j + m + 1; if (a >=srcImage.rows || b >=srcImage.cols) { continue; } wV3 += (srcImage.at<uchar>(i + k + 1, j + m + 1) - srcImage.at<uchar>(i + k, j + m)) *(srcImage.at<uchar>(i + k + 1, j + m + 1) - srcImage.at<uchar>(i + k, j + m)); } } //计算135°方向窗内的兴趣值 for (int k = -r; k <= r; k++) { for (int m = -r; m <= r; m++) { int a = i + k + 1; int b = j + m - 1; if (a >=srcImage.rows || b < 0) { continue; } wV4 += (srcImage.at<uchar>(a, b) - srcImage.at<uchar>(i + k, j + m)) *(srcImage.at<uchar>(a, b) - srcImage.at<uchar>(i + k, j + m)); } } int value = min(min(wV1, wV2), min(wV3, wV4)); //如果兴趣值大于阈值,那么将坐标存入数组中 if (value > threshold) { pPoint[nCount] = cvPoint(j, i); nCount++; } } } //绘制兴趣点 for (int i = 0; i < nCount; i++) { circle(resMorMat, pPoint[i], 5, Scalar(255, 0, 0)); } return resMorMat; }
原图的灰度图:
角点检测效果图:
这张图片因为没有经过极大值抑制,好多角点检测到的重复了。你们可以加上极大值抑制