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

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

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

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

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Python

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

Q&A

解決済

2回答

3660閲覧

物体が地面に落ちた位置(バウンド位置)を検出したい

snake207

総合スコア13

OpenCV

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

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Python

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

0グッド

1クリップ

投稿2018/10/27 01:31

編集2018/10/29 07:17

やりたいこと

検出した物体(ボール)が地面に落ちたことを検出したい

質問内容

映像にラインを引き、検出した物体(ボール)がラインと重なったかどうかの
判断をしたいのですがどうすればいいですか?

作成したプログラム

カメラからの映像を取得し、限定した範囲だけ物体検出するプログラムを作成しました。
このプログラムに付け加える形にしたいです。

Python

1import cv2 2import sys 3import numpy as np 4 5xmin,xmax = 112, 483 # 左上,右下のX座標 6ymin,ymax = 172, 408 # 左上,右下のy座標 7 8def dilation(dilationSize, kernelSize, img): # 膨張した画像にして返す 9 kernel = np.ones((kernelSize, kernelSize), np.uint8) 10 element = cv2.getStructuringElement(cv2.MORPH_RECT, (2 * dilationSize + 1, 2 * dilationSize + 1), (dilationSize, dilationSize)) 11 dilation_img = cv2.dilate(img, kernel, element) 12 return dilation_img 13 14 15def detect(gray_diff, thresh_diff=100, dilationSize=9, kernelSize=20): # 一定面積以上の物体を検出 16 retval, black_diff = cv2.threshold(gray_diff, thresh_diff, 255, cv2.THRESH_BINARY) # 2値化 17 dilation_img = dilation(dilationSize, kernelSize, black_diff) # 膨張処理 18 img = dilation_img.copy() 19 image, contours, hierarchy = cv2.findContours(dilation_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE,offset=(xmin,ymin)) # 境界線検出 20 21 ball_pos = [] 22 23 for i in range(len(contours)): # 重心位置を計算 24 count = len(contours[i]) 25 area = cv2.contourArea(contours[i]) # 面積計算 26 x, y = 0.0, 0.0 27 for j in range(count): 28 x += contours[i][j][0][0] 29 y += contours[i][j][0][1] 30 31 x /= count 32 y /= count 33 x = int(x) 34 y = int(y) 35 ball_pos.append([x, y]) 36 37 return ball_pos, img 38 39 40def displayCircle(image, ballList, thickness=5): 41 for i in range(len(ballList)): 42 x = int(ballList[i][0]) 43 y = int(ballList[i][1]) 44 cv2.circle(image, (x, y), 10, (0, 0, 255), thickness) 45 return image 46 47 48def resizeImage(image, w=2, h=2): 49 height = image.shape[0] 50 width = image.shape[1] 51 resizedImage = cv2.resize(image, (int(width / w), int(height / h))) 52 return resizedImage 53 54 55def blackToColor(bImage): 56 colorImage = np.array((bImage, bImage, bImage)) 57 colorImage = colorImage.transpose(1, 2, 0) 58 return colorImage 59 60 61video = cv2.VideoCapture(0) # videoファイルを読み込む 62# fourcc = cv2.VideoWriter_fourcc(*'MJPG') 63fourcc = cv2.VideoWriter_fourcc(*'XVID') 64 65if not video.isOpened(): # ファイルがオープンできない場合の処理. 66 print("Could not open video") 67 sys.exit() 68 69vidw = video.get(cv2.CAP_PROP_FRAME_WIDTH) 70vidh = video.get(cv2.CAP_PROP_FRAME_HEIGHT) 71 72 73ok, frame = video.read() # 最初のフレームを読み込む 74if not ok: 75 print('Cannot read video file') 76 sys.exit() 77 78frame_pre = frame.copy() 79frame_pre[ymin:ymax,xmin:xmax] 80 81while True: 82 ok, frame = video.read() # フレームを読み込む 83 if not ok: 84 break 85 frame_next = frame.copy() 86 87 color_diff = cv2.absdiff(frame_next[ymin:ymax, xmin:xmax], frame_pre[ymin:ymax, xmin:xmax]) # フレーム間の差分計算 88 gray_diff = cv2.cvtColor(color_diff, cv2.COLOR_BGR2GRAY) # グレースケール変換 89 retval, black_diff = cv2.threshold(gray_diff,30, 255, cv2.THRESH_BINARY) 90 91 ball, dilation_img = detect(gray_diff) 92 93 frame = displayCircle(frame, ball, 2) # 丸で加工 94 95 cv2.imshow("Tracking", frame) # フレームを画面表示 96 cv2.imshow("a",color_diff) 97 98 frame_pre = frame_next.copy() # 次のフレームの読み込み 99 frame_pre[ymin:ymax, xmin:xmax] 100 101 k = cv2.waitKey(10) & 0xff # ESCを押したら中止 102 if k == 27: 103 break 104 105video.release() 106cv2.destroyAllWindows()

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

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

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

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

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

tiitoi

2018/10/29 07:31

ボールの検出自体はうまくいくことは確認出来ているのでしょうか?
snake207

2018/10/29 07:45

はい、ボールの検出自体はほぼうまくできています。
guest

回答2

0

ベストアンサー

例えば、、、

ラインを細長い四角形で定義し、その中に検出したボールの中心が含まれるかどうかで判定するのはどうでしょうか。

点が四角形の中に含まれるかどうかは pointPolygonTest() を使うと、判断できます。

python

1retval = cv.pointPolygonTest(contour, pt, measureDist)
  • contour: 輪郭の点の一覧。(N, 2) の numpy 配列
  • pt: (x, y) のタプル
  • measureDist: 端点までの距離を計算するかどうか

返り値は、ポリゴンの内側にある場合は正の値、境界線上にある場合は0、外側にある場合は負の値を返します。

サンプルコード

rect は四角形の4点を表す (4, 2) の numpy 配列、point は点を表す (x, y) のタプルとしたとき、cv2.pointPolygonTest(rect, point, False) >= 0 の場合、その点は四角形の中に含まれると判断できます。

import cv2 import matplotlib.pyplot as plt import numpy as np from matplotlib.patches import Polygon from matplotlib.lines import Line2D # 線と長方形を定義 p1 = (50, 50) p2 = (200, 100) rect = np.array([[170, 113], [167, 57], [317, 50], [319, 105]]) def within(point, rect): '''点 point が四角形 rect に含まれているかどうか ''' return cv2.pointPolygonTest(rect, point, False) >= 0 # 描画する。 # ------------------------------------------------ fig, ax = plt.subplots() ax.set_xlim([0, 500]) ax.set_ylim([0, 200]) ax.add_patch(Polygon(rect, fill=False)) # 長方形を描画する。 for i, point in enumerate([p1, p2]): ax.text(*point, 'line {}'.format(i), fontsize=12) # テキストを描画する。 if within(point, rect): plt.plot([point[0]], [point[1]], marker='o', markersize=3, color="blue") # 点を描画する。 print('rect contains point {}.'.format(i)) else: plt.plot([point[0]], [point[1]], marker='o', markersize=3, color="red") # 点を描画する。 print('rect does not contains point {}.'.format(i)) plt.show()

イメージ説明

重心位置の計算について

質問欄のコードで1つ気になった点ですが

for i in range(len(contours)): # 重心位置を計算 count = len(contours[i]) area = cv2.contourArea(contours[i]) # 面積計算 x, y = 0.0, 0.0 for j in range(count): x += contours[i][j][0][0] y += contours[i][j][0][1] x /= count y /= count x = int(x) y = int(y) ball_pos.append([x, y])

この部分は、cv2.moments() でモーメントを計算することで以下のように重心を求められます。参考リンク

for cnt in contours: # 重心位置を計算 M = cv2.moments(cnt, False) x, y = int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]) ball_pos.append([x, y])

追記

タプルで表現された点が4点で構成される四角に含まれるかどうかは以下で判定すればよいかと思います。

python

1import cv2 2 3def within(point, rect): 4 '''点 point が四角形 rect に含まれているかどうか 5 ''' 6 return cv2.pointPolygonTest(rect, point, False) >= 0 7 8point = (200, 100) 9rect = np.array([[170, 113], [167, 57], [317, 50], [319, 105]]) 10 11print(within(point, rect)) # True

追記

とりあえず、定義した四角の中にボールの中心が入っている場合は赤色、入っていない場合は青色になるように、以下の関数を変更してみました。
rect の4点の座標値はラインに合わせて変えてください。

python

1def displayCircle(image, ballList, thickness=5): 2 # ここはラインに合わせて変えてください。 3 rect = np.array([[170, 113], [167, 57], [317, 50], [319, 105]]) 4 5 for i in range(len(ballList)): 6 x = int(ballList[i][0]) 7 y = int(ballList[i][1]) 8 9 if cv2.pointPolygonTest(rect, (x, y), False) >= 0: 10 # 線の中にボールの中心が入っている赤色で表示。 11 cv2.circle(image, (x, y), 10, (0, 0, 255), thickness) 12 else: 13 # 線の中にボールの中心が入っていない場合、青色で表示。 14 cv2.circle(image, (x, y), 10, (255, 0, 0), thickness) 15 16 return image

投稿2018/10/29 11:48

編集2018/10/31 08:27
tiitoi

総合スコア21956

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

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

snake207

2018/10/29 13:27

テニスコートのラインを 細長い四角形として定義して その中に検出したボールの中心が 入れったかの判断をするということですか?
tiitoi

2018/10/29 13:45

はい、そのような意図です。 rect は回転していても構いません。
snake207

2018/10/30 06:42

分かりました、一度プログラムを作成していこうと思います。 ご丁寧に教えていただき、ありがとうございます。 またわからないところがあれば、よろしくお願いします。
snake207

2018/10/30 13:54

ボールの座標をタプルに格納して 四角形の中に入ったかどうかを判定していんですがどうすればいいですか?
tiitoi

2018/10/30 14:17 編集

回答に追記したようにやればいいかと思います。
fana

2018/10/31 01:33

「細長い四角形」の太さはボール像の径から決める感じですか?
tiitoi

2018/10/31 02:04

画像から検出するか、手動で設定することを想定してました。
snake207

2018/10/31 06:44

すいません、質問の内容が間違っていました。 ボールの座標をタプルに格納するにはどうすればいいですか?
tiitoi

2018/10/31 07:08

detect() 内の ball_pos.append([x, y]) がボールの座標ですよね? タプルにしたいのであれば、ball_pos.append((x, y))とすればよいと思います。
snake207

2018/10/31 07:29

分かりました。ありがとうございます。 ということは、入ったかどうかを判定するときに def within(point, rect): return cv2.pointPolygonTest(rect, point, False) >= 0 のところでpointのところをball_posを入れればいいですか?
tiitoi

2018/10/31 07:36

ball_pos ってリストになっているので、複数個の場合もあるってことですよね? 渡すべきはタプルのリストではなく、タプルなので1個しか要素がない場合でも ball_pos[0] のようにしないといけません。
snake207

2018/10/31 07:37

おそらくですが、 ball, dilation_img = detect(gray_diff)で ballに座標が入れられていると思います。
tiitoi

2018/10/31 07:41 編集

detect() 関数を見てみると、return ball_pos, img となっており、返してる ball_pos のほうを見てみると、ball_pos = [] とリストとして宣言されてますよね。なので、detect() が返すのは [(x, y), ...] というタプルのリストです。 記載のコードはご自身で書かれたコードではないのでしょうか? 質問欄のコードの内容は把握されているのだと思っていたのですが。。
snake207

2018/10/31 07:48

下記のサイトに書いているプログラムを参考し、改善を行い今のprogramを作成しました。なので、理解しきれていないところがいくつかあります。 申し訳ありません。。 https://qiita.com/otakoma/items/04216c60fa31eae60947
tiitoi

2018/10/31 07:56 編集

とりあえず、rect は4点からなる四角形、point は (x, y) のタプルです。ball_pos はリストなので、ball_pos = [(x, y), (x, y), ..] と複数入っている可能性もあります。 ball_pos[0] のようにして各要素を渡せばよいです。
snake207

2018/10/31 08:17

def within(ball_pos, rect): return cv2.pointPolygonTest(rect, ball_pos[0], False) >= 0 ということですか?
snake207

2018/10/31 08:25

ball_posに入れられた複数の要素を一つ一つ渡さなければ ならないということですか? もしそうなると、ball_pos[0],ball_pos[1],ball,pos[2]を それぞれいれることになると思うのですが。。
tiitoi

2018/10/31 08:30 編集

> ball_pos[0],ball_pos[1],ball_pos[2]を それぞれいれることになると思うのですが。。 おっしゃる通りそのようにする必要があります。 なので、cv2.pointPolygonTest(rect, ball_pos, False) では駄目です。 とりあえず変更例を追記に書きました。 displayCircle() でボールの丸を描画しているようなので、定義した四角に入っていれば赤、入っていなければ青色で丸を描画する例を書きました。rect は線に合わせて変えてください。
snake207

2018/10/31 08:33

変更例を追記していただき、ありがとうございます。 こちらを参考にプログラムを書き直したいと思います。
guest

0

  1. 映像にラインを引き、
  2. 検出した物体(ボール)が重なったら、
  3. USB端子に繋いでいるスピーカーから音を鳴らすにはどうしたらいいですか?

3はググったらすぐ出てきそうなのでいいとして、1, 2 についてです。ボールの位置が検出できるのであれば、その速度差から地面(orその他何か)にぶつかったかどうか判断することができそうですが。いかがでしょう。

投稿2018/10/27 01:49

編集2018/10/27 01:58
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

snake207

2018/10/27 03:03

急激に速度が変化したところを地面にぶつかったと判断するという事でしょうか?
退会済みユーザー

退会済みユーザー

2018/10/27 03:10

そうです(画像処理の知識はあまりないので参考になるかわかりませんが…)。
snake207

2018/10/27 09:01

一旦、その方向で考えてみようと思います。回答、ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問