日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

【OpenCV入门教程之十二】OpenCV边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器合辑

發(fā)布時(shí)間:2023/12/8 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【OpenCV入门教程之十二】OpenCV边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器合辑 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.



本系列文章由@淺墨_毛星云?出品,轉(zhuǎn)載請(qǐng)注明出處。??

文章鏈接:?http://blog.csdn.net/poem_qianmo/article/details/25560901

作者:毛星云(淺墨) ? ?微博:http://weibo.com/u/1723155442

知乎:http://www.zhihu.com/people/mao-xing-yun

郵箱:?happylifemxy@163.com

寫(xiě)作當(dāng)前博文時(shí)配套使用的OpenCV版本: 2.4.9


?

本篇文章中,我們將一起學(xué)習(xí)OpenCV中邊緣檢測(cè)的各種算子和濾波器——Canny算子,Sobel算子,Laplace算子以及Scharr濾波器。文章中包含了五個(gè)淺墨為大家準(zhǔn)備的詳細(xì)注釋的博文配套源代碼。在介紹四塊知識(shí)點(diǎn)的時(shí)候分別一個(gè),以及最后的綜合示例中的一個(gè)。文章末尾提供配套源代碼的下載。

依然是是放出一些程序運(yùn)行截圖吧:

?

?效果圖看完,我們來(lái)嘮嘮嗑。


首先需要說(shuō)明的是,淺墨這篇文章最后的示例代碼是采用兩周前剛剛發(fā)布的2.4.9來(lái)書(shū)寫(xiě)的。里面的lib都已經(jīng)改成了2.4.9版本的。如果大家需要運(yùn)行的話,要么配置好2.4.9.要么把淺墨在工程中包含的末尾數(shù)字為249的各種lib改成之前的248或者你對(duì)應(yīng)的OpenCV版本。

不然會(huì)提示:?LINK : fatal error LNK1181: 無(wú)法打開(kāi)輸入文件“opencv_calib3d248.lib”之類的錯(cuò)誤。

OpenCV 2.4.9的配置和之前的2.4.8差不多,如果還是不太清楚,具體可以參考淺墨修改過(guò)的對(duì)應(yīng)2.4.9版的配置文章:


【OpenCV入門(mén)教程之一】 安裝OpenCV:OpenCV 2.4.8或2.4.9 +VS 開(kāi)發(fā)環(huán)境配置

?

第二,給大家分享一個(gè)OpenCV中寫(xiě)代碼時(shí)節(jié)約時(shí)間的小常識(shí)。其實(shí)OpenCV中,不用namedWindow,直接imshow就可以顯示出窗口。大家看下文的示例代碼就可以發(fā)現(xiàn),淺墨在寫(xiě)代碼的時(shí)候并沒(méi)有用namedWindow,遇到想顯示出來(lái)的Mat變量直接imshow。我們一般是為了規(guī)范,才先用namedWindow創(chuàng)建窗口,再imshow出它來(lái),因?yàn)槲覀冞€有需要用到指定窗口名稱的地方,比如用到trackbar的時(shí)候。而一般情況想顯示一個(gè)Mat變量的圖片的話,直接imshow就可以啦。

?

OK,開(kāi)始正文吧~


?




一、關(guān)于邊緣檢測(cè)

???????



在具體介紹之前,先來(lái)一起看看邊緣檢測(cè)的一般步驟吧。


1)濾波:邊緣檢測(cè)的算法主要是基于圖像強(qiáng)度的一階和二階導(dǎo)數(shù),但導(dǎo)數(shù)通常對(duì)噪聲很敏感,因此必須采用濾波器來(lái)改善與噪聲有關(guān)的邊緣檢測(cè)器的性能。常見(jiàn)的濾波方法主要有高斯濾波,即采用離散化的高斯函數(shù)產(chǎn)生一組歸一化的高斯核(具體見(jiàn)“高斯濾波原理及其編程離散化實(shí)現(xiàn)方法”一文),然后基于高斯核函數(shù)對(duì)圖像灰度矩陣的每一點(diǎn)進(jìn)行加權(quán)求和(具體程序?qū)崿F(xiàn)見(jiàn)下文)。

?

??????? 2)增強(qiáng):增強(qiáng)邊緣的基礎(chǔ)是確定圖像各點(diǎn)鄰域強(qiáng)度的變化值。增強(qiáng)算法可以將圖像灰度點(diǎn)鄰域強(qiáng)度值有顯著變化的點(diǎn)凸顯出來(lái)。在具體編程實(shí)現(xiàn)時(shí),可通過(guò)計(jì)算梯度幅值來(lái)確定。

?

????? ??3)檢測(cè):經(jīng)過(guò)增強(qiáng)的圖像,往往鄰域中有很多點(diǎn)的梯度值比較大,而在特定的應(yīng)用中,這些點(diǎn)并不是我們要找的邊緣點(diǎn),所以應(yīng)該采用某種方法來(lái)對(duì)這些點(diǎn)進(jìn)行取舍。實(shí)際工程中,常用的方法是通過(guò)閾值化方法來(lái)檢測(cè)。


另外,需要注意,下文中講到的Laplace算子,sobel算子和Scharr算子都是帶方向的,所以,示例中我們分別寫(xiě)了X方向,Y方向和最終合成的的效果圖。


OK,正餐開(kāi)始,召喚canny算子。:)

?








二、canny算子篇

?



2.1 canny算子相關(guān)理論與概念講解



2.1.1 canny算子簡(jiǎn)介


Canny邊緣檢測(cè)算子是John F.Canny于 1986 年開(kāi)發(fā)出來(lái)的一個(gè)多級(jí)邊緣檢測(cè)算法。更為重要的是 Canny 創(chuàng)立了邊緣檢測(cè)計(jì)算理論(Computational theory ofedge detection),解釋了這項(xiàng)技術(shù)是如何工作的。Canny邊緣檢測(cè)算法以Canny的名字命名,被很多人推崇為當(dāng)今最優(yōu)的邊緣檢測(cè)的算法。

其中,Canny 的目標(biāo)是找到一個(gè)最優(yōu)的邊緣檢測(cè)算法,讓我們看一下最優(yōu)邊緣檢測(cè)的三個(gè)主要評(píng)價(jià)標(biāo)準(zhǔn):

?

1.低錯(cuò)誤率: 標(biāo)識(shí)出盡可能多的實(shí)際邊緣,同時(shí)盡可能的減少噪聲產(chǎn)生的誤報(bào)。


2.高定位性: 標(biāo)識(shí)出的邊緣要與圖像中的實(shí)際邊緣盡可能接近。


3.最小響應(yīng): 圖像中的邊緣只能標(biāo)識(shí)一次,并且可能存在的圖像噪聲不應(yīng)標(biāo)識(shí)為邊緣。

?

為了滿足這些要求 Canny 使用了變分法,這是一種尋找滿足特定功能的函數(shù)的方法。最優(yōu)檢測(cè)使用四個(gè)指數(shù)函數(shù)項(xiàng)的和表示,但是它非常近似于高斯函數(shù)的一階導(dǎo)數(shù)。

?



?

2.1.2 Canny 邊緣檢測(cè)的步驟



1.消除噪聲。 一般情況下,使用高斯平滑濾波器卷積降噪。 如下顯示了一個(gè) size = 5 的高斯內(nèi)核示例:




?

2.計(jì)算梯度幅值和方向。 此處,按照Sobel濾波器的步驟。

?

Ⅰ.運(yùn)用一對(duì)卷積陣列 (分別作用于 x 和 y 方向):


?



Ⅱ.使用下列公式計(jì)算梯度幅值和方向:



?

梯度方向近似到四個(gè)可能角度之一(一般為0, 45, 90, 135)

?

3.非極大值抑制。 這一步排除非邊緣像素, 僅僅保留了一些細(xì)線條(候選邊緣)。


?

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

?

Ⅰ.如果某一像素位置的幅值超過(guò) 高 閾值, 該像素被保留為邊緣像素。

Ⅱ.如果某一像素位置的幅值小于 低 閾值, 該像素被排除。

.如果某一像素位置的幅值在兩個(gè)閾值之間,該像素僅僅在連接到一個(gè)高于 高 閾值的像素時(shí)被保留。


tips:對(duì)于Canny函數(shù)的使用,推薦的高低閾值比在2:1到3:1之間。

?

更多的細(xì)節(jié),可以參考canny算子的wikipedia:

http://en.wikipedia.org/wiki/Canny_edge_detector

canny邊緣檢測(cè)的原理講述,課參看這篇博文:

http://blog.csdn.net/likezhaobin/article/details/6892176

canny算子的中文wikipedia:

http://zh.wikipedia.org/wiki/Canny%E7%AE%97%E5%AD%90

?



2.2 OpenCV中Canny函數(shù)詳解

?

Canny函數(shù)利用Canny算法來(lái)進(jìn)行圖像的邊緣檢測(cè)。

?

C++: void Canny(InputArray image,OutputArray edges, double threshold1, double threshold2, int apertureSize=3,bool L2gradient=false )


  • 第一個(gè)參數(shù),InputArray類型的image,輸入圖像,即源圖像,填Mat類的對(duì)象即可,且需為單通道8位圖像。
  • 第二個(gè)參數(shù),OutputArray類型的edges,輸出的邊緣圖,需要和源圖片有一樣的尺寸和類型。
  • 第三個(gè)參數(shù),double類型的threshold1,第一個(gè)滯后性閾值。
  • 第四個(gè)參數(shù),double類型的threshold2,第二個(gè)滯后性閾值。
  • 第五個(gè)參數(shù),int類型的apertureSize,表示應(yīng)用Sobel算子的孔徑大小,其有默認(rèn)值3。
  • 第六個(gè)參數(shù),bool類型的L2gradient,一個(gè)計(jì)算圖像梯度幅值的標(biāo)識(shí),有默認(rèn)值false。

?

需要注意的是,這個(gè)函數(shù)閾值1和閾值2兩者的小者用于邊緣連接,而大者用來(lái)控制強(qiáng)邊緣的初始段,推薦的高低閾值比在2:1到3:1之間。

?

調(diào)用示例:

//載入原始圖 Mat src = imread("1.jpg"); //工程目錄下應(yīng)該有一張名為1.jpg的素材圖Canny(src, src, 3, 9,3 );imshow("【效果圖】Canny邊緣檢測(cè)", src);

如上三句,就有結(jié)果出來(lái),非常好用。

?

?



2.3 調(diào)用Canny函數(shù)的實(shí)例代碼

?


OpenCV中調(diào)用Canny函數(shù)的實(shí)例代碼如下:

?

//-----------------------------------【頭文件包含部分】--------------------------------------- // 描述:包含程序所依賴的頭文件 //---------------------------------------------------------------------------------------------- #include <opencv2/opencv.hpp> #include<opencv2/highgui/highgui.hpp> #include<opencv2/imgproc/imgproc.hpp>//-----------------------------------【命名空間聲明部分】--------------------------------------- // 描述:包含程序所使用的命名空間 //----------------------------------------------------------------------------------------------- using namespace cv; //-----------------------------------【main( )函數(shù)】-------------------------------------------- // 描述:控制臺(tái)應(yīng)用程序的入口函數(shù),我們的程序從這里開(kāi)始 //----------------------------------------------------------------------------------------------- int main( ) {//載入原始圖 Mat src = imread("1.jpg"); //工程目錄下應(yīng)該有一張名為1.jpg的素材圖Mat src1=src.clone();//顯示原始圖 imshow("【原始圖】Canny邊緣檢測(cè)", src); //----------------------------------------------------------------------------------// 一、最簡(jiǎn)單的canny用法,拿到原圖后直接用。//----------------------------------------------------------------------------------Canny( src, src, 150, 100,3 );imshow("【效果圖】Canny邊緣檢測(cè)", src); //----------------------------------------------------------------------------------// 二、高階的canny用法,轉(zhuǎn)成灰度圖,降噪,用canny,最后將得到的邊緣作為掩碼,拷貝原圖到效果圖上,得到彩色的邊緣圖//----------------------------------------------------------------------------------Mat dst,edge,gray;// 【1】創(chuàng)建與src同類型和大小的矩陣(dst)dst.create( src1.size(), src1.type() );// 【2】將原圖像轉(zhuǎn)換為灰度圖像cvtColor( src1, gray, CV_BGR2GRAY );// 【3】先用使用 3x3內(nèi)核來(lái)降噪blur( gray, edge, Size(3,3) );// 【4】運(yùn)行Canny算子Canny( edge, edge, 3, 9,3 );//【5】將g_dstImage內(nèi)的所有元素設(shè)置為0 dst = Scalar::all(0);//【6】使用Canny算子輸出的邊緣圖g_cannyDetectedEdges作為掩碼,來(lái)將原圖g_srcImage拷到目標(biāo)圖g_dstImage中src1.copyTo( dst, edge);//【7】顯示效果圖 imshow("【效果圖】Canny邊緣檢測(cè)2", dst); waitKey(0); return 0; }


運(yùn)行效果圖:

?


?

?

?










三、sobel算子篇





3.1 sobel算子相關(guān)理論與概念講解




3.1.1 基本概念


Sobel 算子是一個(gè)主要用作邊緣檢測(cè)的離散微分算子 (discrete differentiation operator)。 它Sobel算子結(jié)合了高斯平滑和微分求導(dǎo),用來(lái)計(jì)算圖像灰度函數(shù)的近似梯度。在圖像的任何一點(diǎn)使用此算子,將會(huì)產(chǎn)生對(duì)應(yīng)的梯度矢量或是其法矢量。


sobel算子的wikipedia:

http://zh.wikipedia.org/wiki/%E7%B4%A2%E8%B2%9D%E7%88%BE%E7%AE%97%E5%AD%90

?

sobel算子相關(guān)概念,還可以參看這篇博文:

http://www.cnblogs.com/lancidie/archive/2011/07/17/2108885.html

?



3.1.2 sobel算子的計(jì)算過(guò)程



我們假設(shè)被作用圖像為 I.然后進(jìn)行如下的操作:

?

1.分別在x和y兩個(gè)方向求導(dǎo)。


Ⅰ.水平變化: 將 I 與一個(gè)奇數(shù)大小的內(nèi)核進(jìn)行卷積。比如,當(dāng)內(nèi)核大小為3時(shí), 的計(jì)算結(jié)果為:


?

?

?

Ⅱ.垂直變化: 將: I 與一個(gè)奇數(shù)大小的內(nèi)核進(jìn)行卷積。比如,當(dāng)內(nèi)核大小為3時(shí), 的計(jì)算結(jié)果為:


?

?

2.在圖像的每一點(diǎn),結(jié)合以上兩個(gè)結(jié)果求出近似梯度:

?


另外有時(shí),也可用下面更簡(jiǎn)單公式代替:

?

?

?


3.2 OpenCV中Sobel函數(shù)詳解



Sobel函數(shù)使用擴(kuò)展的 Sobel 算子,來(lái)計(jì)算一階、二階、三階或混合圖像差分。


C++: void Sobel ( InputArray src,//輸入圖OutputArray dst,//輸出圖int ddepth,//輸出圖像的深度int dx,int dy,int ksize=3,double scale=1,double delta=0,int borderType=BORDER_DEFAULT );


  • 第一個(gè)參數(shù),InputArray 類型的src,為輸入圖像,填Mat類型即可。
  • 第二個(gè)參數(shù),OutputArray類型的dst,即目標(biāo)圖像,函數(shù)的輸出參數(shù),需要和源圖片有一樣的尺寸和類型。
  • 第三個(gè)參數(shù),int類型的ddepth,輸出圖像的深度,支持如下src.depth()和ddepth的組合:
    • 若src.depth() = CV_8U, 取ddepth =-1/CV_16S/CV_32F/CV_64F
    • 若src.depth() = CV_16U/CV_16S, 取ddepth =-1/CV_32F/CV_64F
    • 若src.depth() = CV_32F, 取ddepth =-1/CV_32F/CV_64F
    • 若src.depth() = CV_64F, 取ddepth = -1/CV_64F
  • 第四個(gè)參數(shù),int類型dx,x 方向上的差分階數(shù)。
  • 第五個(gè)參數(shù),int類型dy,y方向上的差分階數(shù)。
  • 第六個(gè)參數(shù),int類型ksize,有默認(rèn)值3,表示Sobel核的大小;必須取1,3,5或7。
  • 第七個(gè)參數(shù),double類型的scale,計(jì)算導(dǎo)數(shù)值時(shí)可選的縮放因子,默認(rèn)值是1,表示默認(rèn)情況下是沒(méi)有應(yīng)用縮放的。我們可以在文檔中查閱getDerivKernels的相關(guān)介紹,來(lái)得到這個(gè)參數(shù)的更多信息。
  • 第八個(gè)參數(shù),double類型的delta,表示在結(jié)果存入目標(biāo)圖(第二個(gè)參數(shù)dst)之前可選的delta值,有默認(rèn)值0。
  • 第九個(gè)參數(shù), int類型的borderType,我們的老朋友了(萬(wàn)年是最后一個(gè)參數(shù)),邊界模式,默認(rèn)值為BORDER_DEFAULT。這個(gè)參數(shù)可以在官方文檔中borderInterpolate處得到更詳細(xì)的信息。


一般情況下,都是用ksize x ksize內(nèi)核來(lái)計(jì)算導(dǎo)數(shù)的。然而,有一種特殊情況——當(dāng)ksize為1時(shí),往往會(huì)使用3 x 1或者1 x 3的內(nèi)核。且這種情況下,并沒(méi)有進(jìn)行高斯平滑操作。

?

一些補(bǔ)充說(shuō)明:


1.當(dāng)內(nèi)核大小為 3 時(shí), 我們的Sobel內(nèi)核可能產(chǎn)生比較明顯的誤差(畢竟,Sobel算子只是求取了導(dǎo)數(shù)的近似值而已)。 為解決這一問(wèn)題,OpenCV提供了Scharr 函數(shù),但該函數(shù)僅作用于大小為3的內(nèi)核。該函數(shù)的運(yùn)算與Sobel函數(shù)一樣快,但結(jié)果卻更加精確,其內(nèi)核是這樣的:


?

?

2.因?yàn)镾obel算子結(jié)合了高斯平滑和分化(differentiation),因此結(jié)果會(huì)具有更多的抗噪性。大多數(shù)情況下,我們使用sobel函數(shù)時(shí),取【xorder = 1,yorder = 0,ksize = 3】來(lái)計(jì)算圖像X方向的導(dǎo)數(shù),【xorder = 0,yorder = 1,ksize = 3】來(lái)計(jì)算圖像y方向的導(dǎo)數(shù)。

計(jì)算圖像X方向的導(dǎo)數(shù),取【xorder= 1,yorder = 0,ksize = 3】情況對(duì)應(yīng)的內(nèi)核:


?

?

而計(jì)算圖像Y方向的導(dǎo)數(shù),取【xorder= 0,yorder = 1,ksize = 3】對(duì)應(yīng)的內(nèi)核:



?


3.3 調(diào)用Sobel函數(shù)的實(shí)例代碼



調(diào)用Sobel函數(shù)的實(shí)例代碼如下。這里只是教大家如何使用Sobel函數(shù),就沒(méi)有先用一句cvtColor將原圖;轉(zhuǎn)化為灰度圖,而是直接用彩色圖操作。

?

//-----------------------------------【頭文件包含部分】--------------------------------------- // 描述:包含程序所依賴的頭文件 //---------------------------------------------------------------------------------------------- #include <opencv2/opencv.hpp> #include<opencv2/highgui/highgui.hpp> #include<opencv2/imgproc/imgproc.hpp>//-----------------------------------【命名空間聲明部分】--------------------------------------- // 描述:包含程序所使用的命名空間 //----------------------------------------------------------------------------------------------- using namespace cv; //-----------------------------------【main( )函數(shù)】-------------------------------------------- // 描述:控制臺(tái)應(yīng)用程序的入口函數(shù),我們的程序從這里開(kāi)始 //----------------------------------------------------------------------------------------------- int main( ) {//【0】創(chuàng)建 grad_x 和 grad_y 矩陣Mat grad_x, grad_y;Mat abs_grad_x, abs_grad_y,dst;//【1】載入原始圖 Mat src = imread("1.jpg"); //工程目錄下應(yīng)該有一張名為1.jpg的素材圖//【2】顯示原始圖 imshow("【原始圖】sobel邊緣檢測(cè)", src); //【3】求 X方向梯度Sobel( src, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT );convertScaleAbs( grad_x, abs_grad_x );imshow("【效果圖】 X方向Sobel", abs_grad_x); //【4】求Y方向梯度Sobel( src, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT );convertScaleAbs( grad_y, abs_grad_y );imshow("【效果圖】Y方向Sobel", abs_grad_y); //【5】合并梯度(近似)addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst );imshow("【效果圖】整體方向Sobel", dst); waitKey(0); return 0; }


運(yùn)行截圖如下:

?


?











四、Laplace算子篇




4.1 Laplace算子相關(guān)理論與概念講解

?

Laplacian 算子是n維歐幾里德空間中的一個(gè)二階微分算子,定義為梯度grad()的散度div()。因此如果f是二階可微的實(shí)函數(shù),則f的拉普拉斯算子定義為:


(1) f的拉普拉斯算子也是笛卡兒坐標(biāo)系xi中的所有非混合二階偏導(dǎo)數(shù)求和:

(2) 作為一個(gè)二階微分算子,拉普拉斯算子把C函數(shù)映射到C函數(shù),對(duì)于k ≥ 2。表達(dá)式(1)(或(2))定義了一個(gè)算子Δ :C(R) → C(R),或更一般地,定義了一個(gè)算子Δ : C(Ω) → C(Ω),對(duì)于任何開(kāi)集Ω。

?

根據(jù)圖像處理的原理我們知道,二階導(dǎo)數(shù)可以用來(lái)進(jìn)行檢測(cè)邊緣 。 因?yàn)閳D像是 “二維”, 我們需要在兩個(gè)方向進(jìn)行求導(dǎo)。使用Laplacian算子將會(huì)使求導(dǎo)過(guò)程變得簡(jiǎn)單。

?

Laplacian 算子的定義:


?

?

需要點(diǎn)破的是,由于 Laplacian使用了圖像梯度,它內(nèi)部的代碼其實(shí)是調(diào)用了 Sobel 算子的。


另附一個(gè)小tips:讓一幅圖像減去它的Laplacian可以增強(qiáng)對(duì)比度。


?

關(guān)于Laplace算子的相關(guān)概念闡述,可以參看這篇博文:

http://www.cnblogs.com/xfzhang/archive/2011/01/19/1939020.html

Laplace算子的wikipedia:

http://zh.wikipedia.org/wiki/%E6%8B%89%E6%99%AE%E6%8B%89%E6%96%AF%E7%AE%97%E5%AD%90

?



4.2 OpenCV中Laplacian函數(shù)詳解



Laplacian函數(shù)可以計(jì)算出圖像經(jīng)過(guò)拉普拉斯變換后的結(jié)果。

?

C++: void Laplacian(InputArray src,OutputArray dst, int ddepth, int ksize=1, double scale=1, double delta=0, intborderType=BORDER_DEFAULT );

  • 第一個(gè)參數(shù),InputArray類型的image,輸入圖像,即源圖像,填Mat類的對(duì)象即可,且需為單通道8位圖像。
  • 第二個(gè)參數(shù),OutputArray類型的edges,輸出的邊緣圖,需要和源圖片有一樣的尺寸和通道數(shù)。
  • 第三個(gè)參數(shù),int類型的ddept,目標(biāo)圖像的深度。
  • 第四個(gè)參數(shù),int類型的ksize,用于計(jì)算二階導(dǎo)數(shù)的濾波器的孔徑尺寸,大小必須為正奇數(shù),且有默認(rèn)值1。
  • 第五個(gè)參數(shù),double類型的scale,計(jì)算拉普拉斯值的時(shí)候可選的比例因子,有默認(rèn)值1。
  • 第六個(gè)參數(shù),double類型的delta,表示在結(jié)果存入目標(biāo)圖(第二個(gè)參數(shù)dst)之前可選的delta值,有默認(rèn)值0。
  • 第七個(gè)參數(shù), int類型的borderType,邊界模式,默認(rèn)值為BORDER_DEFAULT。這個(gè)參數(shù)可以在官方文檔中borderInterpolate()處得到更詳細(xì)的信息。


Laplacian( )函數(shù)其實(shí)主要是利用sobel算子的運(yùn)算。它通過(guò)加上sobel算子運(yùn)算出的圖像x方向和y方向上的導(dǎo)數(shù),來(lái)得到我們載入圖像的拉普拉斯變換結(jié)果。

其中,sobel算子(ksize>1)如下:


?

而當(dāng)ksize=1時(shí),Laplacian()函數(shù)采用以下3x3的孔徑:


?

?

?

?

4.3 調(diào)用Laplacian函數(shù)的實(shí)例代碼

?

?

讓我們看一看調(diào)用實(shí)例:

?

//-----------------------------------【頭文件包含部分】--------------------------------------- // 描述:包含程序所依賴的頭文件 //---------------------------------------------------------------------------------------------- #include <opencv2/opencv.hpp> #include<opencv2/highgui/highgui.hpp> #include<opencv2/imgproc/imgproc.hpp>//-----------------------------------【命名空間聲明部分】--------------------------------------- // 描述:包含程序所使用的命名空間 //----------------------------------------------------------------------------------------------- using namespace cv;//-----------------------------------【main( )函數(shù)】-------------------------------------------- // 描述:控制臺(tái)應(yīng)用程序的入口函數(shù),我們的程序從這里開(kāi)始 //----------------------------------------------------------------------------------------------- int main( ) {//【0】變量的定義Mat src,src_gray,dst, abs_dst;//【1】載入原始圖 src = imread("1.jpg"); //工程目錄下應(yīng)該有一張名為1.jpg的素材圖//【2】顯示原始圖 imshow("【原始圖】圖像Laplace變換", src); //【3】使用高斯濾波消除噪聲GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );//【4】轉(zhuǎn)換為灰度圖cvtColor( src, src_gray, CV_RGB2GRAY );//【5】使用Laplace函數(shù)Laplacian( src_gray, dst, CV_16S, 3, 1, 0, BORDER_DEFAULT );//【6】計(jì)算絕對(duì)值,并將結(jié)果轉(zhuǎn)換成8位convertScaleAbs( dst, abs_dst );//【7】顯示效果圖imshow( "【效果圖】圖像Laplace變換", abs_dst );waitKey(0); return 0; }

示例效果圖:

?

?

?

?

?










五、scharr濾波器篇



scharr一般我就直接稱它為濾波器,而不是算子。上文我們已經(jīng)講到,它在OpenCV中主要是配合Sobel算子的運(yùn)算而存在的,一個(gè)萬(wàn)年備胎。讓我們直接來(lái)看看函數(shù)講解吧。



?

5.1 OpenCV中Scharr函數(shù)詳解

?


使用Scharr濾波器運(yùn)算符計(jì)算x或y方向的圖像差分。其實(shí)它的參數(shù)變量和Sobel基本上是一樣的,除了沒(méi)有ksize核的大小。

?

C++: void Scharr( InputArray src, //源圖OutputArray dst, //目標(biāo)圖int ddepth,//圖像深度int dx,// x方向上的差分階數(shù)int dy,//y方向上的差分階數(shù)double scale=1,//縮放因子double delta=0,// delta值intborderType=BORDER_DEFAULT )// 邊界模式

  • 第一個(gè)參數(shù),InputArray 類型的src,為輸入圖像,填Mat類型即可。
  • 第二個(gè)參數(shù),OutputArray類型的dst,即目標(biāo)圖像,函數(shù)的輸出參數(shù),需要和源圖片有一樣的尺寸和類型。
  • 第三個(gè)參數(shù),int類型的ddepth,輸出圖像的深度,支持如下src.depth()和ddepth的組合:
    • 若src.depth() = CV_8U, 取ddepth =-1/CV_16S/CV_32F/CV_64F
    • 若src.depth() = CV_16U/CV_16S, 取ddepth =-1/CV_32F/CV_64F
    • 若src.depth() = CV_32F, 取ddepth =-1/CV_32F/CV_64F
    • 若src.depth() = CV_64F, 取ddepth = -1/CV_64F
  • 第四個(gè)參數(shù),int類型dx,x方向上的差分階數(shù)。
  • 第五個(gè)參數(shù),int類型dy,y方向上的差分階數(shù)。
  • 第六個(gè)參數(shù),double類型的scale,計(jì)算導(dǎo)數(shù)值時(shí)可選的縮放因子,默認(rèn)值是1,表示默認(rèn)情況下是沒(méi)有應(yīng)用縮放的。我們可以在文檔中查閱getDerivKernels的相關(guān)介紹,來(lái)得到這個(gè)參數(shù)的更多信息。
  • 第七個(gè)參數(shù),double類型的delta,表示在結(jié)果存入目標(biāo)圖(第二個(gè)參數(shù)dst)之前可選的delta值,有默認(rèn)值0。
  • 第八個(gè)參數(shù), int類型的borderType,我們的老朋友了(萬(wàn)年是最后一個(gè)參數(shù)),邊界模式,默認(rèn)值為BORDER_DEFAULT。這個(gè)參數(shù)可以在官方文檔中borderInterpolate處得到更詳細(xì)的信息。

?

不難理解,如下兩者是等價(jià)的:

Scharr(src, dst, ddepth, dx, dy, scale,delta, borderType);

Sobel(src, dst, ddepth, dx, dy, CV_SCHARR,scale, delta, borderType);


?

5.2 調(diào)用Scharr函數(shù)的實(shí)例代碼

?


//-----------------------------------【頭文件包含部分】--------------------------------------- // 描述:包含程序所依賴的頭文件 //---------------------------------------------------------------------------------------------- #include <opencv2/opencv.hpp> #include<opencv2/highgui/highgui.hpp> #include<opencv2/imgproc/imgproc.hpp>//-----------------------------------【命名空間聲明部分】--------------------------------------- // 描述:包含程序所使用的命名空間 //----------------------------------------------------------------------------------------------- using namespace cv; //-----------------------------------【main( )函數(shù)】-------------------------------------------- // 描述:控制臺(tái)應(yīng)用程序的入口函數(shù),我們的程序從這里開(kāi)始 //----------------------------------------------------------------------------------------------- int main( ) {//【0】創(chuàng)建 grad_x 和 grad_y 矩陣Mat grad_x, grad_y;Mat abs_grad_x, abs_grad_y,dst;//【1】載入原始圖 Mat src = imread("1.jpg"); //工程目錄下應(yīng)該有一張名為1.jpg的素材圖//【2】顯示原始圖 imshow("【原始圖】Scharr濾波器", src); //【3】求 X方向梯度Scharr( src, grad_x, CV_16S, 1, 0, 1, 0, BORDER_DEFAULT );convertScaleAbs( grad_x, abs_grad_x );imshow("【效果圖】 X方向Scharr", abs_grad_x); //【4】求Y方向梯度Scharr( src, grad_y, CV_16S, 0, 1, 1, 0, BORDER_DEFAULT );convertScaleAbs( grad_y, abs_grad_y );imshow("【效果圖】Y方向Scharr", abs_grad_y); //【5】合并梯度(近似)addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst );//【6】顯示效果圖imshow("【效果圖】合并梯度后Scharr", dst); waitKey(0); return 0; }


運(yùn)行效果圖:

?




?





?


六、綜合示例篇——在實(shí)戰(zhàn)中熟稔

?


?

依然是每篇文章都會(huì)配給大家的一個(gè)詳細(xì)注釋的博文配套示例程序,把這篇文章中介紹的知識(shí)點(diǎn)以代碼為載體,展現(xiàn)給大家。

這個(gè)示例程序中,分別演示了canny邊緣檢測(cè),sobel邊緣檢測(cè),scharr濾波器的使用,那么,上詳細(xì)注釋的代碼吧:

?

//-----------------------------------【程序說(shuō)明】---------------------------------------------- // 程序名稱::《【OpenCV入門(mén)教程之十二】OpenCV邊緣檢測(cè):Canny算子,Sobel算子,Laplace算子,Scharr濾波器合輯合輯》 博文配套源碼 // 開(kāi)發(fā)所用IDE版本:Visual Studio 2010 // 開(kāi)發(fā)所用OpenCV版本: 2.4.9 // 2014年5月11日 Create by 淺墨 // 淺墨的微博:@淺墨_毛星云 http://weibo.com/1723155442/profile?topnav=1&wvr=5&user=1 // 淺墨的知乎:http://www.zhihu.com/people/mao-xing-yun // 淺墨的豆瓣:http://www.douban.com/people/53426472/ //----------------------------------------------------------------------------------------------//-----------------------------------【頭文件包含部分】--------------------------------------- // 描述:包含程序所依賴的頭文件 //---------------------------------------------------------------------------------------------- #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp>//-----------------------------------【命名空間聲明部分】-------------------------------------- // 描述:包含程序所使用的命名空間 //----------------------------------------------------------------------------------------------- using namespace cv;//-----------------------------------【全局變量聲明部分】-------------------------------------- // 描述:全局變量聲明 //----------------------------------------------------------------------------------------------- //原圖,原圖的灰度版,目標(biāo)圖 Mat g_srcImage, g_srcGrayImage,g_dstImage;//Canny邊緣檢測(cè)相關(guān)變量 Mat g_cannyDetectedEdges; int g_cannyLowThreshold=1;//TrackBar位置參數(shù) //Sobel邊緣檢測(cè)相關(guān)變量 Mat g_sobelGradient_X, g_sobelGradient_Y; Mat g_sobelAbsGradient_X, g_sobelAbsGradient_Y; int g_sobelKernelSize=1;//TrackBar位置參數(shù) //Scharr濾波器相關(guān)變量 Mat g_scharrGradient_X, g_scharrGradient_Y; Mat g_scharrAbsGradient_X, g_scharrAbsGradient_Y;//-----------------------------------【全局函數(shù)聲明部分】-------------------------------------- // 描述:全局函數(shù)聲明 //----------------------------------------------------------------------------------------------- static void ShowHelpText( ); static void on_Canny(int, void*);//Canny邊緣檢測(cè)窗口滾動(dòng)條的回調(diào)函數(shù) static void on_Sobel(int, void*);//Sobel邊緣檢測(cè)窗口滾動(dòng)條的回調(diào)函數(shù) void Scharr( );//封裝了Scharr邊緣檢測(cè)相關(guān)代碼的函數(shù)//-----------------------------------【main( )函數(shù)】-------------------------------------------- // 描述:控制臺(tái)應(yīng)用程序的入口函數(shù),我們的程序從這里開(kāi)始 //----------------------------------------------------------------------------------------------- int main( int argc, char** argv ) {//改變console字體顏色system("color 2F"); //顯示歡迎語(yǔ)ShowHelpText();//載入原圖g_srcImage = imread("1.jpg");if( !g_srcImage.data ) { printf("Oh,no,讀取srcImage錯(cuò)誤~! \n"); return false; }//顯示原始圖namedWindow("【原始圖】");imshow("【原始圖】", g_srcImage);// 創(chuàng)建與src同類型和大小的矩陣(dst)g_dstImage.create( g_srcImage.size(), g_srcImage.type() );// 將原圖像轉(zhuǎn)換為灰度圖像cvtColor( g_srcImage, g_srcGrayImage, CV_BGR2GRAY );// 創(chuàng)建顯示窗口namedWindow( "【效果圖】Canny邊緣檢測(cè)", CV_WINDOW_AUTOSIZE );namedWindow( "【效果圖】Sobel邊緣檢測(cè)", CV_WINDOW_AUTOSIZE );// 創(chuàng)建trackbarcreateTrackbar( "參數(shù)值:", "【效果圖】Canny邊緣檢測(cè)", &g_cannyLowThreshold, 120, on_Canny );createTrackbar( "參數(shù)值:", "【效果圖】Sobel邊緣檢測(cè)", &g_sobelKernelSize, 3, on_Sobel );// 調(diào)用回調(diào)函數(shù)on_Canny(0, 0);on_Sobel(0, 0);//調(diào)用封裝了Scharr邊緣檢測(cè)代碼的函數(shù)Scharr( );//輪詢獲取按鍵信息,若按下Q,程序退出while((char(waitKey(1)) != 'q')) {}return 0; }//-----------------------------------【ShowHelpText( )函數(shù)】---------------------------------- // 描述:輸出一些幫助信息 //---------------------------------------------------------------------------------------------- static void ShowHelpText() {//輸出一些幫助信息printf( "\n\n\t嗯。運(yùn)行成功,請(qǐng)調(diào)整滾動(dòng)條觀察圖像效果~\n\n""\t按下“q”鍵時(shí),程序退出~!\n""\n\n\t\t\t\t by淺墨" ); }//-----------------------------------【on_Canny( )函數(shù)】---------------------------------- // 描述:Canny邊緣檢測(cè)窗口滾動(dòng)條的回調(diào)函數(shù) //----------------------------------------------------------------------------------------------- void on_Canny(int, void*) {// 先使用 3x3內(nèi)核來(lái)降噪blur( g_srcGrayImage, g_cannyDetectedEdges, Size(3,3) );// 運(yùn)行我們的Canny算子Canny( g_cannyDetectedEdges, g_cannyDetectedEdges, g_cannyLowThreshold, g_cannyLowThreshold*3, 3 );//先將g_dstImage內(nèi)的所有元素設(shè)置為0 g_dstImage = Scalar::all(0);//使用Canny算子輸出的邊緣圖g_cannyDetectedEdges作為掩碼,來(lái)將原圖g_srcImage拷到目標(biāo)圖g_dstImage中g(shù)_srcImage.copyTo( g_dstImage, g_cannyDetectedEdges);//顯示效果圖imshow( "【效果圖】Canny邊緣檢測(cè)", g_dstImage ); }//-----------------------------------【on_Sobel( )函數(shù)】---------------------------------- // 描述:Sobel邊緣檢測(cè)窗口滾動(dòng)條的回調(diào)函數(shù) //----------------------------------------------------------------------------------------- void on_Sobel(int, void*) {// 求 X方向梯度Sobel( g_srcImage, g_sobelGradient_X, CV_16S, 1, 0, (2*g_sobelKernelSize+1), 1, 1, BORDER_DEFAULT );convertScaleAbs( g_sobelGradient_X, g_sobelAbsGradient_X );//計(jì)算絕對(duì)值,并將結(jié)果轉(zhuǎn)換成8位// 求Y方向梯度Sobel( g_srcImage, g_sobelGradient_Y, CV_16S, 0, 1, (2*g_sobelKernelSize+1), 1, 1, BORDER_DEFAULT );convertScaleAbs( g_sobelGradient_Y, g_sobelAbsGradient_Y );//計(jì)算絕對(duì)值,并將結(jié)果轉(zhuǎn)換成8位// 合并梯度addWeighted( g_sobelAbsGradient_X, 0.5, g_sobelAbsGradient_Y, 0.5, 0, g_dstImage );//顯示效果圖imshow("【效果圖】Sobel邊緣檢測(cè)", g_dstImage); }//-----------------------------------【Scharr( )函數(shù)】---------------------------------- // 描述:封裝了Scharr邊緣檢測(cè)相關(guān)代碼的函數(shù) //----------------------------------------------------------------------------------------- void Scharr( ) {// 求 X方向梯度Scharr( g_srcImage, g_scharrGradient_X, CV_16S, 1, 0, 1, 0, BORDER_DEFAULT );convertScaleAbs( g_scharrGradient_X, g_scharrAbsGradient_X );//計(jì)算絕對(duì)值,并將結(jié)果轉(zhuǎn)換成8位// 求Y方向梯度Scharr( g_srcImage, g_scharrGradient_Y, CV_16S, 0, 1, 1, 0, BORDER_DEFAULT );convertScaleAbs( g_scharrGradient_Y, g_scharrAbsGradient_Y );//計(jì)算絕對(duì)值,并將結(jié)果轉(zhuǎn)換成8位// 合并梯度addWeighted( g_scharrAbsGradient_X, 0.5, g_scharrAbsGradient_Y, 0.5, 0, g_dstImage );//顯示效果圖imshow("【效果圖】Scharr濾波器", g_dstImage); }


放出一些運(yùn)行效果圖:

?

canny邊緣檢測(cè)效果圖:



?


Sobel邊緣檢測(cè):



Scharr濾波器:



好的,就放出這些效果圖吧,具體更多的運(yùn)行效果大家就自己下載示例程序回去玩~

?

本篇文章的配套源代碼請(qǐng)點(diǎn)擊這里下載:

?

【淺墨OpenCV入門(mén)教程之十二】配套源代碼下載

?

?

OK,今天的內(nèi)容大概就是這些,我們下篇文章見(jiàn):)

?

?

?

總結(jié)

以上是生活随笔為你收集整理的【OpenCV入门教程之十二】OpenCV边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器合辑的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。