影象處理(七)——Canny邊緣檢測
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; }