【翻譯:OpenCV-Python教程】形態變化
⚠️這個系列是自己瞎翻的,文法很醜,主要靠意會,跳著跳著撿重要的部分翻,翻錯了不負責,就這樣哈。
⚠️基於3.4.3,Morphological Transformations,附原文。
目標
在這一章節,
- 我們會學到不同的形態操作比如侵蝕,膨脹,開放,閉合等等。
- 我們會遇到不同的方法,好像:cv.erode(),cv.dilate(),cv.morphologyEx()等等。
理論
形態變換是基於影象形狀的一些簡單操作。 它通常在二進位制影象上執行。 它需要兩個輸入,一個是我們的原始影象,第二個是稱為結構元素或核心,它決定了操作的性質。 兩個基本的形態學運算子是侵蝕和膨脹。 然後它的變體形式如開放,閉合,梯度等等也發揮作用。 我們將在以下圖片的幫助下逐一看到它們:
1、侵蝕
侵蝕的基本思想就像土壤侵蝕一樣,它會侵蝕前景物體的邊界(總是試圖保持前景為白色)。它具體做了什麼? 核心在影象中滑動(如在上節提到的2D卷積中那樣)。只有當核心下的所有畫素都是1時,原始影象中的畫素(1或0)才會被認為是1,否則它會被侵蝕(變為零)。
所以那到底發生了啥,邊界附近的取決於核心大小的所有畫素都將被丟棄。 因此,前景物件的厚度或大小減小,或者影象中的白色區域減小。 它有助於消除小的白噪聲(正如我們在色彩空間章節中看到的那樣),分離兩個連線的物件等。
這裡,作為一個例子,我用一個完整的 5x5 核心。讓我們看看它是如何工作的:
import cv2 as cv import numpy as np img = cv.imread('j.png',0) kernel = np.ones((5,5),np.uint8) erosion = cv.erode(img,kernel,iterations = 1)
結果:
2、 膨脹
它剛好於侵蝕相反。這裡,如果核心下至少有一個畫素元素是 '1' ,那我們就認為這個畫素點為 '1' 。因此它令到影象上的白色區域或者前景的大小增加了。通常,在如去除噪聲這樣的情景下,侵蝕之後要用一次膨脹演算法。因為,侵蝕雖然能去掉白噪聲,但也會讓我們的物體縮小。因此我們要(用膨脹演算法把它再展開)。自從噪聲(從侵蝕演算法中)消失之後,它們就不會再(因為膨脹演算法而)出現了。但我們的物體區域會增加,它也有助於連線物體的破碎部分。
dilation = cv.dilate(img,kernel,iterations = 1)
結果:
3、開放
開放就是腐蝕之後接膨脹的另一種叫法。它有助於消除噪聲,就像我們在上面解釋的那樣,這裡我們使用 cv.morphologyEx() 方法。
opening = cv.morphologyEx(img, cv.MORPH_OPEN, kernel)
結果:
4、閉合
閉合與開放相反,膨脹之後接侵蝕。它有助於關閉掉前景物件上的小洞,或者物件上的小黑點。
closing = cv.morphologyEx(img, cv.MORPH_CLOSE, kernel)
結果:
5、梯度
梯度是一張影象膨脹和侵蝕的差。
這個結果看起來像是物體的外邊線。
gradient = cv.morphologyEx(img, cv.MORPH_GRADIENT, kernel)
結果:
6、頂帽運算
它是原圖與執行過開放演算法的原圖之差,以下是示例是按一個9x9核心來進行的運算。
tophat = cv.morphologyEx(img, cv.MORPH_TOPHAT, kernel)
結果:
7、黑帽運算
它是原圖經過閉合運算之後的結果與原圖之差。
blackhat = cv.morphologyEx(img, cv.MORPH_BLACKHAT, kernel)
結果:
結構化元素
在之前的示例中,我們在Numpy的幫助下手動建立了一個結構化的元素。它是長方形的,但在某些情況下,你可能需要圓形或者橢圓形的核心。所以為了達到這個目的,OpenCV 有個方法,cv.getStructuringElement() 。你只需要傳入核心的形狀以及大小,你就能得到你需要的核心。
# Rectangular Kernel
>>> cv.getStructuringElement(cv.MORPH_RECT,(5,5))
array([[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]], dtype=uint8)
# Elliptical Kernel
>>> cv.getStructuringElement(cv.MORPH_ELLIPSE,(5,5))
array([[0, 0, 1, 0, 0],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[0, 0, 1, 0, 0]], dtype=uint8)
# Cross-shaped Kernel
>>> cv.getStructuringElement(cv.MORPH_CROSS,(5,5))
array([[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[1, 1, 1, 1, 1],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0]], dtype=uint8)