1、moravec角点
2、
3、
基本原理:
我们在图片以某像素点为中心,取一邻域(比如3*3),当窗口向各个方向移动时,其内部灰度值变化不是很明显,则该点即处在平坦区域(如左边图);当其内部灰度值只在几个固定的方向上变化较为明显,那么该点则处在边缘区域(如图中间部分);当向各个方向移动,其变化都是很明显,则该点为角点(如图右)。
基本步骤:
(1) 在当前像素点取一窗口,如3*3,当前像素为中心点
(2)计算当前窗口的兴趣值:
选定方向下的兴趣值:即为窗口内,按某方向的相邻像素灰度值之差的平方再取和。
如下图选定窗口为3*3红色框,黄色像素点为中心像素,那么
水平方向的兴趣值:为左下图蓝色框内相邻像素灰度值之差的平方再取和
垂直方向的兴趣值:为右下图蓝色框内相邻像素灰度值之差的平方再取和
计算公式:
由于窗口有多个方向可移动,因此u,v有(0,1),(1,0),(1,1),(-1,0)……等
最终的兴趣值取各个方向下计算出来的最小值。
(3)将计算出来的兴趣值与设定阈值比较,大于阈值则为角点
实现代码:
#include
#include
#include
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(i, j + k) -
srcImage.at(i, j + k + 1))*
(srcImage.at(i, j + k) -
srcImage.at(i, j + k + 1));
}
//计算垂直方向窗口内的兴趣值
for (int k = -r; k < r; k++){
wV2 += (srcImage.at(i+k, j) -
srcImage.at(i+k+1, j))*
(srcImage.at(i+k, j) -
srcImage.at(i+k+1, j));
}
//计算45度方向窗口的兴趣值
for (int k = -r; k < r; k++){
wV3 += (srcImage.at(i + k, j+k) -
srcImage.at(i + k + 1, j+k+1))*
(srcImage.at(i + k, j+k) -
srcImage.at(i + k + 1, j+k+1));
}
//计算135度方向窗口的兴趣值
for (int k = -r; k < r; k++){
wV4 += (srcImage.at(i + k, j - k) -
srcImage.at(i + k + 1, j - k - 1))*
(srcImage.at(i + k, j + k) -
srcImage.at(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这个算法的缺点之一;对于斜边缘的响应较强烈。
虽然该算法效果一般,但是是接下来两个算法的基础。个人认为,需理解这个算法。