質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.32%
OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

366閲覧

物体が重なり合った画像から個々の輪郭を抽出する方法

rokurou

総合スコア3

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

2クリップ

投稿2025/03/11 11:37

実現したいこと

石が重なり合って写っている画像から、個々の石の輪郭を抽出したい。
ひいては、全ての石の面積(ピクセル)を抽出したい。イメージ説明

下記コードは参考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()...

結果、輪郭として認識される部分は増えたものの、石が接している部分は輪郭扱いにならなかった。

補足

自分は完全に初心者です。
至らないところばかりですが、ご教授頂けますと助かります。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

目的がわかりませんが、コメントには、画像が貼り付けられないので一応回答として
sam2.1_s.ptモデルを使用しました。CPUでは、遅いです。全部選択できてないですが、他にもモデルがあるようです。
イメージ説明
segmentsデータも得られます。そこから面積は計算できるのでは?
モデルの使い方など
https://docs.ultralytics.com/models/sam-2/

投稿2025/03/12 03:39

tmp

総合スコア325

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

rokurou

2025/03/15 15:33

ありがとうございます、チャレンジしてみます。
rokurou

2025/03/24 10:35

SAM2を少し触ってみましたが、どの様にコードを組むべきか分かりませんでした。 もしよろしければ、実際のコードをお教えください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.32%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問