実現したいこと
石が重なり合って写っている画像から、個々の石の輪郭を抽出したい。
ひいては、全ての石の面積(ピクセル)を抽出したい。
下記コードは参考URLをコピペし、Watershed法による輪郭抽出を試みた。
しかしWatershed法にこだわる理由はないため、上記目的を達成し得る方法をご存じであれば代替案をお教え頂きたい。
発生している問題・分からないこと
下記URLを参考に、Watershed法による輪郭抽出を試してみた。
https://pystyle.info/opencv-watershed-algorithm/
しかし石が接している部分で個別に認識されずに、複数の石がひとつの塊として認識されてしまう。
個別に認識させるにはどうすれば良いか?
該当のソースコード
import cv2 import numpy as np from matplotlib import pyplot as plt img = cv2.imread("path") # グレースケール形式に変換する。 img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #img_gray = cv2.bitwise_not(img) # 大津の手法で2値化する。 _, img_bin = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) # ノイズを削除する。 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) opening = cv2.morphologyEx(img_bin, cv2.MORPH_OPEN, kernel, iterations=2) # sure background 領域を抽出する。 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) img_sure_bg = cv2.dilate(img_bin, kernel, iterations=2) # 距離マップを作成する。 img_dist = cv2.distanceTransform(img_bin, cv2.DIST_L2, 5) # sure foreground 領域を抽出する。 _, img_sure_fg = cv2.threshold(img_dist, 0.1 * img_dist.max(), 255, cv2.THRESH_BINARY) img_sure_fg = img_sure_fg.astype(np.uint8) # 前景か背景か判断できない領域を抽出する。 img_unknown = cv2.subtract(img_sure_bg, img_sure_fg) # sure foreground にたいして、ラベル付を行う。 ret, markers = cv2.connectedComponents(img_sure_fg) # 前景か背景か判断できない領域はラベル0を割り当てる。 markers += 1 markers[img_unknown == 255] = 0 fig, ax = plt.subplots(figsize=(6, 6)) # watershed アルゴリズムを適用する。 markers = cv2.watershed(img, markers) fig, ax = plt.subplots(figsize=(6, 6)) labels = np.unique(markers) coins = [] for label in labels[2:]: # labels[0]: 境界ラベル、labels[1]: 背景ラベルは無視する。 # ラベル label の領域のみ前景、それ以外は背景となる2値画像を作成する。 target = np.where(markers == label, 255, 0).astype(np.uint8) # 作成した2値画像に対して、輪郭抽出を行う。 contours, hierarchy = cv2.findContours( target, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE ) coins.append(contours[0]) # 輪郭を描画する。 cv2.drawContours(img, coins, -1, color=(0, 0, 255), thickness=2) cv2.imshow('test',img) cv2.waitKey(0)
試したこと・調べたこと
- teratailやGoogle等で検索した
- ソースコードを自分なりに変更した
- 知人に聞いた
- その他
上記の詳細・結果
上記コードのsure foreground 領域を抽出する工程で、下記のように変更した。
cv2.threshold(img_dist,0.5img_dist.max()...→cv2.threshold(img_dist,0.1img_dist.max()...
結果、輪郭として認識される部分は増えたものの、石が接している部分は輪郭扱いにならなかった。
補足
自分は完全に初心者です。
至らないところばかりですが、ご教授頂けますと助かります。

回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2025/03/15 15:33
2025/03/24 10:35