<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
分水嶺演演算法是用於分割的經典演演算法,在提取影象中粘連或重疊的物件時特別有用,例如下圖中的硬幣。
使用傳統的影象處理方法,如閾值和輪廓檢測,我們將無法從影象中提取每一個硬幣,但通過利用分水嶺演演算法,我們能夠檢測和提取每一個硬幣。
在使用分水嶺演演算法時,我們必須從使用者定義的標記開始。這些標記可以通過點選手動定義,或者我們可以使用閾值和/或形態學操作等方法自動或啟發式定義它們。
基於這些標記,分水嶺演演算法將輸入影象中的畫素視為地形——該方法通過“淹沒”山谷,從標記開始向外移動,直到不同標記相遇。為了獲得準確的分水嶺分割,必須正確放置標記。
在這篇文章的剩下部分,我將向您展示如何使用分水嶺演演算法來分割和提取影象中既粘連又重疊的物件。
為此,我們將使用各種 Python 包,包括 SciPy、scikit-image 和 OpenCV。
在上圖中,您可以看到使用簡單閾值和輪廓檢測無法提取物件,由於這些物件是粘連的、重疊的或兩者兼有,
因此簡單的輪廓提取會將粘連的物件視為單個物件,而不是多個物件。
# 開啟一個新檔案,將其命名為 watershed.py ,然後插入以下程式碼:
# 開啟一個新檔案,將其命名為 watershed.py ,然後插入以下程式碼: # 匯入必要的包 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 # 構造引數解析並解析引數 ap = argparse.ArgumentParser() # ap.add_argument("-i", "--image", default="HFOUG.jpg", help="path to input image") ap.add_argument("-i", "--image", default="watershed_coins_01.jpg", help="path to input image") args = vars(ap.parse_args()) # 載入影象並執行金字塔均值偏移濾波以輔助閾值化步驟 image = cv2.imread(args["image"]) shifted = cv2.pyrMeanShiftFiltering(image, 21, 51) cv2.imshow("Input", image) # 將影象轉換為灰度,然後應用大津閾值 gray = cv2.cvtColor(shifted, cv2.COLOR_BGR2GRAY) thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] cv2.imshow("Thresh", thresh) # 計算從每個二進位制影象中的畫素到最近的零畫素的精確歐氏距離,然後找出這個距離圖中的峰值 D = ndimage.distance_transform_edt(thresh) # 視覺化距離函數 D_show = cv2.normalize(D, None, 0, 1, cv2.NORM_MINMAX) # print(np.max(D_show)) cv2.imshow("D_show", D_show) # 以座標列表(indices=True)或布林掩碼(indices=False)的形式查詢影象中的峰值。峰值是2 * min_distance + 1區域內的區域性最大值。 # (即峰值之間至少相隔min_distance)。此處我們將確保峰值之間至少有20畫素的距離。 localMax = peak_local_max(D, indices=False, min_distance=20, labels=thresh) # 視覺化localMax temp = localMax.astype(np.uint8) cv2.imshow("localMax", temp * 255) # 使用8-連通性對區域性峰值進行連線成分分析,然後應用分水嶺演演算法 # scipy.ndimage.label(input, structure=None, output=None) # input :待標記的陣列物件。輸入中的任何非零值都被視為待標記物件,零值被視為背景。 # structure:定義要素連線的結構化元素。對於二維陣列。預設是四連通, 此處選擇8連通 # markers = ndimage.label(localMax, structure=np.ones((3, 3)))[0] # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # 視覺化markers temp_markers = markers.astype(np.uint8) cv2.imshow("temp_markers", temp_markers * 20) # 由於分水嶺演演算法假設我們的標記代表距離圖中的區域性最小值(即山谷),因此我們取 D 的負值。 labels = watershed(-D, markers, mask=thresh) print("[INFO] {} unique segments found".format(len(np.unique(labels)) - 1)) # 迴圈遍歷分水嶺演演算法返回的標籤 for label in np.unique(labels): # 0表示背景,忽略它 if label == 0: continue # 否則,為標籤區域分配記憶體並將其繪製在掩碼上 mask = np.zeros(gray.shape, dtype="uint8") mask[labels == label] = 255 # 在mask中檢測輪廓並抓取最大的一個 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) # 顯示輸出影象 cv2.imshow("Output", image) cv2.waitKey(0)
範例比較了兩種分割方法,以分離兩個相連的磁碟:分水嶺演演算法和隨機遊走演演算法。 兩種分割方法都需要種子,即明確屬於某個區域的畫素。在這裡,到背景的距離圖的區域性最大值被用作種子。
import numpy as np from skimage.segmentation import watershed from skimage.feature import peak_local_max from skimage import measure from skimage.segmentation import random_walker import matplotlib.pyplot as plt from scipy import ndimage # import cv2 # Generate an initial image with two overlapping circles x, y = np.indices((80, 80)) x1, y1, x2, y2 = 28, 28, 44, 52 r1, r2 = 16, 20 mask_circle1 = (x - x1) ** 2 + (y - y1) ** 2 < r1 ** 2 mask_circle2 = (x - x2) ** 2 + (y - y2) ** 2 < r2 ** 2 image = np.logical_or(mask_circle1, mask_circle2) # Now we want to separate the two objects in image # Generate the markers as local maxima of the distance # to the background distance = ndimage.distance_transform_edt(image) D_show = distance/np.max(distance) # D_show = cv2.normalize(distance, None, 0, 1, cv2.NORM_MINMAX) local_maxi = peak_local_max( distance, indices=False, footprint=np.ones((3, 3)), labels=image) markers = measure.label(local_maxi) labels_ws = watershed(-distance, markers, mask=image) markers[~image] = -1 labels_rw = random_walker(image, markers) plt.figure(figsize=(12, 3.5)) plt.subplot(141) plt.imshow(image, cmap='gray', interpolation='nearest') plt.axis('off') plt.title('image') plt.subplot(142) plt.imshow(D_show, cmap='Spectral',interpolation='nearest') plt.axis('off') plt.title('distance map') plt.subplot(143) plt.imshow(labels_ws, cmap='Spectral', interpolation='nearest') plt.axis('off') plt.title('watershed segmentation') plt.subplot(144) plt.imshow(labels_rw, cmap='Spectral', interpolation='nearest') plt.axis('off') plt.title('random walker segmentation') plt.tight_layout() plt.show()
到此這篇關於Python+OpenCV實現分水嶺分割演演算法的範例程式碼的文章就介紹到這了,更多相關Python OpenCV分水嶺分割演演算法內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45