Canny算法 邊緣檢測


邊緣檢測是 
        圖像處理計算機視覺中的基本問題, 
        邊緣檢測的目的是標識 
        數字圖像亮度變化明顯的點。圖像屬性中的顯著變化通常反映了屬性的重要事件和變化。這些包括(i)深度上的不連續、(ii)表面方向不連續、(iii)物質屬性變化和(iv)場景照明變化。 邊緣檢測是 
        圖像處理計算機視覺中,尤其是 
        特征提取中的一個研究領域。 
        

圖像邊緣檢測大幅度地減少了數據量,並且剔除了可以認為不相關的信息,保留了圖像重要的結構屬性。有許多方法用於邊緣檢測,它們的絕大部分可以划分為兩類:基於查找一類和基於零穿越的一類。基於查找的方法通過尋找圖像一階導數中的最大和最小值來檢測邊界,通常是將邊界定位在梯度最大的方向。基於零穿越的方法通過尋找圖像二階導數零穿越來尋找邊界,通常是Laplacian過零點或者非線性差分表示的過零點。

Canny 邊緣檢測算子是John F. Canny於 1986 年開發出來的一個多級邊緣檢測算法。更為重要的是 Canny 創立了邊緣檢測計(Computational theory of edge detection)解釋這項技術如何工作。

Canny 的目標是找到一個最優的邊緣檢測算法,最優邊緣檢測的含義是:

  • 好的檢測 - 算法能夠盡可能多地標識出圖像中的實際邊緣。
  • 好的定位 - 標識出的邊緣要盡可能與實際圖像中的實際邊緣盡可能接近。
  • 最小響應 - 圖像中的邊緣只能標識一次,並且可能存在的圖像噪聲不應標識為邊緣。

為了滿足這些要求 Canny 使用了變分法,這是一種尋找滿足特定功能函數的方法。最優檢測使用四個指數函數項的和表示,但是它非常近似於高斯函數的一階導數

/***********************************************Canny算法實現過程*************************************************/

分為以下幾個步驟:

1、圖像灰度化:只有灰度圖才能進行邊緣檢測

2、去噪:噪聲點將影響邊緣檢測的准確性

3、求解梯度幅度和方向:利用sobel算子求解

4、非極大值抑制:定位准確的邊緣同時可縮小邊緣線寬

5、雙閥值算法檢測及連接邊緣


1、圖像灰度化

Canny算法通常處理的圖像為灰度圖,因此如果攝像機獲取的是彩色圖像,那首先就得進行灰度化。對一幅彩色圖進行灰度化,就是根據圖像各個通道的采樣值進行加權平均。以RGB格式的彩圖為例,通常灰度化采用的方法主要有:

        方法1:Gray=(R+G+B)/3;

        方法2:Gray=0.299R+0.587G+0.114B;

注意1:至於其他格式的彩色圖像,可以根據相應的轉換關系轉為RGB然后再進行灰度化;

注意2:在編程時要注意圖像格式中RGB的順序通常為BGR


2、去噪

噪聲的存在影響到邊緣的檢測,首先將圖片進行高斯去噪,高斯去噪其實就是一個低通濾波器,濾除高頻噪聲。

3、求解梯度幅度和方向

梯度的幅度及方向采用sobel算子求解,索貝爾算子(Sobel operator)是圖像處理中的算子之一,主要用作邊緣檢測。在技術上,它是一離散性差分算子,用來運算圖像亮度函數的梯度之近似值。在圖像的任何一點使用此算子,將會產生對應的梯度矢量或是其法矢量。

該算子包含兩組3x3的矩陣,分別為橫向及縱向,將之與圖像作平面卷積,即可分別得出橫向及縱向的亮度差分近似值。如果以\mathbf{A}代表原始圖像,\mathbf{G_x}\mathbf{G_y}分別代表經橫向及縱向邊緣檢測的圖像,其公式如下:


圖像的每一個像素的橫向及縱向梯度近似值可用以下的公式結合,來計算梯度的大小。


然后可用以下公式計算梯度方向。


在以上例子中,如果以上的角度\Theta等於零,即代表圖像該處擁有縱向邊緣,左方較右方暗。


4、非極大值抑制

在求出的幅值圖像中,可能存在多個較大幅值臨近的情況,但真正的邊緣點只有一個,針對這樣的情況我們進行非極大值抑制,找出局部最大值,從而可以剔除大部分非邊緣點


如上圖所示,我們對每一像素點做如下處理:

根據該像素點的梯度方向,確定需進行比較的臨近像素點位置,如上圖所示(過像素點方向為梯度方向的直線與該像素點臨近的八像素點所組成的矩形,相交於dTmp1和dTmp2,根據g1,g2a和g3,g4估算出交點像素,如果該像素點均大於兩交點像素則為極大值邊緣點,否則為非邊緣點


5、雙閥值算法檢測及連接邊緣

  1. 滯后閾值: 最后一步,Canny 使用了滯后閾值,滯后閾值需要兩個閾值(高閾值和低閾值):

    1. 如果某一像素位置的幅值超過 高 閾值, 該像素被保留為邊緣像素。
    2. 如果某一像素位置的幅值小於 低 閾值, 該像素被排除。
    3. 如果某一像素位置的幅值在兩個閾值之間,該像素僅僅在連接到一個高於 高 閾值的像素時被保留。

    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;
}



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM