導航:首頁 > 源碼編譯 > canny演算法是opencv

canny演算法是opencv

發布時間:2023-11-22 03:49:11

1. 圖片處理-opencv-10.圖像銳化與邊緣檢測

 

Roberts運算元又稱為交叉微分演算法,它是基於交叉差分的梯度演算法,通過局部差分計算檢測邊緣線條。常用來處理具有陡峭的低雜訊圖像,當圖像邊緣接近於正45度或負45度時,該演算法處理效果更理想。其缺點是對邊緣的定位不太准確,提取的邊緣線條較粗。

Prewitt是一種圖像邊緣檢測的微分運算元,其原理是利用特定區域內像素灰度值產生的差分實現邊緣檢測。由於Prewitt運算元採用3 3模板對區域內的像素值進行計算,而Robert運算元的模板為2 2,故Prewitt運算元的邊緣檢測結果在水平方向和垂直方向均比Robert運算元更加明顯。Prewitt運算元適合用來識別雜訊較多、灰度漸變的圖像。

dst = filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]])

RSobel運算元是一種用於邊緣檢測的離散微分運算元,它結合了高斯平滑和微分求導。該運算元用於計算圖像明暗程度近似值,根據圖像邊緣旁邊明暗程度把該區域內超過某個數的特定點記為邊緣。Sobel運算元在Prewitt運算元的基礎上增加了權重的概念,認為相鄰點的距離遠近對當前像素點的影響是不同的,距離越近的像素點對應當前像素的影響越大,從而實現圖像銳化並突出邊緣輪廓。Sobel運算元的邊緣定位更准確,常用於雜訊較多、灰度漸變的圖像。

Sobel運算元根據像素點上下、左右鄰點灰度加權差,在邊緣處達到極值這一現象檢測邊緣。對雜訊具有平滑作用,提供較為精確的邊緣方向信息。因為Sobel運算元結合了高斯平滑和微分求導(分化),因此結果會具有更多的抗噪性,當對精度要求不是很高時,Sobel運算元是一種較為常用的邊緣檢測方法。

dst = Sobel(src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]])

在進行Sobel運算元處理之後,還需要調用convertScaleAbs()函數計算絕對值,並將圖像轉換為8點陣圖進行顯示

dst = convertScaleAbs(src[, dst[, alpha[, beta]]])

拉普拉斯(Laplacian)運算元是n維歐幾里德空間中的一個二階微分運算元,常用於圖像增強領域和邊緣提取。它通過灰度差分計算鄰域內的像素,基本流程是:判斷圖像中心像素灰度值與它周圍其他像素的灰度值,如果中心像素的灰度更高,則提升中心像素的灰度;反之降低中心像素的灰度,從而實現圖像銳化操作。在演算法實現過程中,Laplacian運算元通過對鄰域中心像素的四方向或八方向求梯度,再將梯度相加起來判斷中心像素灰度與鄰域內其他像素灰度的關系,最後通過梯度運算的結果對像素灰度進行調整。

Laplacian運算元分為四鄰域和八鄰域,四鄰域是對鄰域中心像素的四方向求梯度,八鄰域是對八方向求梯度。當鄰域內像素灰度相同時,模板的卷積運算結果為0;當中心像素灰度高於鄰域內其他像素的平均灰度時,模板的卷積運算結果為正數;當中心像素的灰度低於鄰域內其他像素的平均灰度時,模板的卷積為負數。對卷積運算的結果用適當的衰弱因子處理並加在原中心像素上,就可以實現圖像的銳化處理。

dst = Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]])

由於Sobel運算元在計算相對較小的核的時候,其近似計算導數的精度比較低,比如一個33的Sobel運算元,當梯度角度接近水平或垂直方向時,其不精確性就越發明顯。Scharr運算元同Sobel運算元的速度一樣快,但是准確率更高,尤其是計算較小核的情景,所以利用3*3濾波器實現圖像邊緣提取更推薦使用Scharr運算元

Scharr運算元又稱為Scharr濾波器,也是計算x或y方向上的圖像差分,在OpenCV中主要是配合Sobel運算元的運算而存在的。Scharr運算元的函數原型如下所示,和Sobel運算元幾乎一致,只是沒有ksize參數.

dst = Scharr(src, ddepth, dx, dy[, dst[, scale[, delta[, borderType]]]]])

Canny邊緣檢測運算元(多級邊緣檢測演算法)是一種被廣泛應用於邊緣檢測的標准演算法,其目標是找到一個最優的邊緣檢測解或找尋一幅圖像中灰度強度變化最強的位置。最優邊緣檢測主要通過低錯誤率、高定位性和最小響應三個標准進行評價。

Canny運算元的實現步驟如下:

edges = Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]])

LOG(Laplacian of Gaussian)邊緣檢測運算元也稱為Marr&Hildreth運算元,它根據圖像的信噪比來求檢測邊緣的最優濾波器。該演算法首先對圖像做高斯濾波,然後再求其拉普拉斯(Laplacian)二階導數,根據二階導數的過零點來檢測圖像的邊界,即通過檢測濾波結果的零交叉(Zero crossings)來獲得圖像或物體的邊緣。

LOG運算元該綜合考慮了對雜訊的抑制和對邊緣的檢測兩個方面,並且把Gauss平滑濾波器和Laplacian銳化濾波器結合了起來,先平滑掉雜訊,再進行邊緣檢測,所以效果會更好。 該運算元與視覺生理中的數學模型相似,因此在圖像處理領域中得到了廣泛的應用。它具有抗干擾能力強,邊界定位精度高,邊緣連續性好,能有效提取對比度弱的邊界等特點。

2. canny演算法的演算法的實現步驟

Canny邊緣檢測演算法可以分為以下5個步驟: 應用高斯濾波來平滑圖像,目的是去除雜訊 找尋圖像的強度梯度(intensity gradients) 應用非最大抑制(non-maximum suppression)技術來消除邊誤檢(本來不是但檢測出來是) 應用雙閾值的方法來決定可能的(潛在的)邊界 利用滯後技術來跟蹤邊界 1. 圖像平滑(去雜訊)
任何邊緣檢測演算法都不可能在未經處理的原始數據上很好地工作,所以第一步是對原始數據與高斯 mask 作卷積,得到的圖像與原始圖像相比有些輕微的模糊(blurred)。這樣,單獨的一個像素雜訊在經過高斯平滑的圖像上變得幾乎沒有影響。以下為一個5X5高斯濾波器(高斯核,標准差delta=1.4),其中A為原始圖像,B為平滑後的圖像。


2. 尋找圖像中的強度梯度
Canny演算法的基本思想是找尋一幅圖相中灰度強度變化最強的位置。所謂變化最強,即指梯度方向。平滑後的圖像中每個像素點的梯度可以由Sobel運算元(一種卷積運算)來獲得(opencv中有封裝好的函數,可以求圖像中每個像素點的n階導數)。首先,利用如下的核來分別求得沿水平(x)和垂直(y)方向的梯度G_X和G_Y。
K_{GX} = [-1 0 1 ; -2 0 2 ; -1 0 1], K_{GY} = {1 2 1 ; 0 0 0 ; -1 -2 -1}
之後便可利用公式來求得每一個像素點的梯度度量值(gradient magnitude,可能翻譯得不準確)。
,有時為了計算簡便,也會使用G_X和G_Y的無窮大范數來代替二范數。把平滑後的圖像中的每一個點用G代替,可以獲得如下圖像。從下圖可以看出,在變化劇烈的地方(邊界處),將獲得較大的梯度度量值G,對應的顏色為白色。然而,這些邊界通常非常粗,難以標定邊界的真正位置。為了做到這一點(參考非極大抑制Non-maximum suppression一節),還必須存儲梯度方向,其公式如下圖所示。也就是說在這一步我們會存數兩塊數據,一是梯度的強度信息,另一個是梯度的方向信息。

3. 非極大抑制Non-maximum suppression
這一步的目的是將模糊(blurred)的邊界變得清晰(sharp)。通俗的講,就是保留了每個像素點上梯度強度的極大值,而刪掉其他的值。對於每個像素點,進行如下操作:
a) 將其梯度方向近似為以下值中的一個(0,45,90,135,180,225,270,315)(即上下左右和45度方向)
b) 比較該像素點,和其梯度方向正負方向的像素點的梯度強度
c) 如果該像素點梯度強度最大則保留,否則抑制(刪除,即置為0)
為了更好的解釋這個概念,看下圖。

圖中的數字代表了像素點的梯度強度,箭頭方向代表了梯度方向。以第二排第三個像素點為例,由於梯度方向向上,則將這一點的強度(7)與其上下兩個像素點的強度(5和4)比較,由於這一點強度最大,則保留。處理後效果如下圖所示。

上圖中,可以想像,邊界處的梯度方向總是指向垂直於邊界的方向,即最後會保留一條邊界處最亮的一條細線。
4.雙閾值(Double Thresholding)
經過非極大抑制後圖像中仍然有很多雜訊點。Canny演算法中應用了一種叫雙閾值的技術。即設定一個閾值上界和閾值下界(opencv中通常由人為指定的),圖像中的像素點如果大於閾值上界則認為必然是邊界(稱為強邊界,strong edge),小於閾值下界則認為必然不是邊界,兩者之間的則認為是候選項(稱為弱邊界,weak edge),需進行進一步處理。經過雙閾值處理的圖像如下圖所示

上圖中右側強邊界用白色表示,弱邊界用灰色表示。
5.利用滯後的邊界跟蹤
這里就不細作解釋了。大體思想是,和強邊界相連的弱邊界認為是邊界,其他的弱邊界則被抑制。
以上內容均翻譯自參考文獻【4】
上一個網路版本:
圖像中的邊緣可能會指向不同的方向,所以 Canny 演算法使用 4 個 掩模(mask) 檢測水平、垂直以及對角線方向的邊緣。原始圖像與每個 mask 所作的卷積都存儲起來。對於每個點我們都標識在這個點上的最大值以及生成的邊緣的方向。這樣我們就從原始圖像生成了圖像中每個點亮度梯度圖以及亮度梯度的方向。以下兩個公式分別求取高斯濾波後圖像的梯度幅值及其方向的表達式。這一步,也叫稱為非極大抑制(Non-maximum suppression)。


3. 在圖像中跟蹤邊緣
較高的亮度梯度比較有可能是邊緣,但是沒有一個確切的值來限定多大的亮度梯度是邊緣多大又不是,所以 Canny 使用了滯後閾值。
滯後閾值(Hysteresis thresholding) 需要兩個閾值,即高閾值與低閾值。假設圖像中的重要邊緣都是連續的曲線,這樣我們就可以跟蹤給定曲線中模糊的部分,並且避免將沒有組成曲線 的雜訊像素當成邊緣。所以我們從一個較大的閾值開始,這將標識出我們比較確信的真實邊緣,使用前面導出的方向信息,我們從這些真正的邊緣開始在圖像中跟蹤 整個的邊緣。在跟蹤的時候,我們使用一個較小的閾值,這樣就可以跟蹤曲線的模糊部分直到我們回到起點。
一旦這個過程完成,我們就得到了一個二值圖像,每點表示是否是一個邊緣點。
一個獲得亞像素精度邊緣的改進實現是在梯度方向檢測二階方向導數的過零點,它在梯度方向的三階方向導數滿足符號條件。
滯後閾值也可以用於亞像素邊緣檢測。

3. EmguCV學習 與opencv的區別和聯系

openCV是因特爾的一個開源的視覺庫,裡面幾乎
包含了所有的圖像處理的經典演算法,並且採用C和少量的C++編寫,運行效率很高,對於做圖像處理這方面工作的,認識opencv是必須的工作。不過
opencv有個很大的不足,這在於它幾乎沒有提供gui這方面介面,很難滿足目前應用程序開發的需要,而萬惡的MFC框架醜陋的界面也成為了我的噩
夢,MFC與opencv和界面優化幾乎讓我在圖像處理這一塊兒無法動彈。
C#
是.net平台上的明星語言,可以很容易做出漂亮的界面。EmguCV是將opencv封裝的一個.net庫可以被VC++,VC#,VB.net調用。
網上對於EmguCV的介紹很少,不是因為它沒用,而是因為它的使用方法幾乎和opencv一摸一樣,opencv的資料完全可以直接用於EmguCV。
不過不少新手在使用EmguCV在使用幾次之後便放棄。這有以下幾個原因:
1.
輿論影響,很多人都說C#的運行效率低,採用C/C++,opencv是C和C++編寫的,理所當然應該在VC++中運行,圖像處理又是一個計算量很大的
工作,C#不行。C#運行效率肯定比C/C++差,但是採用混合編程的方法就可以啦,用C#的框架和運行機制,計算交給C就好啦。EmguCV很多處理函
數都是採用託管調用opencv。這個在EmguCV的安裝包里可以看到,裡面含有所有Opencv的dll。

2.
缺少資料,學習受挫而放棄(我放棄這個大概有半年)。不得不承認EmguCV方面的學習資料實在是太少啦。很多時候出現問題,在網上基本上找不到答案。而
且EmguCV前期版本對opencv封裝不全面,很多基本的函數沒有被封裝,使用起來很不方便,網上很多人以訛傳訛,編寫很困難。不過使用2.3版本就
沒有這個問題,opencv基本函數都得到了很好的封裝。opencv圖像處理的函數都封裝在cvInvoke中

而Image<>結構是連接opencv與emgucv的重要橋梁。其中C#的Intptr類型可以很好地傳遞IplImage*指針結構,下面我用一個實驗來驗證我的判斷。
創建一個winform工程,添加一個button和picturebox控制項

添加如下代碼
Capture cam;

private void btopen_Click(object sender, EventArgs e)
{
cam = new Capture();
Application.Idle += new EventHandler(processframe);

}

private void processframe(object sender, EventArgs arg)
{
Image<Bgr, Byte> frame = cam.QueryFrame();
Image<Gray,Byte> Ecanny=frame.Convert<Gray,Byte>();
CvInvoke.cvCanny(Ecanny.Ptr, Ecanny.Ptr, 50, 150, 3);
//cvCanny是opencv中常用的函數,原本的參數應該是IplImage*類型,這里使用Intpr代替,即Ecanny.ptr
pictureBox1.Image = Ecanny.Bitmap;
}
運行結果如下

當然如果只是簡單的canny演算法,使用EmguCV封裝的結構Image<>更加簡單,將代碼如下圖所示修改

運行結果如下圖所示

上述實驗表明,EmguCV可以很好地連接C#與opencv,能夠彌補opencv在gui這方面的不足,有利於機器視覺開發者得工作

4. 3種python3的canny邊緣檢測之靜態,可調節和自適應

先看高級版的python3的canny的自適應邊緣檢測:

內容:

1 canny的邊緣檢測的介紹。

2 三種方法的canny的邊緣檢測,由淺入深地介紹:固定值的靜態,可自調節的,自適應的。

說明:

1 環境:python3.8、opencv4.5.3和matplotlib3.4.3。

2 圖片:來自品閱網正版免費圖庫。

3 實現自適應閾值的canny邊緣檢測的參考代碼和文章:

上述的代碼,本機均有報錯,故對代碼進行修改,注釋和運行。

初級canny:

1 介紹:opencv中給出了canny邊緣檢測的介面,直接調用:

即可得到邊緣檢測的結果ret,其中,t1,t2是需要人為設置的閾值。

2 python的opencv的一行代碼即可實現邊緣檢測。

3 Canny函數及使用:

4 Canny邊緣檢測流程:

去噪 --> 梯度 --> 非極大值抑制 --> 滯後閾值

5 代碼:

6 操作和過程:

7 原圖:

8 疑問:

ret = cv2.canny(img,t1,t2),其中,t1,t2是需要人為設置的閾值,一般人怎麼知道具體數值是多少,才是最佳的呀?所以,這是它的缺點。

中級canny:

1 中級canny,就是可調節的閾值,找到最佳的canny邊緣檢測效果。

2 採用cv2.createTrackbar來調節閾值。

3 代碼:

4 操作和效果:

5 原圖:

高級canny:

1 自適應canny的演算法:

ret = cv2.canny(img,t1,t2)

即演算法在運行過程中能夠自適應地找到較佳的分割閾值t1,t2。

2 文件結構:

3 main.py代碼:

4 dog.py代碼:

5 bilateralfilt.py代碼:

6 原圖:

7 效果圖:本文第一個gif圖,此處省略。

小結:

1 本文由淺入深,總結的很好,適合收藏。

2 對於理解python的opencv的canny的邊緣檢測,很有幫助。

3 本文高級版canny自適應的演算法參考2篇文章,雖然我進行代碼的刪除,注釋,修改,優化等操作,故我不標注原創,對原作者表達敬意。

4 自己總結和整理,分享出來,希望對大家有幫助。

5. 如何利用opencv實現彩色圖像邊緣檢測演算法

在opencv中顯示邊緣檢測很簡單,只需調用一個cvCanny函數,其使用的是Canny演算法來實現對圖像的邊緣檢測.
函數原型為:
void cvCanny( const CvArr* image,CvArr* edges,double threshold1,double threshold2, int aperture_size=3 );
第一個參數為待檢測的圖像,注意一點,其必須是灰度圖.
第二個參數為輸出的邊緣圖,其也是一個灰度圖.
後三個參數與Canny演算法直接相關,threshold1和threshold2 當中的小閾值用來控制邊緣連接,大的閾值用來控制強邊緣的初始分割,aperture_size運算元內核大小,可以去看看Canny演算法.
從彩色圖到灰度圖需要使用到cvCvtColor函數,其接受三個參數,第一為輸入,第二為輸出,第三個為轉換的標識,我們這邊是RGB到GRAY,使用的是CV_RGB2GRAY.
參考demo代碼如下:

#include <iostream>

#include <string>
#include <sstream>
#include <opencv/cv.h>
#include <opencv/highgui.h>

using namespace std;

int String2int(const string& str_)
{
int _nre = 0;
stringstream _ss;
_ss << str_;
_ss >> _nre;
return _nre;
}

void DoCanny(const string& strFileName_)
{
//原彩色圖片
IplImage* _pIplImageIn = cvLoadImage(strFileName_.data());

if (_pIplImageIn == NULL)
{
return;
}
//彩色圖片轉換成灰度圖放置的圖片
IplImage* _pIplImageCanny = cvCreateImage(cvGetSize(_pIplImageIn), _pIplImageIn->depth, 1);
cvCvtColor(_pIplImageIn, _pIplImageCanny, CV_RGB2GRAY);//CV_RGB2GRAY將rgb圖轉成灰度圖
//只有邊緣路徑的圖片
IplImage* _pIplImageOut = cvCreateImage(cvGetSize(_pIplImageIn), IPL_DEPTH_8U, 1);

//邊緣檢測只能作用於灰度圖
if (_pIplImageCanny->nChannels != 1)
{
return;
}

//邊緣檢測操作
cvCanny(_pIplImageCanny, _pIplImageOut, 1, 110, 3);

cvNamedWindow("Src");
cvShowImage("Src", _pIplImageIn);
cvNamedWindow("Canny");
cvShowImage("Canny", _pIplImageOut);

cvWaitKey(0);

cvReleaseImage(&_pIplImageIn);
cvReleaseImage(&_pIplImageCanny);
cvReleaseImage(&_pIplImageOut);

cvDestroyWindow("Src");
cvDestroyWindow("Canny");

}

int main(int argc, char* argv[])
{
if (argc < 2)
{
cout << "You should give the filename of picture!" << endl;
return -1;
}
DoCanny(argv[1]);
return 0;
}

閱讀全文

與canny演算法是opencv相關的資料

熱點內容
oracledbcalinux 瀏覽:842
酬勤任務app怎麼被特邀 瀏覽:197
android應用文件夾 瀏覽:1000
平面設計法則pdf 瀏覽:337
3d圓角命令怎麼用 瀏覽:567
程序員買意外險還是重疾險 瀏覽:619
遼寧的dns伺服器地址雲空間 瀏覽:446
我的世界伺服器斷開後怎麼連接 瀏覽:413
htmltopdfpython 瀏覽:75
如何預覽網站源碼文件 瀏覽:35
怎麼修改後台源碼 瀏覽:28
bat編程入門 瀏覽:853
命令與征服下載手機版 瀏覽:11
單片機控制櫃說明什麼 瀏覽:854
javacontainskey 瀏覽:221
win10操作系統如何設置伺服器 瀏覽:415
wow法師宏命令大全 瀏覽:138
iphone備份到阿里雲伺服器 瀏覽:148
解壓植物大全 瀏覽:543
木門加密碼鎖效果圖 瀏覽:582