付費限定

[OpenCV應用][Python]應用watershed分割圖像(硬幣分割)

更新 發佈閱讀 16 分鐘

本文參考OpenCV官方Image Segmentation with Watershed Algorithm來實作分割相黏的硬幣

相較於官方範例,多新增取出分割後的物件的中心點來標註,大部分在分割圖像後我們都想知道分割後物件的位置(x,y)。

結果圖

二值化 -> 像素到背景的距離圖 -> 前景圖 ->分割背景圖

標記圖 -> 分割後的圖 -> 套用到原圖並畫出中心

分割結果圖

分割結果圖

OpenCV 實作了一種基於標記的分水嶺演算法物件賦予不同的標籤用一種顏色(或強度)標記我們確定是前景或物體的區域,用另一種顏色標記我們確定是背景或非物體的區域最後標記我們不確定的區域,用0 標記它。然後應用分水嶺演算法。將使用我們給出的標籤進行更新,並且物件的邊界的值為-1。

標記圖像的數值對應於不同的標籤,常見的標籤值為正整數,但有一些特殊值:

正整數: 表示已知的區域,其中每個數字代表一個不同的標籤。

例如,1 表示前景,2 表示背景,0表示不確定的區域。

-1: 在分水嶺演算法後,標記圖像的邊界值會被設為-1。這樣可以用來標示物體的邊界。

程式範例

import numpy as np
import cv2
from matplotlib import pyplot as plt
import copy
img = cv2.imread('coins.jpg')
assert img is not None, "file could not be read, check with os.path.exists()"
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

# noise removal 噪聲去除
kernel = np.ones((3,3),np.uint8)
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2)
sure_bg = cv2.dilate(opening,kernel,iterations=3)
dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5)
_, sure_fg = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0)

# Finding unknown region 找到未知區域
sure_fg = np.uint8(sure_fg) #
unknown = cv2.subtract(sure_bg,sure_fg)

# Marker labelling
ret, markers = cv2.connectedComponents(sure_fg)
# Add one to all labels so that sure background is not 0, but 1
markers = markers + 1
# Now, mark the region of unknown with zero。
markers[unknown==255] = 0

#watershed
markers = cv2.watershed(img,markers)
img[markers == -1] = [255,0,0]

# 在 'markers' 陣列中找到唯一的標籤
unique_labels = np.unique(markers)

# 排除標籤 -1(表示watershed邊界)
unique_labels = unique_labels[unique_labels != -1]

# 將 'img' 轉換為 RGB 以便視覺化
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# 逐一處理每個標籤,找到其中心
for label in unique_labels:
mask = (markers == label) # 建立當前標籤的遮罩
ys, xs = np.where(mask) # 找到當前標籤所有像素的座標

# 計算中心座標
centroid = (np.mean(xs), np.mean(ys)) # (mean x, mean y)

# 將中心座標轉換為整數
center_coordinates = (int(centroid[0]), int(centroid[1])) # (x, y)

# 在中心繪製一個圓
cv2.circle(img_rgb, center_coordinates, radius=5, color=(255, 0, 0), thickness=-1) # -1 fills the circle

# Display the result
plt.imshow(img_rgb)
plt.title('Centroids Marked')
plt.axis('off')
plt.show()
程式結果圖

程式結果圖



程 式 解 析

將會拆解程式範例,並輸出圖片,直觀的了解每個步驟輸出的圖

載入圖片

使用 Otsu 的二值化。

import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('coins.jpg')
assert img is not None, "file could not be read, check with os.path.exists()"
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
#因用ipynb呈現,需plt與opencv默認RGB不同需轉換
gray = cv2.cvtColor(thresh, cv2.COLOR_GRAY2BGR)
gray = cv2.cvtColor(thresh, cv2.COLOR_BGR2RGB)
plt.imshow(gray)
plt.axis('off')
plt.show()
raw-image

前處理步驟

主要用於確定前景背景區域,同時找到未知區域(物體邊界)。

  1. 通過對二值化圖像 thresh 執行兩次開運算,清除圖像中的小斑點或小區域
  2. 膨脹操作(Dilation),通過對 opening 圖像進行三次膨脹操作,確定背景區域
  3. 距離變換(Distance Transform)和二值化操作,將這些距離轉換為二進制圖像,形成確定的前景區域
  4. 背景區域減去前景區域。未知區域是分水嶺演算法中需要進一步處理的區域
import copy
# noise removal 去除雜訊
kernel = np.ones((3,3),np.uint8)
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2)
#通過對二值化圖像 thresh 執行兩次開運算,清除圖像中的小斑點或小區域。

# sure background area 確定背景區域
sure_bg = cv2.dilate(opening,kernel,iterations=3)
#通過對 opening 圖像進行三次膨脹操作,進一步確定背景區域。

# Finding sure foreground area 找到確定的前景區域:
dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5)
#使用 distanceTransform 函數計算二值化圖像 opening 中每個像素到最近的零像素的距離。
_, sure_fg = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0)
# 通過 threshold 函數將這些距離轉換為二進制圖像,形成確定的前景區域

# Finding unknown region 找到未知區域
sure_fg = np.uint8(sure_fg) # 將確定的前景區域(二進制圖像)轉換為 8 位的無符號整數型別 uint8
unknown = cv2.subtract(sure_bg,sure_fg) #通過 subtract 函數找到未知區域,即背景區域減去前景區域。

#因用ipynb呈現,需plt與opencv默認RGB不同需轉換
unknown_show = cv2.cvtColor(unknown, cv2.COLOR_GRAY2BGR)
unknown_show = cv2.cvtColor(unknown_show, cv2.COLOR_BGR2RGB)
sure_fg_Show = cv2.cvtColor(sure_fg, cv2.COLOR_GRAY2BGR)
sure_fg_Show = cv2.cvtColor(sure_fg_Show, cv2.COLOR_BGR2RGB)
plt.subplot(1, 3, 1), plt.imshow(dist_transform), plt.title('dist_transform'), plt.axis('off')
plt.subplot(1, 3, 2), plt.imshow(sure_fg_Show), plt.title('sure_fg'), plt.axis('off')
plt.subplot(1, 3, 3), plt.imshow(unknown_show), plt.title('unknown'), plt.axis('off')
plt.show()

左圖:像素到背景的距離圖

中間的圖:找到的前景圖

右圖:物體邊界圖

raw-image

建立標記

以行動支持創作者!付費即可解鎖
本篇內容共 6493 字、0 則留言,僅發佈於[Python][OpenCV]學習心得筆記你目前無法檢視以下內容,可能因為尚未登入,或沒有該房間的查看權限。
留言
avatar-img
留言分享你的想法!
avatar-img
螃蟹_crab的沙龍
157會員
309內容數
本業是影像辨識軟體開發,閒暇時間進修AI相關內容,將學習到的內容寫成文章分享。 興趣是攝影,踏青,探索未知領域。 人生就是不斷的挑戰及自我認清,希望老了躺在床上不會後悔自己什麼都沒做。
螃蟹_crab的沙龍的其他內容
2025/04/01
1. 概述 在光學字符識別(OCR)過程中,常見的問題之一是「斷字」,即原本應為一個完整字符的部分被錯誤地分割成兩個或多個獨立的字符。這通常發生在掃描文件、圖像降噪或影像二值化處理後。本篇文章將介紹一種基於 骨架化端點距離分析 的斷字檢測方法,並提供完整的 Python 實作。 2. 斷字檢測的
Thumbnail
2025/04/01
1. 概述 在光學字符識別(OCR)過程中,常見的問題之一是「斷字」,即原本應為一個完整字符的部分被錯誤地分割成兩個或多個獨立的字符。這通常發生在掃描文件、圖像降噪或影像二值化處理後。本篇文章將介紹一種基於 骨架化端點距離分析 的斷字檢測方法,並提供完整的 Python 實作。 2. 斷字檢測的
Thumbnail
2025/03/13
本教學將介紹如何使用 OpenCV 來檢測螺絲的鎖附間距,並提供完整的 Python 程式碼來實作這項功能。 🔹 1. 設計目標 使用二值化處理與形態學運算來強化影像 計算螺絲之間的間距 視覺化結果,標記最大間距並顯示數值 🔹 2. 測試用螺絲影像 🔹 3.
Thumbnail
2025/03/13
本教學將介紹如何使用 OpenCV 來檢測螺絲的鎖附間距,並提供完整的 Python 程式碼來實作這項功能。 🔹 1. 設計目標 使用二值化處理與形態學運算來強化影像 計算螺絲之間的間距 視覺化結果,標記最大間距並顯示數值 🔹 2. 測試用螺絲影像 🔹 3.
Thumbnail
2025/01/18
我們將學習如何使用 Python 和 OpenCV 實現圖像的主色提取與重新著色。 以下的程式碼展示了如何通過 KMeans 聚類演算法分析圖像,提取 HSV 色彩空間中的主色,並將圖像重新著色,提取想偵測的物件的顏色。 在官網案例,實作為RGB色彩空間,但如果套用HSV色彩空間則會因為H色
Thumbnail
2025/01/18
我們將學習如何使用 Python 和 OpenCV 實現圖像的主色提取與重新著色。 以下的程式碼展示了如何通過 KMeans 聚類演算法分析圖像,提取 HSV 色彩空間中的主色,並將圖像重新著色,提取想偵測的物件的顏色。 在官網案例,實作為RGB色彩空間,但如果套用HSV色彩空間則會因為H色
Thumbnail
看更多
你可能也想看
Thumbnail
不是每個人都適合自己操盤,懂得利用「專業」,才是績效拉開差距的開始
Thumbnail
不是每個人都適合自己操盤,懂得利用「專業」,才是績效拉開差距的開始
Thumbnail
題目敘述 Merge Nodes in Between Zeros 給定一個鏈結串列,合併非零區間的節點(以加總的方式合併),輸出合併後的鏈結串列。
Thumbnail
題目敘述 Merge Nodes in Between Zeros 給定一個鏈結串列,合併非零區間的節點(以加總的方式合併),輸出合併後的鏈結串列。
Thumbnail
這篇文章討論了從二維整數陣列中挖掘金礦的問題。文章使用DFS模擬N4走法來解決問題,並提供了時間複雜度和空間複雜度的分析。這將有助於瞭解如何從地圖中挖取最多金礦。文章中提到了相關的關鍵知識點和參考資料。
Thumbnail
這篇文章討論了從二維整數陣列中挖掘金礦的問題。文章使用DFS模擬N4走法來解決問題,並提供了時間複雜度和空間複雜度的分析。這將有助於瞭解如何從地圖中挖取最多金礦。文章中提到了相關的關鍵知識點和參考資料。
Thumbnail
這篇文章,會帶著大家複習以前學過的 區間DP框架, 並且以回文子字串、回文子序列的應用題與概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 回文字串的基本定義 s = s[::-1] 也就是說字串s的正序 和 逆序完全相同。 回文字串的基本結構 空字串"
Thumbnail
這篇文章,會帶著大家複習以前學過的 區間DP框架, 並且以回文子字串、回文子序列的應用題與概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 回文字串的基本定義 s = s[::-1] 也就是說字串s的正序 和 逆序完全相同。 回文字串的基本結構 空字串"
Thumbnail
這篇文章,會帶著大家複習以前學過的區間DP框架, 並且以區間DP的概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個實用的演算法框架。 基本的區間DP框架(限制條件: 相鄰的兩項不允許同時選擇) 在House Robbery這題中,我們學會了一種基本的區間DP框架。
Thumbnail
這篇文章,會帶著大家複習以前學過的區間DP框架, 並且以區間DP的概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個實用的演算法框架。 基本的區間DP框架(限制條件: 相鄰的兩項不允許同時選擇) 在House Robbery這題中,我們學會了一種基本的區間DP框架。
Thumbnail
這篇文章,會帶著大家複習以前學過的二分搜尋法(Binary Search)框架, 並且以二分搜尋法的概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個實用的演算法框架。 Binary search 二分搜尋法框架 用途: 在已經排序好的數列中尋找目標值。
Thumbnail
這篇文章,會帶著大家複習以前學過的二分搜尋法(Binary Search)框架, 並且以二分搜尋法的概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個實用的演算法框架。 Binary search 二分搜尋法框架 用途: 在已經排序好的數列中尋找目標值。
Thumbnail
最近會試著寫一些統整類的文章, 幫助讀者、觀眾整理、吸收、複習已經學習到的演算法框架。 找零錢框架 在以前學過的題目中,我們已經學會了考零錢的抽象思考邏輯與框架,就是試著用每一種銅板去湊出n元(也就是找零錢的過程) 寫成虛擬碼或演算法,找零錢用了幾枚銅板可以這樣表達 # 銅板數目累加​
Thumbnail
最近會試著寫一些統整類的文章, 幫助讀者、觀眾整理、吸收、複習已經學習到的演算法框架。 找零錢框架 在以前學過的題目中,我們已經學會了考零錢的抽象思考邏輯與框架,就是試著用每一種銅板去湊出n元(也就是找零錢的過程) 寫成虛擬碼或演算法,找零錢用了幾枚銅板可以這樣表達 # 銅板數目累加​
Thumbnail
題目已經給了依照起點升序排列好的區間陣列。 接下來新插入一個區間,插入後如果和原本的區間重疊,請把他們合併,要求我們輸出插入後的結果。 這是一個線性掃苗,所需時間為O(n)的演算法。 題目已經幫我們排序好區間順序,我們只要接著依序檢查區間、(假如有重疊的話)合併區間。
Thumbnail
題目已經給了依照起點升序排列好的區間陣列。 接下來新插入一個區間,插入後如果和原本的區間重疊,請把他們合併,要求我們輸出插入後的結果。 這是一個線性掃苗,所需時間為O(n)的演算法。 題目已經幫我們排序好區間順序,我們只要接著依序檢查區間、(假如有重疊的話)合併區間。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News