視覺影象:Sobel運算元及其實現

來源:酷知科普網 4.68K

緒:
Sobel運算元是一種常用的邊緣檢測運算元,是一階的梯度演算法;
對噪聲具有平滑作用,提供較為精確的邊緣方向資訊,邊緣定位精度不夠高;
當對精度要求不是很高時,是一種較為常用的邊緣檢測方法。
常見的應用和物理意義是邊緣檢測。

視覺影象:Sobel運算元及其實現

操作方法

(01)思想:運算元使用兩個3*3的矩陣運算元分別和原始圖片作卷積,分別得到橫向Gx和縱向Gy的梯度值,如果梯度值大於某一個閾值,則認為該點為邊緣點;

視覺影象:Sobel運算元及其實現 第2張

(02)矩陣轉換:事實上卷積矩陣也可以由兩個一維矩陣卷積而成,在opencv原始碼中就是用兩個一維矩陣卷積生成一個卷積矩陣:

視覺影象:Sobel運算元及其實現 第3張

(03)梯度值:影象的梯度值由以下公式計算:影象近似梯度值如下:對於原始影象,P5的梯度值為:

視覺影象:Sobel運算元及其實現 第4張

(04)OpenCV2410,sobel運算元函式原型: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 )函式引數解釋:InputArray src:輸入的原影象,Mat型別OutputArray dst:輸出的邊緣檢測結果影象,Mat型別,大小與原影象相同。int ddepth:輸出影象的深度,針對不同的輸入影象,輸出目標影象有不同的深度,具體組合如下:- 若h() = CV_8U, 取ddepth =-1/CV_16S/CV_32F/CV_64F- 若h() = CV_16U/CV_16S, 取ddepth =-1/CV_32F/CV_64F- 若h() = CV_32F, 取ddepth =-1/CV_32F/CV_64F- 若h() = CV_64F, 取ddepth = -1/CV_64F注:ddepth =-1時,代表輸出影象與輸入影象相同的深度。int dx:int型別dx,x 方向上的差分階數,1或0int dy:int型別dy,y 方向上的差分階數,1或0其中,dx=1,dy=0,表示計算X方向的導數,檢測出的是垂直方向上的邊緣;dx=0,dy=1,表示計算Y方向的導數,檢測出的是水平方向上的邊緣。int ksize:為進行邊緣檢測時的模板大小為ksize*ksize,取值為1、3、5和7,其中預設值為3。特殊情況:ksize=1時,採用的模板為3*1或1*3。當ksize=3時,Sobel核心可能產生比較明顯的誤差;double scale:預設1。double delta:預設0。int borderType:預設值為BORDER_DEFAULT。

(05)Sobel呼叫格式:sobel演算法程式碼實現過程為:// 求 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 );convertScaleAbs( grad_x, abs_grad_x );convertScaleAbs( grad_y, abs_grad_y );addWeighted( dst_x, 0.5, dst_y, 0.5, 0, dst); //一種近似的估計

視覺影象:Sobel運算元及其實現 第5張

(06)Sobel運算元實現:#include <opencv2>using namespace std;using namespace cv;int main( int argc, char** argv ){Mat in_img = imread("raw.jpg",0);if (!in_){return -1;}Mat out_img_dx = Mat::zeros(in_(),CV_16SC1);Mat out_img_dy = Mat::zeros(in_(),CV_16SC1);Mat out_img_dxy = Mat::zeros(in_(),CV_16SC1);GaussianBlur(in_img,in_img,Size(3,3),0);unsigned char* p_data = (unsigned char*)in_;unsigned char* p_data_dx = (unsigned char*)out_img_;unsigned char* p_data_dy = (unsigned char*)out_img_;int step = in_;for (int i=1;i<in_-1;i++){for (int j=1;j<in_-1;j++)}addWeighted(out_img_dx,0.5,out_img_dy,0.5,0,out_img_dxy);Mat img_dx,img_dy,img_dxy;convertScaleAbs(out_img_dx,img_dx);convertScaleAbs(out_img_dy,img_dy);convertScaleAbs(out_img_dxy,img_dxy);imshow("raw img",in_img);imshow("x direction",img_dx);imshow("y direction",img_dy);imshow("xy direction",img_dxy);Mat sobel_img;Sobel(in_img,sobel_img,CV_8UC1,1,1,3);imshow("opencv sobel",sobel_img);waitKey( 0 );return 0;}

視覺影象:Sobel運算元及其實現 第6張

(07)OpenCV內原始碼:static void getSobelKernels( OutputArray _kx, OutputArray _ky,  int dx, int dy, int _ksize, bool   normalize, int ktype ){int i, j, ksizeX = _ksize, ksizeY = _ksize;if( ksizeX == 1 && dx > 0 )ksizeX = 3;if( ksizeY == 1 && dy > 0 )ksizeY = 3;CV_Assert( ktype == CV_32F || ktype == CV_64F );_te(ksizeX, 1, ktype, -1, true);_te(ksizeY, 1, ktype, -1, true);Mat kx = _at();Mat ky = _at();if( _ksize % 2 == 0 || _ksize > 31 )CV_Error( CV_StsOutOfRange, "The kernel size must be odd and not larger than 31" );std::vector<int> kerI(std::max(ksizeX, ksizeY) + 1);CV_Assert( dx >= 0 && dy >= 0 && dx+dy > 0 );for( int k = 0; k < 2; k++ ){Mat* kernel = k == 0 ? &kx : &ky;int order = k == 0 ? dx : dy;int ksize = k == 0 ? ksizeX : ksizeY;CV_Assert( ksize > order );if( ksize == 1 )kerI[0] = 1;else if( ksize == 3 ){if( order == 0 )kerI[0] = 1, kerI[1] = 2, kerI[2] = 1;else if( order == 1 )kerI[0] = -1, kerI[1] = 0, kerI[2] = 1;elsekerI[0] = 1, kerI[1] = -2, kerI[2] = 1;}else{int oldval, newval;kerI[0] = 1;for( i = 0; i < ksize; i++ )kerI[i+1] = 0;for( i = 0; i < ksize - order - 1; i++ ){oldval = kerI[0];for( j = 1; j <= ksize; j++ ){newval = kerI[j]+kerI[j-1];kerI[j-1] = oldval;oldval = newval;}}for( i = 0; i < order; i++ ){oldval = -kerI[0];for( j = 1; j <= ksize; j++ ){newval = kerI[j-1] - kerI[j];kerI[j-1] = oldval;oldval = newval;}}}Mat temp(kernel->rows, kernel->cols, CV_32S, &kerI[0]);double scale = !normalize ? 1. : 1./(1 << (ksize-order-1));ertTo(*kernel, ktype, scale);}}

特別提示

Sobel運算元是一種常用的邊緣檢測運算元,是一階的梯度演算法;

注:核大小超過3的sobel運算元,都過兩個一維矩陣卷積實現;具體參考opencv手冊

熱門標籤