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

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

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

Raspbianは、DebianベースのRaspberry Pi用ディストリビューション。ハードウェア浮動小数点演算を有効にすることが可能で、Webブラウズなどの速度を向上できます。

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

解決済

1回答

2718閲覧

選択した領域内にボールが落ちたかを判断したい

snake207

総合スコア13

Raspbian

Raspbianは、DebianベースのRaspberry Pi用ディストリビューション。ハードウェア浮動小数点演算を有効にすることが可能で、Webブラウズなどの速度を向上できます。

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グッド

0クリップ

投稿2018/09/08 05:16

編集2018/09/13 12:10

やりたいこと

動画からボールの軌道を抽出するプログラムと
動画上にマウスで領域の4隅を選択すると線が引かれて領域を囲む
プログラムを作成した。
この2つのプログラムを組み合わせ、領域を選択してからボールの軌道を抽出する
プログラムを作成したい。

発生したエラー

Traceback (most recent call last):
File "test.py",line 141, in <module>
plist.run()
File "test.py",line 100, in run
color_diff = cv2.absdiff(self.frame_next, self.frame_pre)   #フレーム間の差分
AttributeError: 'PointList' object has no attribute 'frame_next'

Python

1# -*- coding: utf-8 -*- 2import cv2 3import sys 4import numpy as np 5 6 7VIDEO_DATE = "/home/pi/テニスコート撮影/tennis.AVI" 8WINDOW_NAME = "MouseEvent" 9 10def dilation(dilationSize, kernelSize, img): # 膨張した画像にして返す 11 kernel = np.ones((kernelSize, kernelSize), np.uint8) 12 element = cv2.getStructuringElement( 13 cv2.MORPH_RECT, (2 * dilationSize + 1, 2 * dilationSize + 1), (dilationSize, dilationSize)) 14 dilation_img = cv2.dilate(img, kernel, element) 15 return dilation_img 16 17 18def detect(gray_diff, thresh_diff=95, dilationSize=9, kernelSize=20): # 一定面積以上の物体を検出 19 retval, black_diff = cv2.threshold( 20 gray_diff, thresh_diff, 255, cv2.THRESH_BINARY) # 2値化 21 dilation_img = dilation(dilationSize, kernelSize, black_diff) # 膨張処理 22 img = dilation_img.copy() 23 image, contours, hierarchy = cv2.findContours( 24 dilation_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 境界線検出 25 26 ball_pos = [] 27 28 for i in range(len(contours)): # 重心位置を計算 29 count = len(contours[i]) 30 area = cv2.contourArea(contours[i]) # 面積計算 31 x, y = 0.0, 0.0 32 for j in range(count): 33 x += contours[i][j][0][0] 34 y += contours[i][j][0][1] 35 36 x /= count 37 y /= count 38 x = int(x) 39 y = int(y) 40 ball_pos.append([x, y]) 41 42 return ball_pos, img 43 44 45def displayCircle(image, ballList, thickness=5): 46 for i in range(len(ballList)): 47 x = int(ballList[i][0]) 48 y = int(ballList[i][1]) 49 cv2.circle(image, (x, y), 10, (0, 0, 255), thickness) 50 return image 51 52 53def resizeImage(image, w=2, h=2): 54 height = image.shape[0] 55 width = image.shape[1] 56 resizedImage = cv2.resize(image, (int(width / w), int(height / h))) 57 return resizedImage 58 59 60def blackToColor(bImage): 61 colorImage = np.array((bImage, bImage, bImage)) 62 colorImage = colorImage.transpose(1, 2, 0) 63 return colorImage 64 65class PointList(): 66 def __init__(self, npoints): 67 self.video = cv2.VideoCapture(VIDEO_DATE) 68 self.frame = None 69 self.npoints = npoints 70 self.ptlist = np.empty((npoints, 2), dtype=int) 71 self.pos = 0 72 cv2.setMouseCallback(WINDOW_NAME, self.onMouse) 73 74 def add(self, x, y): 75 if self.pos < self.npoints: 76 self.ptlist[self.pos, :] = [x, y] 77 self.pos += 1 78 return True 79 return False 80 81 def run(self): 82 while(self.video.isOpened()): 83 end_flag, self.frame = self.video.read() 84 if not end_flag: # EOF 85 break 86 self.frame_pre = self.frame.copy() 87 88 if(self.pos == self.npoints): 89 # コメントアウト 90 #print(self.ptlist) 91 cv2.line(self.frame, (self.ptlist[0][0], self.ptlist[0][1]), 92 (self.ptlist[1][0], self.ptlist[1][1]), (0, 255, 0), 3) 93 cv2.line(self.frame, (self.ptlist[1][0], self.ptlist[1][1]), 94 (self.ptlist[2][0], self.ptlist[2][1]), (0, 255, 0), 3) 95 cv2.line(self.frame, (self.ptlist[2][0], self.ptlist[2][1]), 96 (self.ptlist[3][0], self.ptlist[3][1]), (0, 255, 0), 3) 97 cv2.line(self.frame, (self.ptlist[3][0], self.ptlist[3][1]), 98 (self.ptlist[0][0], self.ptlist[0][1]), (0, 255, 0), 3) 99 100 color_diff = cv2.absdiff(self.frame_next, self.frame_pre) # フレーム間の差分計算 101 gray_diff = cv2.cvtColor(color_diff, cv2.COLOR_BGR2GRAY) # グレースケール変換 102 retval, black_diff = cv2.threshold(gray_diff,30, 255, cv2.THRESH_BINARY) 103 104 ball, dilation_img = detect(gray_diff) 105 106 self.frame = displayCircle(self.frame, ball, 2) # 丸で加工 107 cImage = blackToColor(dilation_img) # 2値化画像をカラーの配列サイズと同じにする 108 im1 = resizeImage(frame, 2, 2) 109 im2 = resizeImage(cImage, 2, 2) 110 im_h = cv2.hconcat([im1, im2]) # 画像を横方向に連結 111 112 cv2.imshow("Tracking", im_h) # フレームを画面表示 113 out.write(im_h) 114 115 self.frame_pre = self.frame_next.copy() # 次のフレームの読み込み 116 117 cv2.imshow(WINDOW_NAME, self.frame) 118 if cv2.waitKey(10) ==27: # Escキーで抜ける 119 break 120 121 def onMouse(self,event, x, y, flag, params): 122 if event == cv2.EVENT_MOUSEMOVE: # マウスが移動したときにx線とy線を更新する 123 self.frame2 = np.copy(self.frame) 124 h, w = self.frame2.shape[0], self.frame2.shape[1] 125 cv2.line(self.frame2, (x, 0), (x, h - 1), (255, 0, 0)) 126 cv2.line(self.frame2, (0, y), (w - 1, y), (255, 0, 0)) 127 cv2.imshow(WINDOW_NAME, self.frame2) 128 129 if event == cv2.EVENT_LBUTTONDOWN: # レフトボタンをクリックしたとき、ptlist配列にx,y座標を格納する 130 if self.add(x, y): 131 print('[%d] ( %d, %d )' % (ptlist.pos - 1, x, y)) 132 cv2.circle(self.frame, (x, y), 3, (0, 0, 255), 3) 133 cv2.imshow(WINDOW_NAME, self.frame) 134 else: 135 print('All points have selected. Press ESC-key.') 136 137if __name__ == '__main__': 138 cv2.namedWindow(WINDOW_NAME) 139 npoints = 4 140 ptlist = PointList(npoints) 141 ptlist.run() 142

質問内容

・エラーの原因は何なのか?
・元の2つのプログラムを組み合わせるにはどうしたらいいか?

下記にプログラム作成に参考したプログラムとサイトページのリンクを載せます。
回答の参考にしてください。

マウスで領域選択(元のプログラム)

リンク内容

ボール軌道抽出(元のプログラム)

Python

1import cv2 2import sys 3import numpy as np 4 5 6def dilation(dilationSize, kernelSize, img): # 膨張した画像にして返す 7 kernel = np.ones((kernelSize, kernelSize), np.uint8) 8 element = cv2.getStructuringElement( 9 cv2.MORPH_RECT, (2 * dilationSize + 1, 2 * dilationSize + 1), (dilationSize, dilationSize)) 10 dilation_img = cv2.dilate(img, kernel, element) 11 return dilation_img 12 13 14def detect(gray_diff, thresh_diff=30, dilationSize=9, kernelSize=20): # 一定面積以上の物体を検出 15 retval, black_diff = cv2.threshold( 16 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( 20 dilation_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 境界線検出 21 22 ball_pos = [] 23 24 for i in range(len(contours)): # 重心位置を計算 25 count = len(contours[i]) 26 area = cv2.contourArea(contours[i]) # 面積計算 27 x, y = 0.0, 0.0 28 for j in range(count): 29 x += contours[i][j][0][0] 30 y += contours[i][j][0][1] 31 32 x /= count 33 y /= count 34 x = int(x) 35 y = int(y) 36 ball_pos.append([x, y]) 37 38 return ball_pos, img 39 40 41def displayCircle(image, ballList, thickness=5): 42 for i in range(len(ballList)): 43 x = int(ballList[i][0]) 44 y = int(ballList[i][1]) 45 cv2.circle(image, (x, y), 10, (0, 0, 255), thickness) 46 return image 47 48 49def resizeImage(image, w=2, h=2): 50 height = image.shape[0] 51 width = image.shape[1] 52 resizedImage = cv2.resize(image, (int(width / w), int(height / h))) 53 return resizedImage 54 55 56def blackToColor(bImage): 57 colorImage = np.array((bImage, bImage, bImage)) 58 colorImage = colorImage.transpose(1, 2, 0) 59 return colorImage 60 61 62def run(input_video_path, output_video_path): 63 video = cv2.VideoCapture(input_video_path) # videoファイルを読み込む 64 # fourcc = cv2.VideoWriter_fourcc(*'MJPG') 65 fourcc = cv2.VideoWriter_fourcc(*'XVID') 66 67 if not video.isOpened(): # ファイルがオープンできない場合の処理. 68 print("Could not open video") 69 sys.exit() 70 71 vidw = video.get(cv2.CAP_PROP_FRAME_WIDTH) 72 vidh = video.get(cv2.CAP_PROP_FRAME_HEIGHT) 73 out = cv2.VideoWriter(output_video_path, fourcc, 20.0, 74 (int(vidw), int(vidh))) # 出力先のファイルを開く 75 76 ok, frame = video.read() # 最初のフレームを読み込む 77 if not ok: 78 print('Cannot read video file') 79 sys.exit() 80 81 frame_pre = frame.copy() 82 83 while True: 84 ok, frame = video.read() # フレームを読み込む 85 if not ok: 86 break 87 frame_next = frame.copy() 88 89 color_diff = cv2.absdiff(frame_next, frame_pre) # フレーム間の差分計算 90 gray_diff = cv2.cvtColor(color_diff, cv2.COLOR_BGR2GRAY) # グレースケール変換 91 retval, black_diff = cv2.threshold( 92 gray_diff, 30, 255, cv2.THRESH_BINARY) 93 94 ball, dilation_img = detect(gray_diff) 95 96 frame = displayCircle(frame, ball, 2) # 丸で加工 97 cImage = blackToColor(dilation_img) # 2値化画像をカラーの配列サイズと同じにする 98 im1 = resizeImage(frame, 2, 2) 99 im2 = resizeImage(cImage, 2, 2) 100 im_h = cv2.hconcat([im1, im2]) # 画像を横方向に連結 101 102 cv2.imshow("Tracking", im_h) # フレームを画面表示 103 out.write(im_h) 104 105 frame_pre = frame_next.copy() # 次のフレームの読み込み 106 107 k = cv2.waitKey(1) & 0xff # ESCを押したら中止 108 if k == 27: 109 break 110 111 video.release() 112 out.release() 113 cv2.destroyAllWindows() 114 115 116if __name__ == '__main__': 117 inputFile="tennis.avi" 118 outputFile="output.mp4" 119 run(inputFile, outputFile)

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

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

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

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

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

hayataka2049

2018/09/08 05:19

まとめたプログラムを掲載し、できる範囲で自分でデバッグしてみた結果わかったことも書いてください
umyu

2018/09/08 07:43 編集

まとめたプログラムは定義はありますが、PointList#runの呼び出し部分がありません。転記漏れでしょうか?
snake207

2018/09/08 09:07 編集

すいません、追加しときます。
guest

回答1

0

ベストアンサー

エラーの原因について

AttributeError: 'PointList' object has no attribute 'frame_next'

PointList オブジェクトの frame_next という attribute を 100行目で参照しようとしたけど、そんなのないよというエラーです。

この時点で self.frame_next は定義されていない。
どこかから持ってきたコードだとしたら、移植が不十分になっています。

color_diff = cv2.absdiff(self.frame_next, self.frame_pre)

やりたいことに関して

  • 動画からボールの軌道を抽出するプログラム
  • 動画上にマウスで領域の4隅を選択すると線が引かれて領域を囲むプログラム

ソースを見ました。意図として

  1. フレーム間背景差分をとる。
  2. 差分があった (つまり、動いたもの) はボールと判定して、検出する。
  3. 検出対象の領域は、マウスで選択した矩形内にしたい

ということですね。
とりあえず、一度にやろうとするのではなく、以下のように1つずつ完成させて繋ぎこむほうがよいと思います。
一度にやろうとすると、どこかで問題があったときなにが原因かわかりづらくなるので。

  • フレーム間背景差分を表示するプログラム
  • マウスで選択した4隅から矩形を設定するプログラム
  • 背景差分の結果からボールを検出するプログラム

投稿2018/09/14 17:55

tiitoi

総合スコア21956

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

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

snake207

2018/09/15 07:33 編集

回答、ありがとうございます。 アドバイス頂いたように、一つずつ 作成していこうと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問