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

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

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

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

Python

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

Q&A

解決済

2回答

1843閲覧

水槽内のメダカの重心を求めるプログラムについて

sincere

総合スコア3

OpenCV

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

Python

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

0グッド

1クリップ

投稿2021/12/07 07:45

編集2021/12/07 08:32

python初心者です
水槽内のメダカの軌跡を見るためにメダカの重心の値を求めるプログラムを作っています.(動画orリアルタイムで)
現状だと2値化して映ったものすべてに重心が出てしまうので対処法がわかりません(水槽内のごみなどにも)
メダカの重心のみを出すにはどうすればいいでしょうか.また光を当てている影響でメダカの体にも影ができてしまっているのでメダカの体をすべて映せるようにする方法も教えてくださるとうれしいです.

環境:Spyder(anaconda3),opencv4.5.4-dev

import cv2 import time import numpy as np movie = cv2.VideoCapture('sample3.mp4') before = None # 前回の画像を保存する変数 fps = int(movie.get(cv2.CAP_PROP_FPS)) #動画のFPSを取得 while True: /画像を取得 ret, frame = movie.read() /再生が終了したらループを抜ける if ret == False: break gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) if before is None: before = gray.astype("float") continue /現在のフレームと移動平均との差を計算 cv2.accumulateWeighted(gray, before, 0.6) frameDelta = cv2.absdiff(gray, cv2.convertScaleAbs(before)) /frameDeltaの画像を2値化 thresh = cv2.threshold(frameDelta, 6, 255, cv2.THRESH_BINARY)[1] label = cv2.connectedComponentsWithStats(thresh) /オブジェクト情報を項目別に抽出 n = label[0] - 1 data = np.delete(label[2], 0, 0) center = np.delete(label[3], 0, 0) /ラベリング結果書き出し用に二値画像をカラー変換 color_src = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR) /オブジェクト情報を利用してラベリング結果を表示 for i in range(n): x1 = data[i][0] + data[i][2] y1 = data[i][1] + data[i][3] /各オブジェクトの重心座標をに黄文字で表示 cv2.putText(color_src, "X: " + str(int(center[i][0])), (x1-10 , y1+15),cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 255)) cv2.putText(color_src, "Y: " + str(int(center[i][1])), (x1-10 , y1+30),cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 255)) time.sleep(0.25/fps) cv2.imshow('movie',color_src) cv2.imshow('target_bh', thresh) /Enterキーが押されたらループを抜ける if cv2.waitKey(1) == 13: break cv2.destroyAllWindows() # ウィンドウを破棄

イメージ説明
2値化した状態
イメージ説明
重心を割り出している状態

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

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

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

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

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

1T2R3M4

2021/12/07 07:56

インデントをつけていただけませんか。
sincere

2021/12/07 08:07

ご指摘ありがとうございます
fana

2021/12/07 08:17

画像を示す場合,それぞれの画像が何なのか(何のために提示しているのか)という説明が要るのではないでしょうか. ※また,2つの画像は別のシーン(フレーム)のものであるように見えますが,そうであればあえて別にする意図も. (ある画像に関する各処理の過程を例示するのであれば,同一フレームでの絵を貼ると思うので)
sincere

2021/12/07 08:35

ご指摘ありがとうございます。 画像の方はこちらの都合により同フレームではないですが近いフレームに直しました。申し訳ありません。
guest

回答2

0

ベストアンサー

retval, labels, stats, centroids = cv2.connectedComponentsWithStats()

cv2.connectedComponentsWithStats() の返り値 stats を参照すると、面積、幅、高さが参照できるので、これらの情報を使って、誤検出を無視できないでしょうか?

  • stats[i][cv2.CC_STAT_LEFT] で i 番目の検出結果の x 座標
  • stats[i][cv2.CC_STAT_TOP] で i 番目の検出結果の y 座標
  • stats[i][cv2.CC_STAT_AREA] で i 番目の検出結果の面積
  • stats[i][cv2.CC_STAT_WIDTH] で i 番目の検出結果の幅
  • stats[i][cv2.CC_STAT_HEIGHT] で i 番目の検出結果の高さ

例: 面積が極端に大きいまたは小さいものを除外、幅、高さからアスペクト比を計算し、おかしいものは除外、xy座標で水槽の範囲外のものは除外など

OpenCV - 連結成分のラベリングを行う cv2.connectedComponents の使い方

投稿2021/12/07 08:25

tiitoi

総合スコア21956

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

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

sincere

2021/12/07 08:36

ありがとうございます
fana

2021/12/07 09:28

メダカってどの程度緩急のある泳ぎをするのか知らないので可否の判断はつきませんが… この回答のような方法で,あるフレームにおいて「十分にメダカらしい」領域が得られたならば, 「次のフレームでもその近辺にメダカがいるはず」という条件を用いて,次のフレームでは遠くにあるゴミをメダカ候補から排除することができるのではないかと思います.
tiitoi

2021/12/07 17:01

To: fanaさん トラッキングを組み合わせればより精度高く検出できそうですね OpenCV にもいくつか API があったと思います。
fana

2021/12/08 00:58

不真面目な(?)方法としては, Nフレーム目で見つけたメダカ領域を適当に膨張させたようなマスクを作って N+1フレーム目での2値画像にそれをANDする形で使うとか.
guest

0

  • 現状だと2値化して映ったものすべてに重心が出てしまうので対処法がわかりません(水槽内のごみなどにも)メダカの重心のみを出すにはどうすればいいでしょうか.

メダカが一匹なら、data[i][2] * data[i][3] つまり、バウンディングボックスが最も大きいのをメダカだと判定すればよいのではないでしょうか。

投稿2021/12/07 08:23

ppaul

総合スコア24666

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

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

sincere

2021/12/07 08:37

ありがとうございます
fana

2021/12/07 09:07

AABBの面積最大のものを採用するのでは, 例えば,質問内に提示されている2値画像の上の方に残っている線状の領域群が長めに繋がってしまったような場合等に誤判断することになりそうです.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問