Python OpenCV分水岭算法分割和提取重叠或有衔接的图像中的对象
生活随笔
收集整理的這篇文章主要介紹了
Python OpenCV分水岭算法分割和提取重叠或有衔接的图像中的对象
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
本文將介紹如何使用分水嶺算法對觸摸和重疊的圖像中的對象進行分割和提取。
參考:https://www.pyimagesearch.com/2015/11/02/watershed-opencv/
分水嶺算法是一種分割的經典算法,在提取圖像中連接或重疊的圖像中的對象(例如上圖中的硬幣)時特別有用。 使用傳統的圖像處理方法(例如閾值檢測和輪廓檢測),我們將無法從圖像中提取每個硬幣–但是,利用分水嶺算法,我們能夠準確地檢測和提取每個硬幣。
簡單閥值和邊緣輪廓檢測很強大,但對于圖片中有重疊和互相接觸的對象,簡單閥值和輪廓檢測將無能為力。
簡單閥值和邊緣輪廓檢測結果如下所示:
硬幣數量對不上,也不準確。
要應用分水嶺算法,我們需要定義與圖像中的對象相對應的標記。這些標記可以是用戶定義的,也可以應用圖像處理技術(例如閾值)為我們找到標記。
在應用分水嶺算法時,獲取準確的標記至關重要。
給定標記,我們可以計算歐幾里得距離變換并將距離圖傳遞給分水嶺函數本身,該分水嶺函數從初始標記開始并向外移動,從而“淹沒”距離圖中的山谷。在分割過程中,水的“池”相遇的地方可以視為邊界線。 分水嶺算法的輸出是一組標簽,其中每個標簽對應于圖像中的唯一對象。從那里開始,我們要做的就是分別遍歷每個標簽并提取每個對象。
# import the necessary packages
from skimage.feature import peak_local_max
from skimage.morphology import watershed
from scipy import ndimage
import numpy as np
import argparse
import imutils
import cv2# 我們已成功檢測到圖像中的所有九個硬幣。此外,我們還能夠清晰地繪制每個硬幣周圍的邊界。這與使用簡單閾值檢測和輪廓檢測的先前示例形成了鮮明對比,在先前示例中,僅(錯誤地)檢測到兩個對象。image = cv2.imread('D:/pyimagesearch/images/coin4.jpg')
# 應用金字塔均值漂移濾波 以提高閾值設置步驟的準確性 【金字塔均值偏移濾波可以看做是對彩色圖像平滑顏色的一種操作】
shifted = cv2.pyrMeanShiftFiltering(image, 21, 51)
cv2.imshow("Input", image)# 將經過金字塔均值偏移濾波處理的圖像 讀取為灰度圖像
# 應用Otsu的閾值將背景從前景中分割出來:
gray = cv2.cvtColor(shifted, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv2.imshow("Thresh", thresh)# 分割的第一步:通過distance_transform_edt計算歐幾里德距離變換(EDT Euclidean distance)功能 此函數為每個前景像素計算最接近零的歐幾里得距離(即背景像素)。
D = ndimage.distance_transform_edt(thresh)
# 在距離圖中找到峰值(即局部最大值)。我們將確保每個峰之間的距離至少為20像素。采用peak_local_max的輸出功能,并使用8連接性應用連接組件分析。
localMax = peak_local_max(D, indices=False, min_distance=20,labels=thresh)# 該函數的輸出為我們提供了標記 然后我們將其饋入分水嶺函數
# 分水嶺算法 假設我們的標記代表我們的距離圖中的局部最小值(即山谷),因此我們采用D的負值。
# 分水嶺函數返回標簽矩陣,一個NumPy數組,其寬度和高度與我們的輸入圖像相同。每個像素值作為唯一的標簽值。具有相同標簽值的像素屬于同一對象。
markers = ndimage.label(localMax, structure=np.ones((3, 3)))[0]
labels = watershed(-D, markers, mask=thresh)
print("[INFO] {} unique segments found".format(len(np.unique(labels)) - 1))# 最后一步是簡單地循環唯一標簽值并提取每個唯一對象
# loop over the unique labels returned by the Watershed
# algorithm
for label in np.unique(labels):# label為0 默認為背景,忽略if label == 0:continue# 為我們的遮罩分配內存 并將屬于當前標簽的像素設置為255(白色)。mask = np.zeros(gray.shape, dtype="uint8")mask[labels == label] = 255# 檢測到遮罩中的輪廓 并提取最大的輪廓-該輪廓將代表圖像中給定對象的輪廓/邊界。cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)cnts = imutils.grab_contours(cnts)c = max(cnts, key=cv2.contourArea)# 繪制圍繞對象的包圍圓邊界。我們還可以計算對象的邊界框,應用按位運算,并提取每個單獨的對象。((x, y), r) = cv2.minEnclosingCircle(c)cv2.circle(image, (int(x), int(y)), int(r), (0, 255, 0), 2)cv2.putText(image, "#{}".format(label), (int(x) - 10, int(y)),cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)
# show the output image
cv2.imshow("Output", image)
cv2.waitKey(0)
總結
以上是生活随笔為你收集整理的Python OpenCV分水岭算法分割和提取重叠或有衔接的图像中的对象的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 求一个好听的法国男孩名字!
- 下一篇: python 点云las、laz文件的读