邊緣檢測是 圖像處理和計算機視覺中的基本問題, 邊緣檢測的目的是標識 數字圖像中 亮度變化明顯的點。圖像屬性中的顯著變化一般反映了屬性的重要事件和變化。這些包括(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; }