Sobel算子

1、Sobel邊緣檢測算子html

l 在討論邊緣算子以前,首先給出一些術語的定義:算法

l (1)邊緣:灰度或結構等信息的突變處,邊緣是一個區域的結束,也是另外一個區域的開始,利用該特徵能夠分割圖像。函數

l (2)邊緣點:圖像中具備座標[x,y],且處在強度顯著變化的位置上的點。ui

l (3)邊緣段:對應於邊緣點座標[x,y]及其方位 ,邊緣的方位多是梯度角。url

幻燈片3spa

2、Sobel算子的基本原理視頻

l Sobel算子是一階導數的邊緣檢測算子,在算法實現過程當中,經過3×3模板做爲核與圖像中的每一個像素點作卷積和運算,而後選取合適的閾值以提取邊緣。htm

l 採用3×3鄰域能夠避免在像素之間內插點上計算梯度。Sobel算子也是一種梯度幅值,即:blog

l 其中的偏導數Sx 和Sy可用卷積模板來實現。內存


幻燈片4

Sx=(Z1+2Z2+Z3)-(Z7+2Z8+Z9)

Sy=(Z1+2Z4+Z7)-(Z3+2Z6+Z9)


幻燈片5

l Sobel算子算法的優勢是計算簡單,速度快。可是因爲只採用了2個方向的模板,只能檢測水平和垂直方向的邊緣,所以這種算法對於紋理較爲複雜的圖像,其邊緣檢測效果就不是很理想。該算法認爲:凡灰度新值大於或等於閾值的像素點時都是邊緣點。這種判斷欠合理,會形成邊緣點的誤判,由於許多噪聲點的灰度值也很大

幻燈片6

3、模板方向的改變

幻燈片7


幻燈片8

4、Sobel算子圖像邊緣檢測的MATLB程序實現

l >> f=imread('peppers.png');

l >> f=rgb2gray(f);

l >> f=im2double(f);

l >> figure,imshow(f),title('原始圖像');

l >> [SFST Threshold] =edge(f,'sobel','horizontal');

l >> figure,imshow(SFST),title(' 水平圖像邊緣檢測');

l >> [VSFAT Threshold]=edge(f,'sobel','vertical');

l >> figure,imshow(VSFAT),title('垂直圖像邊緣檢測');

l >> s45=[-2 -1 0;-1 0 1;0 1 2];

l >> SFST45=imfilter(f,s45,'replicate');

l >> SFST45=SFST45>=Threshold;

l >> figure,imshow(SFST45),title('45度角圖像邊緣檢測');

l >> s135=[0 -1 -2;1 0 -1;2 1 0];

l >> SFST135=imfilter(f,s135,'replicate');

l >> SFST135=SFST135>=Threshold;

l >> figure,imshow(SFST135),title('135度角圖像邊緣檢測');

l >>

幻燈片9

幻燈片10



幻燈片11


幻燈片12

幻燈片13

 

 因爲項目裏要用到邊緣檢測,因此今天研究了一下最簡單的梯度的方法。

首先,咱們來開一下計算機是如何檢測邊緣的。以灰度圖像爲例,它的理論基礎是這樣的,若是出現一個邊緣,那麼圖像的灰度就會有必定的變化,爲了方便假設由黑漸變爲白表明一個邊界,那麼對其灰度分析,在邊緣的灰度函數就是一個一次函數y=kx,對其求一階導數就是其斜率k,就是說邊緣的一階導數是一個常數,而因爲非邊緣的一階導數爲零,這樣經過求一階導數就能初步判斷圖像的邊緣了。一般是X方向和Y方向的導數,也就是梯度。理論上計算機就是經過這種方式來得到圖像的邊緣。

可是,具體應用到圖像中你會發現這個導數是求不了的,由於沒一個準確的函數讓你去求導,並且計算機在求解析解要比求數值解麻煩得多,因此就想到了一種替代的方式來求導數。就是用一個3×3的窗口來對圖像進行近似求導。拿對X方向求導爲例,某一點的導數爲第三列的元素之和減去第一列元素之和,這樣就求得了某一點的近似導數。其實也很好理解爲何它就近似表明導數,導數就表明一個變化率,從第一列變爲第三列,灰度值相減,固然就是一個變化率了。這就是所謂的Prewitt算子。這樣近似X方向導數就求出來了。Y方向導數與X方向導數求法類似,只不過是用第三行元素之和減去第一行元素之和。X方向和Y方向導數有了,那麼梯度也就出來了。這樣就能夠找出一幅圖中的邊緣了。

還有一個問題,因爲求的是3×3中心點的導數,因此給第二列加了一個權重,它的權重爲2,第一列和第三列的權重爲1,好了,這就是Sobel算子了。相比Prewitt算子,Sobel的抗噪能力更強。如圖所示:Sobel算子及cvSobel這樣,中心點的Y方向導數就求出來了。

舉個例子吧。Sobel算子及cvSobel,X點以Sobel方式求導數ΔX=1×50+2×30+1×50-(1×50+2×30+1×50)=0。這樣能夠看出這個點不是邊界。

好了,瞭解了基本理論以後,咱們看看OpenCv下的Sobel函數吧,void cvSobel( const CvArr* src, CvArr* dst, int xorder, int yorder, int aperture_size=3 );src:輸入圖像;dst:輸出圖像;xorder:x 方向上的差分階數;yorder:y 方向上的差分階數;aperture_size 擴展 Sobel 核的大小(既窗口階數),必須是 1(注意這是一個3×1或1×3向量而不是一個方陣), 3, 5 或 7。

下面編寫一個Sobel邊緣檢測的程序吧,平臺是VS08,創建Win32控制檯應用程序。

#include <cv.h>

#include <highgui.h>

void main()

{

IplImage *frame,*gray,*sobel;

frame=cvLoadImage("lena.jpg");//加載圖像

gray=cvCreateImage(cvGetSize(frame),frame->depth,1);//分配圖像空間

sobel=cvCreateImage(cvGetSize(frame),frame->depth,1);

cvNamedWindow("frame");

cvNamedWindow("gray");

cvNamedWindow("sobel");

cvCvtColor(frame,gray,CV_BGR2GRAY);//轉爲灰度

cvSobel(gray,sobel,1,0,3);

cvShowImage("frame",frame);//顯示圖像

cvShowImage("gray",gray);

cvShowImage("sobel",sobel);

cvWaitKey(0);//等待

cvReleaseImage(&frame);//釋放空間(對視頻處理很重要,不釋放會形成內存泄露)

cvReleaseImage(&gray);

cvReleaseImage(&sobel);

cvDestroyWindow("frame");

cvDestroyWindow("gray");

cvDestroyWindow("sobel");

}

運行,你會發現出錯,仔細看看沒有問題啊。其實,這裏是問題的,由於以Sobel方式求完導數後會有負值,還有會大於255的值而你建的Sobel的圖像是 IPL_DEPTH_8U,也就是8位無符號數,因此Sobel創建的圖像位數不夠,要16位有符號的,也就是 IPL_DEPTH_16S。把創建圖像這句改成

sobel=cvCreateImage(cvGetSize(frame),IPL_DEPTH_16S,1);運行,發現不報錯了,可是Sobel圖像顯示不出來,這是什麼緣由呢?原來圖像顯示是以8位無符號顯示的,如今是16位有符號,固然顯示會出問題了。因此還要將Sobel轉爲8位無符號。OpenCv裏提供了一個函數,就是cvConvertScaleAbs( const CvArr* src, CvArr* dst, double scale=1, double shift=0 );src:源圖像;dst:目標圖像;scale:轉化前乘的係數;shift轉化前加的係數。這樣新建一個無符號圖像再轉換就能夠實現了。

IplImage *sobel8u=cvCreateImage(cvGetSize(sobel),IPL_DEPTH_8U,1);

再在顯示圖像前加上cvConvertScaleAbs(sobel,sobel8u,1,0);這樣就能夠看到cvSobel的效果了。能夠看X方向或Y方向求導是什麼效果。

爲了方便你們,我把改好後的程序也放上來了。

#include <cv.h>

#include <highgui.h>

void main()

{

IplImage *frame,*gray,*sobel;

frame=cvLoadImage("e:/p1.jpg");//加載圖像

gray=cvCreateImage(cvGetSize(frame),frame->depth,1);//分配圖像空間

sobel=cvCreateImage(cvGetSize(frame),IPL_DEPTH_16S,1);

cvNamedWindow("frame");

cvNamedWindow("gray");

cvNamedWindow("sobel");

cvCvtColor(frame,gray,CV_BGR2GRAY);//轉爲灰度

cvSobel(gray,sobel,1,0,3);

IplImage *sobel8u=cvCreateImage(cvGetSize(sobel),IPL_DEPTH_8U,1);

cvConvertScaleAbs(sobel,sobel8u,1,0);

cvShowImage("frame",frame);//顯示圖像

cvShowImage("gray",gray);

cvShowImage("sobel",sobel8u);

cvWaitKey(0);//等待

cvReleaseImage(&frame);//釋放空間(對視頻處理很重要,不釋放會形成內存泄露)

cvReleaseImage(&gray);

cvReleaseImage(&sobel);

cvDestroyWindow("frame");

cvDestroyWindow("gray");

cvDestroyWindow("sobel");

}

相關文章
相關標籤/搜索