边缘检测是 图像处理和计算机视觉中的基本问题, 边缘检测的目的是标识 数字图像中 亮度变化明显的点。图像属性中的显著变化一般反映了属性的重要事件和变化。这些包括(i)深度上的不连续、(ii)表面方向不连续、(iii)物质属性变化和(iv)场景照明变化。 边缘检测是 图像处理和 计算机视觉中,尤为是 特征提取中的一个研究领域。
图像边缘检测大幅度地减小了数据量,而且剔除了能够认为不相关的信息,保留了图像重要的结构属性。有许多方法用于边缘检测,它们的绝大部分能够划分为两类:基于查找一类和基于零穿越的一类。基于查找的方法经过寻找图像一阶导数中的最大和最小值来检测边界,一般是将边界定位在梯度最大的方向。基于零穿越的方法经过寻找图像二阶导数零穿越来寻找边界,一般是Laplacian过零点或者非线性差分表示的过零点。php
Canny 边缘检测算子是John F. Canny于 1986 年开发出来的一个多级边缘检测算法。更为重要的是 Canny 创立了边缘检测计(Computational theory of edge detection)解释这项技术如何工做。
算法
Canny 的目标是找到一个最优的边缘检测算法,最优边缘检测的含义是:编程
为了知足这些要求 Canny 使用了变分法,这是一种寻找知足特定功能的函数的方法。最优检测使用四个指数函数项的和表示,可是它很是近似于高斯函数的一阶导数。函数
/***********************************************Canny算法实现过程*************************************************/ui
分为如下几个步骤:spa
一、图像灰度化:只有灰度图才能进行边缘检测code
二、去噪:噪声点将影响边缘检测的准确性事件
三、求解梯度幅度和方向:利用sobel算子求解图片
四、非极大值抑制:定位准确的边缘同时可缩小边缘线宽ip
五、双阀值算法检测及链接边缘
一、图像灰度化
Canny算法一般处理的图像为灰度图,所以若是摄像机获取的是彩色图像,那首先就得进行灰度化。对一幅彩色图进行灰度化,就是根据图像各个通道的采样值进行加权平均。以RGB格式的彩图为例,一般灰度化采用的方法主要有:
方法1:Gray=(R+G+B)/3;
方法2:Gray=0.299R+0.587G+0.114B;
注意1:至于其余格式的彩色图像,能够根据相应的转换关系转为RGB而后再进行灰度化;
注意2:在编程时要注意图像格式中RGB的顺序一般为BGR。
二、去噪
三、求解梯度幅度和方向
梯度的幅度及方向采用sobel算子求解,索贝尔算子(Sobel operator)是图像处理中的算子之一,主要用做边缘检测。在技术上,它是一离散性差分算子,用来运算图像亮度函数的梯度之近似值。在图像的任何一点使用此算子,将会产生对应的梯度矢量或是其法矢量。
该算子包含两组3x3的矩阵,分别为横向及纵向,将之与图像做平面卷积,便可分别得出横向及纵向的亮度差分近似值。若是以表明原始图像,
及
分别表明经横向及纵向边缘检测的图像,其公式以下:
图像的每个像素的横向及纵向梯度近似值可用如下的公式结合,来计算梯度的大小。
而后可用如下公式计算梯度方向。
在以上例子中,若是以上的角度等于零,即表明图像该处拥有纵向边缘,左方较右方暗。
四、非极大值抑制
在求出的幅值图像中,可能存在多个较大幅值临近的状况,但真正的边缘点只有一个,针对这样的状况咱们进行非极大值抑制,找出局部最大值,从而能够剔除大部分非边缘点
如上图所示,咱们对每一像素点作以下处理:
根据该像素点的梯度方向,肯定需进行比较的临近像素点位置,如上图所示(过像素点方向为梯度方向的直线与该像素点临近的八像素点所组成的矩形,相交于dTmp1和dTmp2,根据g1,g2a和g3,g4估算出交点像素,若是该像素点均大于两交点像素则为极大值边缘点,不然为非边缘点)
五、双阀值算法检测及链接边缘
滞后阈值: 最后一步,Canny 使用了滞后阈值,滞后阈值须要两个阈值(高阈值和低阈值):
Canny 推荐的 高:低 阈值比在 2:1 到3:1之间。
下面咱们将看到基于opencv中的canny边缘算法的具体实现(opencv中已经实现了canny算法咱们只需调用便可,具体实现可见源码):
/************************************************** * C++ Canny:Canny边缘检测 **************************************************/ #include "stdafx.h" #include "cv.h" #include "cxcore.h" #include "highgui.h" using namespace cv; using namespace std; int edgeThresh = 1; // 声明 原始图片,灰度图片,和 canny边缘图片 IplImage *image; IplImage *gray, *edge; void onTrackbar(int, void*) { // 高斯滤波 cvSmooth(gray, edge, CV_GAUSSIAN, 3, 3, 0 ); // Canny 边缘检测 cvCanny(gray,edge, edgeThresh, edgeThresh*3, 3); // 显示图片 cvShowImage("Edge map", edge); } int main() { // 载入图片 image = cvLoadImage("E:\\test\\lenna.bmp"); // 判断载入图片是否成功 if( image == NULL ) { printf("miss the image file\n"); return -1; } // 生成灰度图片,由于只有灰度图片才能生成边缘图片 gray = cvCreateImage( cvGetSize(image),IPL_DEPTH_8U ,1 ); edge = cvCreateImage( cvGetSize(image),IPL_DEPTH_8U ,1 ); cvCvtColor(image,gray, CV_BGR2GRAY); // 新建一个窗口 namedWindow("Edge map", 1); // 生成一个进度条来控制边缘检测 createTrackbar("Canny Threshold", "Edge map", &edgeThresh, 100, onTrackbar); // 初始化图像 onTrackbar(0,0); waitKey(0); cvReleaseImage( &image ); cvReleaseImage( &edge ); cvReleaseImage( &gray ); return 0; }