天天看點

OpenCV與圖像處理學習六——圖像形态學操作:腐蝕、膨脹、開、閉運算、形态學梯度、頂帽和黑帽四、圖像形态學操作

OpenCV與圖像處理學習六——圖像形态學操作:腐蝕、膨脹、開、閉運算、形态學梯度、頂帽和黑帽

  • 四、圖像形态學操作
    • 4.1 腐蝕和膨脹
      • 4.1.1 圖像腐蝕
      • 4.1.2 圖像膨脹
    • 4.2 開運算與閉運算
      • 4.2.1 開運算
      • 4.2.2 閉運算
    • 4.3 形态學梯度(Gradient)
    • 4.4頂帽和黑帽

有關圖像處理前三次的筆記:

OpenCV與圖像處理學習三——圖像基本操作(1)

OpenCV與圖像處理學習四——圖像基本操作(2)

OpenCV與圖像處理學習五——圖像基本操作(3)

這是有關圖像基本操作的最後一次筆記,有關圖像形态學操作。

四、圖像形态學操作

形态學,是圖像進行中應用最為廣泛的技術之一,主要用于從圖像中提取對表達和描繪區域形狀有意義的圖像分量,使後續的識别工作能夠抓住目标對象最為本質的形狀特征,如邊界和連通區域等。

下面會經常用到一個概念,這裡先進行說明:

結構元素:設有兩幅圖像B,X,若X是被處理的對象,而B是用來處理X的,則B稱為結構元素(structure element),又被形象地稱作刷子。結構元素通常都是一些比較小的圖像。

下面将介紹形态學的幾種常用操作:腐蝕、膨脹、開運算和閉運算等。

4.1 腐蝕和膨脹

圖像的膨脹(Dilation)和腐蝕(Erosion)是兩種基本的形态學運算,其中膨脹類似于“領域擴張”,将圖像中的白色部分進行擴張,其運作結果圖比原圖的白色區域更大;而腐蝕類似于“領域被蠶食”,将圖像中白色的部分進行縮減細化,其運作結果圖比原圖的白色區域更小。

4.1.1 圖像腐蝕

把結構元素B平移a後得到Ba,若Ba包含于X,我們記下這個a點,所有滿足上述條件的a點組成的集合稱作X被B腐蝕(Erosion)的結果。如下圖所示:

OpenCV與圖像處理學習六——圖像形态學操作:腐蝕、膨脹、開、閉運算、形态學梯度、頂帽和黑帽四、圖像形态學操作

其中X是被處理的對象,B是結構元素。對于任意一個在陰影部分的點a,Ba包含于X,是以X被B腐蝕的結果就是那個陰影部分。陰影部分在X的範圍之内,且比X小,就像X被剝掉了一層似的。

OpenCV與圖像處理學習六——圖像形态學操作:腐蝕、膨脹、開、閉運算、形态學梯度、頂帽和黑帽四、圖像形态學操作

腐蝕後的結果如下圖黑色部分所示:

OpenCV與圖像處理學習六——圖像形态學操作:腐蝕、膨脹、開、閉運算、形态學梯度、頂帽和黑帽四、圖像形态學操作

相較于原來的灰色部分,仿佛變瘦了。

OpenCV中的函數為:

參數為:

  1. src:輸入圖像,可以是灰階圖或彩色圖。
  2. kernel:腐蝕操作的結構元素,預設為一個3×3的簡單矩陣。
  3. anchor:錨點,預設為結構元素的中心。
  4. iterations:腐蝕次數,預設為1。

下面看個例子:

import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('./image/morphology.png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
kernel = np.ones((3, 3), np.uint8)
erosion = cv2.erode(img, kernel, iterations = 1)
plt.subplot(121), plt.imshow(img), plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(erosion), plt.title('erosion')
plt.xticks([]), plt.yticks([])
plt.show()
           

結果如下所示:

OpenCV與圖像處理學習六——圖像形态學操作:腐蝕、膨脹、開、閉運算、形态學梯度、頂帽和黑帽四、圖像形态學操作

若将結構元素的尺寸擴大到7,結果為:

OpenCV與圖像處理學習六——圖像形态學操作:腐蝕、膨脹、開、閉運算、形态學梯度、頂帽和黑帽四、圖像形态學操作

ps:在構造結構元素的時候,可以使用numpy,也可以使用OpenCV提供的函數

cv2.getStructuringElement()

函數:

參數:

  1. shape:結構元素内部的結構,有三種,分别是矩形、十字形和橢圓形:
    OpenCV與圖像處理學習六——圖像形态學操作:腐蝕、膨脹、開、閉運算、形态學梯度、頂帽和黑帽四、圖像形态學操作
  2. ksize:結構元素的尺寸。
  3. anchor:錨點位置,預設為中心位置。

看一下例子:

import numpy as np
import cv2

kernel = np.ones((5, 5), np.uint8)
print(kernel)
           
[[1 1 1 1 1]
 [1 1 1 1 1]
 [1 1 1 1 1]
 [1 1 1 1 1]
 [1 1 1 1 1]]
           
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (7,7))
print(kernel)
           
[[0 0 0 1 0 0 0]
 [0 0 0 1 0 0 0]
 [0 0 0 1 0 0 0]
 [1 1 1 1 1 1 1]
 [0 0 0 1 0 0 0]
 [0 0 0 1 0 0 0]
 [0 0 0 1 0 0 0]]
           
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7,7))
print(kernel)
           
[[0 0 0 1 0 0 0]
 [0 1 1 1 1 1 0]
 [1 1 1 1 1 1 1]
 [1 1 1 1 1 1 1]
 [1 1 1 1 1 1 1]
 [0 1 1 1 1 1 0]
 [0 0 0 1 0 0 0]]
           
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7,7))
print(kernel)
           
[[1 1 1 1 1 1 1]
 [1 1 1 1 1 1 1]
 [1 1 1 1 1 1 1]
 [1 1 1 1 1 1 1]
 [1 1 1 1 1 1 1]
 [1 1 1 1 1 1 1]
 [1 1 1 1 1 1 1]]
           

我們可以用非矩形的結構元素來進行腐蝕操作:

#!/usr/bin/env python3
import cv2

image = cv2.imread("./image/morphology.png")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imshow("Gray Image", gray)

kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 7))
eroded = cv2.erode(gray.copy(), kernel, 10)
# eroded = cv2.erode(gray.copy(), None, 10)

cv2.imshow("Eroded Image", eroded)
cv2.waitKey(0)
cv2.destroyAllWindows()
           
OpenCV與圖像處理學習六——圖像形态學操作:腐蝕、膨脹、開、閉運算、形态學梯度、頂帽和黑帽四、圖像形态學操作

也是可以達到一定效果的,但是比矩形的那種腐蝕程度低一些些,因為畢竟結構元素裡多了一些0。

4.1.2 圖像膨脹

膨脹(dilation)可以看做是腐蝕的對偶運算,其定義是:把結構元素B平移後得到Ba,若Ba與X有交集,我們記下這個a點。所有滿足上述條件的a點組成的集合稱作X被B膨脹後的結果,如下圖所示:

OpenCV與圖像處理學習六——圖像形态學操作:腐蝕、膨脹、開、閉運算、形态學梯度、頂帽和黑帽四、圖像形态學操作

其中X是被處理的對象,B是結構元素,對于任意一個在陰影部分的點a,Ba與X有交集,是以X被B膨脹後的結果就是那個陰影部分,陰影部分包括X所有範圍,就像是X膨脹了一圈似的。

OpenCV與圖像處理學習六——圖像形态學操作:腐蝕、膨脹、開、閉運算、形态學梯度、頂帽和黑帽四、圖像形态學操作

膨脹後的圖像,其中綠色是膨脹多出來的部分:

OpenCV與圖像處理學習六——圖像形态學操作:腐蝕、膨脹、開、閉運算、形态學梯度、頂帽和黑帽四、圖像形态學操作

在OpenCV中的函數為:

參數:

  1. src:輸入圖像,可以是灰階圖也可以是彩色圖。
  2. kernel:膨脹運算的結構元素,預設為一個3×3的簡單矩陣。
  3. anchor:同上。
  4. iterations:同上。

看個例子:

import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('./image/morphology.png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
#kernel = np.ones((3,),np.uint8)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7,7))

dilation = cv2.dilate(img,kernel,iterations = 1)
plt.subplot(121),plt.imshow(img),plt.title('origin')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(dilation),plt.title('dilation')
plt.xticks([]), plt.yticks([])
plt.show()
           

結果為:

OpenCV與圖像處理學習六——圖像形态學操作:腐蝕、膨脹、開、閉運算、形态學梯度、頂帽和黑帽四、圖像形态學操作

若将運算元素尺寸擴大一點,擴大為11:

OpenCV與圖像處理學習六——圖像形态學操作:腐蝕、膨脹、開、閉運算、形态學梯度、頂帽和黑帽四、圖像形态學操作

原本斷開的地方或小孔都被填上了。

4.2 開運算與閉運算

4.2.1 開運算

開運算 = 先腐蝕運算,再膨脹運算,看上去把細微連在一起的兩塊目标分開了,開運算的效果圖如下所示:

OpenCV與圖像處理學習六——圖像形态學操作:腐蝕、膨脹、開、閉運算、形态學梯度、頂帽和黑帽四、圖像形态學操作

開運算對一些細微的小點,小塊,細條等部分是可以消去的,因為先腐蝕消去它們,導緻它們消失了無法再通過膨脹變回來,而一些比較大的塊通過腐蝕操作隻是會變瘦一點,不會被完全抹去,是以可以通過膨脹運算變回來,那麼總的效果就是開運算去除了這些孤立的小點,細長的小條。

開運算總結:

  1. 開運算能夠去除孤立的小點,毛刺和小條,而總的位置和形狀不變。
  2. 開運算是一個基于幾何運算的濾波器。
  3. 結構元素大小的不同将導緻濾波效果的不同。
  4. 不同的結構元素的選擇導緻了不同的分割,即提取出不同的特征。

開運算和閉運算都用如下函數來表示,這個函數是OpenCV中圖像形态學變化的通用函數:

參數如下所示:

  1. src:輸入圖像,灰階圖或彩色圖均可。
  2. op:形态學操作的類型,包括腐蝕、運算、開運算以及後面要提及的閉運算、形态學梯度、頂帽、黑帽等類型。
    OpenCV與圖像處理學習六——圖像形态學操作:腐蝕、膨脹、開、閉運算、形态學梯度、頂帽和黑帽四、圖像形态學操作
  3. kernel:結構元素,可以使用

    cv2.getStructuringElement

    函數來定義。
  4. anchor:錨點位置,一般都用中心位置。
  5. iterations:腐蝕或膨脹的次數。

下面看個例子:

import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('./image/open.png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
#kernel = np.ones((5,5),np.uint8)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
plt.subplot(121), plt.imshow(img), plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(opening), plt.title('opening')
plt.xticks([]), plt.yticks([])
plt.show()
           

結果如下所示:

OpenCV與圖像處理學習六——圖像形态學操作:腐蝕、膨脹、開、閉運算、形态學梯度、頂帽和黑帽四、圖像形态學操作

一些細小的點被去除了很多,但是開運算的結構元素的尺寸很重要,太小可能去除效果不好,太大可能會得到不想要的結果,如将3改為9,結果将變為:

OpenCV與圖像處理學習六——圖像形态學操作:腐蝕、膨脹、開、閉運算、形态學梯度、頂帽和黑帽四、圖像形态學操作

是以調節這個參數還是很關鍵的。

4.2.2 閉運算

閉運算 = 先膨脹運算,再腐蝕運算,看上去将兩個細微連接配接的圖塊封閉在一起,閉運算的效果圖如下圖所示:

OpenCV與圖像處理學習六——圖像形态學操作:腐蝕、膨脹、開、閉運算、形态學梯度、頂帽和黑帽四、圖像形态學操作

閉運算總結:

  1. 閉運算能夠填平小孔,彌合小縫隙,而總的位置和形狀不變。
  2. 閉運算是通過填充圖像的凹角來濾波圖像的。
  3. 結構元素大小的不同将導緻濾波效果的不同。
  4. 不同結構元素的選擇導緻了不同的分割。

看個例子:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
img = cv.imread('./image/close.png')
img = cv.cvtColor(img,cv.COLOR_BGR2RGB)
# kernel = np.ones((5,5),np.uint8)
kernel = np.ones((7, 7), np.uint8)
closing = cv.morphologyEx(img, cv.MORPH_CLOSE, kernel)
plt.subplot(121), plt.imshow(img), plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(closing), plt.title('closing')
plt.xticks([]), plt.yticks([])
plt.show()
           

結果如下所示:

OpenCV與圖像處理學習六——圖像形态學操作:腐蝕、膨脹、開、閉運算、形态學梯度、頂帽和黑帽四、圖像形态學操作

一些小孔被填滿了。若把尺寸從7改為21,結果為:

OpenCV與圖像處理學習六——圖像形态學操作:腐蝕、膨脹、開、閉運算、形态學梯度、頂帽和黑帽四、圖像形态學操作

就有點過了,把不需要連接配接和填補的地方也給連接配接、填補了,是以要合理選擇參數。

4.3 形态學梯度(Gradient)

  1. 基礎梯度:基礎梯度是用膨脹後的圖像減去腐蝕後的圖像得到的內插補點圖像,也是OpenCV中支援的計算形态學梯度的方法,而此方法得到梯度又稱為基本梯度。
  2. 内部梯度:是用原圖減去腐蝕之後的圖像得到的內插補點圖像。
  3. 外部梯度:圖形膨脹後再減去原來圖像得到的內插補點圖像。

cv2.morphologyEx

函數可以實作基礎梯度操作,看下面這個例子:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
img = cv.imread('./image/morphology.png')
img = cv.cvtColor(img, cv.COLOR_BGR2RGB)
kernel = np.ones((3, 3), np.uint8)
gradient = cv.morphologyEx(img, cv.MORPH_GRADIENT, kernel)
plt.subplot(121), plt.imshow(img), plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(gradient), plt.title('gradient')
plt.xticks([]), plt.yticks([])
plt.show()
           

結果如下所示:

OpenCV與圖像處理學習六——圖像形态學操作:腐蝕、膨脹、開、閉運算、形态學梯度、頂帽和黑帽四、圖像形态學操作

4.4頂帽和黑帽

  • 頂帽(Top Hat):原圖像與開運算圖的內插補點,突出原圖像中比周圍亮的區域。
  • 黑帽(Black Hat):閉運算圖與原圖的內插補點,突出原圖中比周圍暗的區域。

看兩個例子:

頂帽:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
img = cv.imread('./image/morphology.png')
img = cv.cvtColor(img, cv.COLOR_BGR2RGB)
kernel = np.ones((9, 9), np.uint8)
tophat = cv.morphologyEx(img, cv.MORPH_TOPHAT, kernel)
plt.subplot(121), plt.imshow(img), plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(tophat), plt.title('tophat')
plt.xticks([]), plt.yticks([])
plt.show()
           

結果為:

OpenCV與圖像處理學習六——圖像形态學操作:腐蝕、膨脹、開、閉運算、形态學梯度、頂帽和黑帽四、圖像形态學操作

黑帽:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
img = cv.imread('./image/morphology.png')
img = cv.cvtColor(img, cv.COLOR_BGR2RGB)
kernel = np.ones((9, 9), np.uint8)
tophat = cv.morphologyEx(img, cv.MORPH_BLACKHAT, kernel)
plt.subplot(121), plt.imshow(img), plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(tophat), plt.title('blackhat')
plt.xticks([]), plt.yticks([])
plt.show()
           
OpenCV與圖像處理學習六——圖像形态學操作:腐蝕、膨脹、開、閉運算、形态學梯度、頂帽和黑帽四、圖像形态學操作

圖像處理之圖像基本操作的筆記就暫時到這裡,後面将學習傳統方法進行圖像分割,包括門檻值分割、邊緣檢測算法、連通域分析以及一些其他區域生長算法。

繼續閱讀