python電腦視覺2:映像邊緣檢測

來源:互聯網
上載者:User

標籤:


我是一名初學者,如果你發現文中有錯誤,請留言告訴我,謝謝

 

如果需要檢測到映像裡面的邊緣,首先我們需要知道邊緣處具有什麼特徵。

對於一幅灰階映像來說,邊緣兩邊的灰階值肯定不相同,這樣我們才能分辨出哪裡是邊緣,哪裡不是。

因此,如果我們需要檢測一個灰階映像的邊緣,我們需要找出哪裡的灰階變化最大。顯然,灰階變化越大,對比越強,邊緣就越明顯。

那麼問題來了,我們怎麼知道哪裡灰階變化大,哪裡灰階變化小呢?

 導數,梯度,邊緣資訊 

在數學中,與變動率有關的就是導數。

如果灰階映像的像素是連續的(實際不是),那麼我們可以分別原映像G對x方向和y方向求導數

獲得x方向的導數映像Gx和y方向的導數映像Gy。Gx和Gy分別隱含了x和y方向的灰階變化資訊,也就隱含了邊緣資訊。

如果要在同一映像上包含兩個方向的邊緣資訊,我們可以用到梯度。(梯度是一個向量)

原映像的梯度向量Gxy為(Gx,Gy),梯度向量的大小和方向可以用下面兩個式子計算

角度值好像需要根據向量所在象限不同適當+pi或者-pi。

梯度向量大小就包含了x方向和y方向的邊緣資訊。

 

 映像導數 

實際上,映像矩陣是離散的。

連續函數求變動率用的是導數,而離散函數求變動率用的是差分。

差分的概念很容易理解,就是用相鄰兩個數的差來表示變動率。

下面公式是向後差分

x方向的差分:Gx(n,y) = G(n,y)-G(n-1,y)

y方向的差分:Gy(x,n) = G(x,n)-G(x,n-1)

 實際計算映像導數時,我們是通過原映像和一個運算元進行卷積來完成的(這種方法是求映像的近似導數)。

最簡單的求映像導數的運算元是 Prewitt運算元 :

x方向的Prewitt運算元為

y方向的Prewitt運算元為

---------------------------------------------

原映像和一個運算元進行卷積的大概過程如下

如果映像矩陣中一塊地區為

那麼x5處的x方向的導數是,將x方向運算元的中心和x5重合,然後對應元素相乘再求和,即

x5處的x方嚮導數為x3+x6+x9-x1-x4-x7

對矩陣中所有元素進行上述計算,就是卷積的過程。

--------------------------------------------

因此,利用原映像和x方向Prewitt運算元進行卷積就可以得到映像的x方嚮導數矩陣Gx,

利用原映像和y方向Prewitt運算元進行卷積就可以得到映像的y方嚮導數矩陣Gy。

利用公式

就可以得到映像的梯度矩陣Gxy,這個矩陣包含映像x方向和y方向的邊緣資訊。

 

 Python實現卷積及Prewitt運算元的邊緣檢測 

 首先我們把映像卷積函數封裝在一個名為imconv的函數中

import numpy as npfrom PIL import Imagedef imconv(image_array,suanzi):    ‘‘‘計算卷積        參數        image_array 原灰階映像矩陣        suanzi      運算元        返回        原映像與運算元卷積後的結果矩陣    ‘‘‘    image = image_array.copy()     # 原映像矩陣的深拷貝        dim1,dim2 = image.shape    # 對每個元素與運算元進行乘積再求和(忽略最外圈邊框像素)    for i in range(1,dim1-1):        for j in range(1,dim2-1):            image[i,j] = (image_array[(i-1):(i+2),(j-1):(j+2)]*suanzi).sum()        # 由於卷積後灰階值不一定在0-255之間,統一化成0-255    image = image*(255.0/image.max())    # 返回結果矩陣    return image

 

然後我們利用Prewitt運算元計算x方嚮導數矩陣Gx,y方嚮導數矩陣Gy,和梯度矩陣Gxy。

import numpy as npimport matplotlib.pyplot as plt# x方向的Prewitt運算元suanzi_x = np.array([[-1, 0, 1],                    [ -1, 0, 1],                    [ -1, 0, 1]])# y方向的Prewitt運算元suanzi_y = np.array([[-1,-1,-1],                     [ 0, 0, 0],                     [ 1, 1, 1]])# 開啟映像並轉化成灰階映像image = Image.open("pika.jpg").convert("L")# 轉化成映像矩陣image_array = np.array(image)# 得到x方向矩陣image_x = imconv(image_array,suanzi_x)# 得到y方向矩陣image_y = imconv(image_array,suanzi_y)# 得到梯度矩陣image_xy = np.sqrt(image_x**2+image_y**2)# 梯度矩陣統一到0-255image_xy = (255.0/image_xy.max())*image_xy# 繪出映像plt.subplot(2,2,1)plt.imshow(image_array,cmap=cm.gray)plt.axis("off")plt.subplot(2,2,2)plt.imshow(image_x,cmap=cm.gray)plt.axis("off")plt.subplot(2,2,3)plt.imshow(image_y,cmap=cm.gray)plt.axis("off")plt.subplot(2,2,4)plt.imshow(image_xy,cmap=cm.gray)plt.axis("off")plt.show()

 

 Prewitt運算元 的結果如所示

上方:左圖為原映像,右圖為x方嚮導數映像

下方:左圖為y方嚮導數映像,右圖為梯度映像

可以看出,Prewitt運算元雖然能檢測出映像邊緣,但是檢測結果較為粗糙,還帶有大量的雜訊。

 

 近似導數的Sobel運算元 

Sobel運算元與Prewitt比較類似,但是它比Prewitt運算元要好一些。

x方向的Sobel運算元為

y方向的Sobel運算元為

python代碼只需要將上面代碼中的Prewitt運算元改成Sobel運算元即可。

# x方向的Sobel運算元suanzi_x = np.array([[-1, 0, 1],                    [ -2, 0, 2],                    [ -1, 0, 1]])# y方向的Sobel運算元suanzi_y = np.array([[-1,-2,-1],                     [ 0, 0, 0],                     [ 1, 2, 1]])

 Sobel運算元 的結果如所示

上方:左圖為原映像,右圖為x方嚮導數映像

下方:左圖為y方嚮導數映像,右圖為梯度映像

看出,比較Prewitt運算元和Sobel運算元,Sobel運算元稍微減少了一點雜訊,但雜訊還是比較多的。

未完,待續

 

參考列表

1.《python電腦視覺編程》 

python電腦視覺2:映像邊緣檢測

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.