Canny边缘检测算子是John F. Canny于 1986 年开发出来的一个多级边缘检测算法。更为重要的是 Canny 创立了边缘检测计算理论(Computational theory of edge detection)解释这项技术如何工作。
通常情况下边缘检测的目的是在保留原有图像属性的情况下,显著减少图像的数据规模。目前有多种算法可以进行边缘检测,虽然Canny算法年代久远,但可以说它是边缘检测的一种标准算法,而且仍在研究中广泛使用。
Canny算法是实现可以分为六步:
-
灰度化图像
较为简单,不多说 -
高斯滤波
高斯滤波是为了平滑图像,消除噪声。高斯滤波是实现之前的实验已经做过。 -
计算梯度之和方向
图像灰度值的梯度一般使用一阶有限差分来进行近似,这样就可以得图像在x和y方向上偏导数的两个矩阵。
其中f为图像灰度值,P代表X方向梯度幅值,Q代表Y方向 梯度幅值,M是该点幅值,Θ是梯度方向,也就是角度。 -
非极大值抑制
非极大值抑制是进行边缘检测的一个重要步骤,简单来说就是指寻找像素点局部最大值。
通过插值来计算dTemp1和dTemp2的像素值(亚像素 )。 -
双阈值的选取
双阈值的选取是按照直方图来选择的,至于选取多少就要自己定义了,这里我测试了几种不同的取值,结果分别如下:
(50,150)
(100,200)
(20,100)
如果边缘像素的梯度值高于高阈值,则将其标记为强边缘像素;如果边缘像素的梯度值小于高阈值并且大于低阈值,则将其标记为弱边缘像素;如果边缘像素的梯度值小于低阈值,则会被抑制。 -
边缘检测
首先判断该点是否超过高阈值,然后判断该点的8邻域点中寻找满足超过低阈值的点,再根据此点收集新的边缘,直到整个图像边缘闭合。整个图像找完后,将非边缘点剔除,即灰度值置0.
完成了以上六步,Canny边缘检测算法就完成了,实测效果也挺不错的。
代码自取
// CVE7(2).cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "StdAfx.h"
#include "cv.h"
#include "cxcore.h"
#include "highgui.h"
int main(int argc, char** argv)
{
//声明IplImage指针
IplImage* img = NULL;
IplImage* cannyImg = NULL;
//char *filename;
//filename = "图片1.png";
img = cvLoadImage("E:/C++/CVE7(2)/图片1.png", 1);
//载入图像,强制转化为Gray
if ((img = cvLoadImage("E:/C++/CVE7(2)/图片2.jpg", 0)) != 0)
{
//为canny边缘图像申请空间
cannyImg = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
//canny边缘检测
cvCanny(img, cannyImg, 20, 100, 3);
//创建窗口
cvNamedWindow("src", 1);
cvNamedWindow("canny", 1);
//显示图像
cvShowImage("src", img);
cvShowImage("canny", cannyImg);
cvWaitKey(0); //等待按键
//销毁窗口
cvDestroyWindow("src");
cvDestroyWindow("canny");
//释放图像
cvReleaseImage(&img);
cvReleaseImage(&cannyImg);
return 0;
}
return -1;
}