1.1. 形態學操作介紹
初識:
形態學操作是一種基于圖像形狀的處理方法,主要用于分析和處理圖像中的幾何結構。其核心是通過結構元素(卷積核)對圖像進行掃描和操作,從而改變圖像的形狀和特征。例如:
- 腐蝕(Erosion):將圖像中的前景物體邊界向內收縮,使物體變小。
- 膨脹(Dilation):將圖像中的前景物體邊界向外擴展,使物體變大。
- 開運算(Opening):先腐蝕后膨脹,用于去除小噪點。
- 閉運算(Closing):先膨脹后腐蝕,用于填補小孔。
功能:
形態學操作的主要功能包括:
- 去噪:通過腐蝕或開運算去除小的噪點。
- 邊緣提取:通過形態學梯度(膨脹與腐蝕的差)突出邊緣。
- 圖像分割:通過閉運算或開運算分離或連接物體。
- 特征增強:通過頂帽或黑帽操作提取特定特征。
-
- 頂帽:原圖與開運算的差
- 黑帽:閉運算與原圖的差
應用場景:
操作類型 | 應用場景 |
腐蝕 | 去噪、細化邊緣、分離相鄰對象 |
膨脹 | 填補小孔、連接對象、加粗前景 |
開運算 | 去除小噪點、平滑前景邊界 |
閉運算 | 填補暗孔、平滑前景邊界 |
形態學梯度 | 邊緣檢測、輪廓提取 |
頂帽運算 | 提取亮點、去除低頻背景信息 |
黑帽運算 | 提取暗紋、增強低頻陰影 |
?
1.2. 原理介紹
1.2.1. 腐蝕(Erosion) :
- 腐蝕操作會將圖像中的前景物體(通常是白色區域)的邊界向內收縮。具體來說,當結構元素的中心移動到圖像的某個像素時,只有當結構元素覆蓋的所有像素都是前景物體的像素時,該中心像素才會被保留為前景物體的一部分。否則,該像素將被視為背景(黑色區域)。這種操作會使物體的邊緣變細,可以去除小的突出物和噪點。
1.2.2. 膨脹(Dilation) :
- 膨脹操作與腐蝕相反,它會將前景物體的邊界向外擴展。當結構元素的中心移動到圖像的某個像素時,只要結構元素覆蓋的像素中存在至少一個前景物體的像素,該中心像素就會被保留為前景物體的一部分。這種操作會使物體的邊緣變粗,可以填補物體中的小孔和斷開的部分。
1.2.3. 開運算(Opening) :
- 開運算是先腐蝕后膨脹的過程。它可以通過去除小的突出物和噪點來平滑前景物體的邊界。開運算對于去除小的白色噪點特別有效。
-
- 腐蝕:可以有效的消除突出物體和噪點,但是原前景會變小,有的地方存在孔洞與斷開
- 膨脹:修復孔洞,恢復大小。
1.2.4. 閉運算(Closing) :
- 閉運算是先膨脹后腐蝕的過程。它可以通過填補小的孔洞來平滑前景物體的邊界。閉運算對于填補小的黑色孔洞特別有效。
-
- 膨脹:修復孔洞,但是前景圖像會變大
- 腐蝕:將大小近似恢復到原圖大小
1.2.5. 頂帽操作:
-
- 定義:頂帽操作是原始圖像與開運算結果之間的差值。開運算是先進行腐蝕操作,再進行膨脹操作。
- 功能:
-
-
- 頂帽操作可以提取圖像中比背景亮的細小區域。
- 提取比背景亮的細小區域。去除大范圍的低頻背景信息,
- 突出局部亮點。增強對比度。
-
-
- 原理:
-
-
- 開運算會去掉毛刺和突出部分
- 原圖減去開運算結果,就可以獲得開運算去除的細小區域
-
1.2.6. 黑帽操作:
-
- 定義: 黑帽操作是閉運算結果與原始圖像之間的差值。閉運算是先進行膨脹操作,再進行腐蝕操作。黑帽操作可以提取圖像中比背景暗的細小區域。
- 功能:
-
-
- 提取比背景暗的小區域。
- 突出細小的暗紋和陰影區域。
- 增強對比度,適合背景亮、局部暗區域的圖像。
-
-
- 原理:
-
-
- 閉運算先膨脹在腐蝕,把孔洞和非連續區域不全了
- 閉運算減去原圖像,就可以得到閉運算去除的部分——比背景暗的小區域
-
1.3. 在openCV中實現
1.3.1. kernel
以下函數都會用到kernel
,結構元素(卷積核),用于定義鄰域的形狀和大小。選擇合適的形狀與大小,可以提高形態學操作的效果。首先需要了解一下如何選擇kernel
1.3.1.1. 確定結構元素形狀
結構元素的形狀應根據圖像的特征和處理目標來選擇。常見的結構元素形狀包括:
- 矩形(Rectangular):
-
- 適用于處理規則形狀的圖像,如文本、表格等。
- 代碼示例:
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
- 橢圓(Elliptical):
-
- 適用于處理圓形或橢圓形的圖像,如細胞、顆粒等。
- 代碼示例:
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
- 十字形(Cross-shaped):
-
- 適用于處理需要突出中心點的圖像,如邊緣檢測等。
- 代碼示例:
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5))
1.3.1.2. 確定結構元素大小
結構元素的大小應根據圖像中物體的大小和細節來選擇。以下是一些指導原則:
- 去除小噪點:
-
- 如果圖像中有小的噪點,選擇較小的結構元素(如 3x3 或 5x5)。
- 代碼示例:
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
- 填補小孔:
-
- 如果圖像中有小的孔洞,選擇較大的結構元素(如 5x5 或 7x7)。
- 代碼示例:
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
- 處理大物體:
-
- 如果圖像中有較大的物體,選擇更大的結構元素(如 7x7 或 9x9)。
- 代碼示例:
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7, 7))
1.3.1.3. 選擇結構元素的步驟
- 分析圖像特征:
-
- 觀察圖像中的物體大小、形狀和細節。
- 確定需要處理的目標(如去除噪點、填補孔洞、提取邊緣等)。
- 選擇結構元素形狀:
-
- 根據圖像的特征選擇合適的形狀(矩形、橢圓、十字形等)。
- 選擇結構元素大小:
-
- 根據圖像中物體的大小和細節選擇合適的大小。
- 可以通過實驗逐步調整結構元素的大小,觀察不同大小對結果的影響。
- 實驗和調整:
-
- 使用不同的結構元素大小和形狀進行實驗,觀察處理后的圖像效果。
- 根據實驗結果調整結構元素的大小和形狀,直到達到滿意的效果。
1.3.2. cv2.erode
函數:
def erode(src: cv2.typing.MatLike, kernel: cv2.typing.MatLike, dst: cv2.typing.MatLike | None = ..., anchor: cv2.typing.Point = ..., iterations: int = ..., borderType: int = ..., borderValue: cv2.typing.Scalar = ...) -> cv2.typing.MatLike: ...
參數解釋:
src
:輸入圖像(通常是二值圖像或灰度圖像)。kernel
:結構元素(卷積核),用于定義鄰域的形狀和大小。dst
:輸出圖像。如果未指定,則默認與輸入圖像具有相同的類型和大小。anchor
:結構元素的錨點位置,默認為(-1, -1)
,表示錨點位于結構元素的中心。iterations
:迭代次數,默認為 1。增加迭代次數會增強腐蝕的效果。borderType
:邊界填充方式,默認為cv2.BORDER_CONSTANT
。常見的邊界填充方式有:
-
cv2.BORDER_CONSTANT
:用常數值填充邊界。cv2.BORDER_REFLECT
:用鏡像反射的方式填充邊界。cv2.BORDER_REPLICATE
:用邊界像素值重復填充邊界。cv2.BORDER_WRAP
:用環繞方式填充邊界。
borderValue
:邊界填充的值,默認為 0。
參數確定方法:
- 結構元素(Kernel):如第一點所講
- 迭代次數(Iterations):根據需要調整,次數越多,腐蝕效果越明顯。通常設置為 1 或 2。
參數對結果的影響:
- 結構元素的形狀和大小:影響腐蝕的范圍和效果。較大的結構元素會使腐蝕效果更明顯,但可能會導致圖像失真。
- 迭代次數:增加迭代次數會使腐蝕效果更明顯,但可能會導致圖像過度腐蝕。
使用注意事項:
- 選擇合適的結構元素大小和形狀,避免過度腐蝕導致圖像失真。
- 迭代次數不宜過多,以免影響圖像的整體結構。
結合腐蝕和對不同結構元素的效果進行對比:
def TestMorphologicalErode(iterator:int):# 讀取圖像img = cv2.imread('Word.jfif', 0) # 以灰度模式讀取圖像# 定義不同形狀和大小的結構元素kernel_rect = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) # 矩形結構元素kernel_ellipse = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)) # 橢圓結構元素kernel_cross = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3)) # 十字形結構元素# 腐蝕操作erosion_rect = cv2.erode(img, kernel_rect, iterations=1)erosion_ellipse = cv2.erode(img, kernel_ellipse, iterations=1)erosion_cross = cv2.erode(img, kernel_cross, iterations=1)# 顯示結果plt.figure(figsize=(12, 8))plt.subplot(2, 2, 1)plt.imshow(img, cmap='gray')plt.title('Original Image')plt.axis('off')plt.subplot(2, 2, 2)plt.imshow(erosion_rect, cmap='gray')plt.title('Erosion with Rectangular Kernel')plt.axis('off')plt.subplot(2, 2, 3)plt.imshow(erosion_ellipse, cmap='gray')plt.title('Erosion with Elliptical Kernel')plt.axis('off')plt.subplot(2, 2, 4)plt.imshow(erosion_cross, cmap='gray')plt.title('Erosion with Cross-shaped Kernel')plt.axis('off')plt.show()
結果發現:
- 腐蝕操作,字反而變粗了,其實這里可以理解前景為,黑色的字是背景,腐蝕會讓白色的前景變小,即黑色的背景變大,所以黑色的字變大了
- 矩形的白色孔洞腐蝕的厲害,十字星與橢圓的與原圖保留的較好(對比“驚”的口)
1.3.3. cv2.dilate
函數:
def dilate(src: cv2.typing.MatLike, kernel: cv2.typing.MatLike, dst: cv2.typing.MatLike | None = ..., anchor: cv2.typing.Point = ..., iterations: int = ..., borderType: int = ..., borderValue: cv2.typing.Scalar = ...) -> cv2.typing.MatLike: ...
參數解釋:
src
:輸入圖像(通常是二值圖像或灰度圖像)。kernel
:結構元素(卷積核),用于定義鄰域的形狀和大小。dst
:輸出圖像。如果未指定,則默認與輸入圖像具有相同的類型和大小。anchor
:結構元素的錨點位置,默認為(-1, -1)
,表示錨點位于結構元素的中心。iterations
:迭代次數,默認為 1。增加迭代次數會增強膨脹的效果。borderType
:邊界填充方式,默認為cv2.BORDER_CONSTANT
。borderValue
:邊界填充的值,默認為 0。
參數確定方法:
- 結構元素(Kernel):如第一部分所示
- 迭代次數(Iterations):根據需要調整,次數越多,膨脹效果越明顯。通常設置為 1 或 2。
參數對結果的影響:
- 結構元素的形狀和大小:影響膨脹的范圍和效果。較大的結構元素會使膨脹效果更明顯,但可能會導致圖像失真。
- 迭代次數:增加迭代次數會使膨脹效果更明顯,但可能會導致圖像過度膨脹。
使用注意事項:
- 選擇合適的結構元素大小和形狀,避免過度膨脹導致圖像失真。
- 迭代次數不宜過多,以免影響圖像的整體結構。
對比不同形狀結構元素的膨脹操作:
def TestMorphologicalDilate(iterator:int):# 讀取圖像img = cv2.imread('Word.jfif', 0) # 以灰度模式讀取圖像# 定義不同形狀和大小的結構元素kernel_rect = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) # 矩形結構元素kernel_ellipse = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)) # 橢圓結構元素kernel_cross = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3)) # 十字形結構元素# 腐蝕操作erosion_rect = cv2.dilate(img, kernel_rect, iterations=1)erosion_ellipse = cv2.dilate(img, kernel_ellipse, iterations=1)erosion_cross = cv2.dilate(img, kernel_cross, iterations=1)# 顯示結果plt.figure(figsize=(12, 8))plt.subplot(2, 2, 1)plt.imshow(img, cmap='gray')plt.title('Original Image')plt.axis('off')plt.subplot(2, 2, 2)plt.imshow(erosion_rect, cmap='gray')plt.title('Dilation with Rectangular Kernel')plt.axis('off')plt.subplot(2, 2, 3)plt.imshow(erosion_ellipse, cmap='gray')plt.title('Dilation with Elliptical Kernel')plt.axis('off')plt.subplot(2, 2, 4)plt.imshow(erosion_cross, cmap='gray')plt.title('Dilation with Cross-shaped Kernel')plt.axis('off')plt.show()
- 膨脹操作會讓白色孔洞變大,黑色字體會變瘦
- 矩形效果不好,實際運行時可以在字體邊緣看到一些處理過的痕跡,橢圓形與十字星更適合毛筆字的處理
1.3.4. cv2.morphologyEx
(開運算、閉運算、頂帽操作、黑帽操作、形態學梯度)
函數:
cv2.morphologyEx(src, op, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]]) -> dst
參數解釋:
src
:輸入圖像(通常是二值圖像或灰度圖像)。op
:形態學操作類型:
-
cv2.MORPH_OPEN
:開運算。cv2.MORPH_CLOSE
:閉運算。cv2.MORPH_TOPHAT
:頂帽操作。cv2.MORPH_BLACKHAT
:黑帽操作。cv2.MORPH_GRADIENT
:形態學梯度。
kernel
:結構元素(卷積核),用于定義鄰域的形狀和大小。dst
:輸出圖像。如果未指定,則默認與輸入圖像具有相同的類型和大小。anchor
:結構元素的錨點位置,默認為(-1, -1)
,表示錨點位于結構元素的中心。iterations
:迭代次數,默認為 1。增加迭代次數會增強操作的效果。borderType
:邊界填充方式,默認為cv2.BORDER_CONSTANT
。borderValue
:邊界填充的值,默認為 0。
參數確定方法:
- 結構元素(Kernel):根據圖像的特征和處理目標選擇合適的形狀和大小。例如,去除小噪點時,可以選擇較小的結構元素,如
np.ones((3, 3), np.uint8)
;填補小孔時,可以選擇較大的結構元素,如np.ones((5, 5), np.uint8)
。 - 迭代次數(Iterations):根據需要調整,次數越多,操作的效果越明顯。通常設置為 1 或 2。
參數對結果的影響:
- 結構元素的形狀和大小:影響操作的范圍和效果。較大的結構元素會使操作效果更明顯,但可能會導致圖像失真。
- 迭代次數:增加迭代次數會使操作效果更明顯,但可能會導致圖像過度處理。
使用注意事項:
- 選擇合適的結構元素大小和形狀,避免過度處理導致圖像失真。
- 迭代次數不宜過多,以免影響圖像的整體結構。
- 不同的操作類型(如開運算、閉運算等)對圖像的影響不同,需根據具體需求選擇合適的操作類型。
根據運算結果,我們可以嘗試對比一下結果圖
def TestMorphologicalEx():image=cv2.imread("Word.jfif",0) #讀取灰度圖kernel=cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))#十字星 3*3 image_open=cv2.morphologyEx(image,cv2.MORPH_OPEN,kernel,iterations=1)image_close=cv2.morphologyEx(image,cv2.MORPH_CLOSE,kernel,iterations=1)image_TopHat=cv2.morphologyEx(image,cv2.MORPH_TOPHAT,kernel,iterations=1)image_BlackHat=cv2.morphologyEx(image,cv2.MORPH_BLACKHAT,kernel,iterations=1)# 顯示結果plt.figure(figsize=(8, 12))plt.subplot(3, 2, 1)plt.imshow(image, cmap='gray')plt.title('Original Image')plt.axis('off')plt.subplot(3, 2, 2)plt.imshow(image, cmap='gray')plt.title('Original Image')plt.axis('off')plt.subplot(3, 2, 3)plt.imshow(image_open, cmap='gray')plt.title('image_open')plt.axis('off')plt.subplot(3, 2, 4)plt.imshow(image_close, cmap='gray')plt.title('image_close')plt.axis('off')plt.subplot(3, 2, 5)plt.imshow(image_TopHat, cmap='gray')plt.title('image_TopHat Original - open')plt.axis('off')plt.subplot(3, 2, 6)plt.imshow(image_BlackHat, cmap='gray')plt.title('image_BlackHat Close - Original')plt.axis('off')plt.show()
?
- 在這個圖中前景是白色,黑色是背景
- 頂帽操作結果是開運算去除的噪點,可以看到白色前景的噪點確實去掉了,在這里體現在于背景(黑色部分)更連續了
- 黑帽操作是閉運算補全的孔洞,白色為前景,紅框部分可以理解為前景中的孔洞,閉運算填補了孔洞
?