首先我们再重新回顾一下Canny算子中出现的一些概念:
滞后阈值处理:
非极大值抑制:符合Canny边缘检测算子的标准的算子的基,它相当于返回峰值(也相当于边缘垂直方向上的微分),因而可以细化边缘检测算子的响应,给出正确的边缘点,而没有多重响应,而且对噪声的响应最小。
我们可以利用非极大值抑制来去除HARRIS算子中一些黏在一起的角点。
非极大值抑制原理是,在一个窗口内,如果有多个角点则用值最大的那个角点,其他的角点都删除,窗口大小这里我们用3*3,程序中通过图像的膨胀运算来达到检测极大值的目的,因为默认参数的膨胀运算就是用窗口内的最大值替代当前的灰度值。程序的最后使用了一个画角点的函数将角点显示在图像中。
下面是opencv代码实现:
#include"cv.h"
#include"highgui.h"
#include"opencv2/opencv.hpp"
using namespace cv;
void drawCornerOnImage(Mat& image,const Mat&binary)
{
Mat_<uchar>::const_iterator it=binary.begin<uchar>();
Mat_<uchar>::const_iterator itd=binary.end<uchar>();
for(int i=0;it!=itd;it++,i++)
{
if(*it)
circle(image,Point(i%image.cols,i/image.cols),3,Scalar(0,255,0),1);
}
}
int main()
{
Mat image=imread("img2.jpg");
Mat gray;
cvtColor(image,gray,CV_BGR2GRAY);
Mat cornerStrength;
cornerHarris(gray,cornerStrength,3,3,0.01);
double maxStrength;
double minStrength;
// 找到图像中的最大、最小值
minMaxLoc(cornerStrength,&minStrength,&maxStrength);
Mat dilated;
Mat locaMax;
// 膨胀图像,最找出图像中全部的局部最大值点
dilate(cornerStrength,dilated,Mat());
// compare是一个逻辑比较函数,返回两幅图像中对应点相同的二值图像
compare(cornerStrength,dilated,locaMax,CMP_EQ);
Mat cornerMap;
double qualityLevel=0.01;
double th=qualityLevel*maxStrength; // 阈值计算
threshold(cornerStrength,cornerMap,th,255,THRESH_BINARY);
cornerMap.convertTo(cornerMap,CV_8U);
// 逐点的位运算
bitwise_and(cornerMap,locaMax,cornerMap);
drawCornerOnImage(image,cornerMap);
namedWindow("result");
imshow("result",image);
waitKey();
return 0;
}
两组运行结果是:
可以把这个与我上篇文章点击打开链接中试验进行对比。发现检测更加精确,增加了许多检测出的角点。其实这种还可以通过GoodFeaturesToTrack()这个函数实现,不深究。