opencv sobel导数
- 如何使用OpenCV函數(shù)?Sobel?對(duì)圖像求導(dǎo)。
- 如何使用OpenCV函數(shù)?Scharr?更準(zhǔn)確地計(jì)算??核的導(dǎo)數(shù)。
原理
Note
?以下內(nèi)容來自于Bradski和Kaehler的大作:?Learning OpenCV?.
上面兩節(jié)我們已經(jīng)學(xué)習(xí)了卷積操作。一個(gè)最重要的卷積運(yùn)算就是導(dǎo)數(shù)的計(jì)算(或者近似計(jì)算).
為什么對(duì)圖像進(jìn)行求導(dǎo)是重要的呢? 假設(shè)我們需要檢測圖像中的?邊緣?,如下圖:
你可以看到在?邊緣?,相素值顯著的?改變?了。表示這一?改變?的一個(gè)方法是使用?導(dǎo)數(shù)?。 梯度值的大變預(yù)示著圖像中內(nèi)容的顯著變化。
用更加形象的圖像來解釋,假設(shè)我們有一張一維圖形。下圖中灰度值的”躍升”表示邊緣的存在:
使用一階微分求導(dǎo)我們可以更加清晰的看到邊緣”躍升”的存在(這里顯示為高峰值)
從上例中我們可以推論檢測邊緣可以通過定位梯度值大于鄰域的相素的方法找到(或者推廣到大于一個(gè)閥值).
更加詳細(xì)的解釋,請(qǐng)參考Bradski 和 Kaehler的?Learning OpenCV?。
Sobel算子
計(jì)算
假設(shè)被作用圖像為?:
在兩個(gè)方向求導(dǎo):
水平變化: 將??與一個(gè)奇數(shù)大小的內(nèi)核??進(jìn)行卷積。比如,當(dāng)內(nèi)核大小為3時(shí),??的計(jì)算結(jié)果為:
垂直變化: 將:math:I?與一個(gè)奇數(shù)大小的內(nèi)核??進(jìn)行卷積。比如,當(dāng)內(nèi)核大小為3時(shí),??的計(jì)算結(jié)果為:
在圖像的每一點(diǎn),結(jié)合以上兩個(gè)結(jié)果求出近似?梯度:
有時(shí)也用下面更簡單公式代替:
Note
當(dāng)內(nèi)核大小為??時(shí), 以上Sobel內(nèi)核可能產(chǎn)生比較明顯的誤差(畢竟,Sobel算子只是求取了導(dǎo)數(shù)的近似值)。 為解決這一問題,OpenCV提供了?Scharr?函數(shù),但該函數(shù)僅作用于大小為3的內(nèi)核。該函數(shù)的運(yùn)算與Sobel函數(shù)一樣快,但結(jié)果卻更加精確,其內(nèi)核為:
關(guān)于(?Scharr?)的更多信息請(qǐng)參考OpenCV文檔。在下面的示例代碼中,你會(huì)發(fā)現(xiàn)在?Sobel?函數(shù)調(diào)用的上面有被注釋掉的?Scharr?函數(shù)調(diào)用。 反注釋Scharr調(diào)用 (當(dāng)然也要相應(yīng)的注釋掉Sobel調(diào)用),看看該函數(shù)是如何工作的。
源碼
- 使用?Sobel算子?產(chǎn)生的輸出圖像上,檢測到的亮起的?邊緣?相素散布在更暗的背景中。
解釋
首先申明變量:
Mat src, src_gray; Mat grad; char* window_name = "Sobel Demo - Simple Edge Detector"; int scale = 1; int delta = 0; int ddepth = CV_16S;裝載原圖像?src:
src = imread( argv[1] );if( !src.data ) { return -1; }第一步對(duì)原圖像使用?GaussianBlur?降噪 ( 內(nèi)核大小 = 3 )
GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );將降噪后的圖像轉(zhuǎn)換為灰度圖:
cvtColor( src, src_gray, CV_RGB2GRAY );第二步,在?x?和?y?方向分別”求導(dǎo)“。 為此,我們使用函數(shù)?Sobel?:
Mat grad_x, grad_y; Mat abs_grad_x, abs_grad_y;/// 求 X方向梯度 Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT ); /// 求 Y方向梯度 Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );該函數(shù)接受了以下參數(shù):
- src_gray: 在本例中為輸入圖像,元素類型?CV_8U
- grad_x/grad_y: 輸出圖像.
- ddepth: 輸出圖像的深度,設(shè)定為?CV_16S?避免外溢。
- x_order:?x?方向求導(dǎo)的階數(shù)。
- y_order:?y?方向求導(dǎo)的階數(shù)。
- scale,?delta?和?BORDER_DEFAULT: 使用默認(rèn)值
注意為了在?x?方向求導(dǎo)我們使用:??,?. 采用同樣方法在?y?方向求導(dǎo)。
將中間結(jié)果轉(zhuǎn)換到?CV_8U:
convertScaleAbs( grad_x, abs_grad_x ); convertScaleAbs( grad_y, abs_grad_y );將兩個(gè)方向的梯度相加來求取近似?梯度?(注意這里沒有準(zhǔn)確的計(jì)算,但是對(duì)我們來講已經(jīng)足夠了)。
addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad );最后,顯示結(jié)果:
imshow( window_name, grad );結(jié)果
這里是將Sobel算子作用于?lena.jpg?的結(jié)果:
總結(jié)
以上是生活随笔為你收集整理的opencv sobel导数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: opencv图像边界的填充
- 下一篇: OpenCV函数 Laplacian 算