前文傳送門:
「Python 影像處理 OpenCV (2):畫素處理與 Numpy 操作以及 Matplotlib 顯示影像」
「Python 影像處理 OpenCV (3):影像屬性、影像感興趣 ROI 區域及通道處理」
「Python 影像處理 OpenCV (4):影像算數運算以及修改顏色空間」
「Python 影像處理 OpenCV (5):影像的幾何變換」
「Python 影像處理 OpenCV (6):影像的閾值處理」
「Python 影像處理 OpenCV (7):影像平滑(濾波)處理」
「Python 影像處理 OpenCV (8):影像腐蝕與影像膨脹」
引言
前面介紹了影像形態學的兩種基礎演算法,影像腐蝕和影像膨脹,本篇接著介紹影像形態學中的開運算、閉運算以及梯度運算。
由於內容的連貫性,請先閱讀前文「Python 影像處理 OpenCV (8):影像腐蝕與影像膨脹」,瞭解清楚影像的腐蝕與膨脹基礎原理。
不然真的沒辦法理解開運算和閉運算。
第一件事情還是給影像增加噪聲,思路沿用之前加噪聲的思路,使用 Numpy 給圖片新增黑白兩種噪聲點,程式碼如下:
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
# 讀取圖片
img = cv.imread("demo.png", cv.IMREAD_UNCHANGED)
source = cv.cvtColor(img, cv.COLOR_BGR2RGB)
rows, cols, chn = source.shape
# 加噪聲-白點噪聲
for i in range(500):
x = np.random.randint(0, rows)
y = np.random.randint(0, cols)
source[x, y, :] = 255
# 影像儲存 白點噪聲影像
cv.imwrite("demo_noise_white.jpg", source)
print("白點噪聲新增完成")
# 重新讀取影像
img1 = cv.imread("demo.png", cv.IMREAD_UNCHANGED)
source1 = cv.cvtColor(img1, cv.COLOR_BGR2RGB)
# 加噪聲-黑點噪聲
for i in range(1000):
x = np.random.randint(0, rows)
y = np.random.randint(0, cols)
source1[x, y, :] = 0
# 影像儲存 黑點噪聲影像
cv.imwrite("demo_noise_black.jpg", source1)
print("黑點噪聲新增完成")
# 顯示結果
titles = ['White Img','Black Img']
images = [source, source1]
# matplotlib 繪圖
for i in range(2):
plt.subplot(1, 2, i+1), plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
形態學開運算
影像開運算實際上是一個組合運算,開運算是影像先進行腐蝕,再進行膨脹的運算。
影像被腐蝕後,去除了噪聲,但是也壓縮了影像;接著對腐蝕過的影像進行膨脹處理,使得剛才在腐蝕過程中被壓縮的影像得以恢復原狀。
下面是一個影像開運算的流程圖:
開運算的一些特性:
- 開運算能夠除去孤立的小點,毛刺和小橋,而總的位置和形狀不便。
- 開運算是一個基於幾何運算的濾波器。
- 結構元素大小的不同將導致濾波效果的不同。
- 不同的結構元素的選擇導致了不同的分割,即提取出不同的特徵。
我們先不管開運算 OpenCV 為我們提供的函式是什麼,先使用前面介紹過的影像腐蝕與膨脹處理看下結果:
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
# 讀取圖片
source = cv.imread("demo_noise_white.jpg", cv.IMREAD_GRAYSCALE)
# 設定卷積核
kernel = np.ones((5, 5),np.uint8)
# 影像腐蝕
erode_img = cv.erode(source, kernel)
# 影像膨脹
dilate_result = cv.dilate(erode_img, kernel)
# 顯示結果
titles = ['Source Img','Erode Img','Dilate Img']
images = [source, erode_img, dilate_result]
# matplotlib 繪圖
for i in range(3):
plt.subplot(1, 3, i+1), plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
可以看到降噪的效果還是不錯的。
接著看 OpenCV 為開運算提供的函式。
影像開運算主要使用到的函式是 morphologyEx()
它是形態學擴充套件的一組函式,而其中的 cv.MORPH_OPEN
對應的是開運算。
使用時語法如下:
dst = cv.morphologyEx(src, cv.MORPH_OPEN, kernel)
- src: 原圖形
- cv2.MORPH_OPEN: 表示開運算
- kernel: 卷積核
我們再使用 morphologyEx()
函式去重新實現下剛才的影像開運算,看下和之前的結果有啥區別:
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
# 讀取圖片
source = cv.imread("demo_noise_white.jpg", cv.IMREAD_GRAYSCALE)
# 設定卷積核
kernel = np.ones((5, 5),np.uint8)
#影像開運算
dst = cv.morphologyEx(source, cv.MORPH_OPEN, kernel)
# 顯示結果
titles = ['Source Img','Dst Img']
images = [source, dst]
# matplotlib 繪圖
for i in range(2):
plt.subplot(1, 2, i+1), plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
至少從肉眼的角度上看不出來和之前的方式有啥區別,實際上也沒啥區別。
形態學閉運算
與開運算相反的是閉運算,閉運算是影像先膨脹,後腐蝕,它有助於關閉前景物體內部的小孔,或物體上的小黑點。
先看下影像閉運算的流程圖:
閉運算的一些特性:
- 閉運算能夠填平小湖(即小孔),彌合小裂縫,而總的位置和形狀不變。
- 閉運算是通過填充影像的凹角來濾波影像的。
- 結構元素大小的不同將導致濾波效果的不同。
- 不同結構元素的選擇導致了不同的分割。
首先還是用 dilate()
和 erode()
函式實現一下影像閉運算,程式碼如下:
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
# 讀取圖片
source = cv.imread("demo_noise_black.jpg", cv.IMREAD_GRAYSCALE)
# 設定卷積核
kernel = np.ones((5, 5),np.uint8)
# 影像膨脹
dilate_result = cv.dilate(source, kernel)
# 影像腐蝕
erode_img = cv.erode(dilate_result, kernel)
# 顯示結果
titles = ['Source Img','Dilate Img','Erode Img']
images = [source, dilate_result, erode_img]
# matplotlib 繪圖
for i in range(3):
plt.subplot(1, 3, i+1), plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
如果想要使用形態學擴充套件的函式 morphologyEx()
則需要把裡面的引數換成 MORPH_CLOSE
,同樣,既然是形態學擴充套件函式,那麼影像腐蝕和影像膨脹也有對應的引數:
- 影像腐蝕:
MORPH_ERODE
- 影像膨脹:
MORPH_DILATE
接著還是使用 MORPH_CLOSE
引數來實現下影像的閉運算:
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
# 讀取圖片
source = cv.imread("demo_noise_black.jpg", cv.IMREAD_GRAYSCALE)
# 設定卷積核
kernel = np.ones((5, 5),np.uint8)
# 影像閉運算
dst = cv.morphologyEx(source, cv.MORPH_CLOSE, kernel)
# 顯示結果
titles = ['Source Img','Dst Img']
images = [source, dst]
# matplotlib 繪圖
for i in range(2):
plt.subplot(1, 2, i+1), plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
形態學梯度運算
影像形態學的梯度運算和前面的開運算閉運算是一樣的,都是組合函式。
梯度運算實際上是影像膨脹減去影像腐蝕後的結果,最終我們得到的是一個類似於影像輪廓的圖形。
梯度運算在 morphologyEx()
函式中的引數是 MORPH_GRADIENT
,示例程式碼如下:
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
# 讀取圖片
source = cv.imread("demo.png", cv.IMREAD_GRAYSCALE)
# 設定卷積核
kernel = np.ones((5, 5), np.uint8)
# 影像梯度運算
dst = cv.morphologyEx(source, cv.MORPH_GRADIENT, kernel)
# 顯示結果
titles = ['Source Img','Dst Img']
images = [source, dst]
# matplotlib 繪圖
for i in range(2):
plt.subplot(1, 2, i+1), plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
示例程式碼
如果有需要獲取原始碼的同學可以在公眾號回覆「OpenCV」進行獲取。
參考
https://blog.csdn.net/Eastmount/article/details/83651172
https://blog.csdn.net/hanshanbuleng/article/details/80657148