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

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コンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Q&A

解決済

1回答

4573閲覧

動画ファイルを読み取り、マウスイベントで領域を選択する方法は?

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コンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

0グッド

0クリップ

投稿2018/08/22 05:55

編集2018/08/22 06:46

前提・実現したいこと

動画ファイルを読み取り、マウスイベントで領域を選択するというプログラムを作っています。
作成中に以下のエラーメッセージが発生しました。

発生している問題・エラーメッセージ

Traceback (most recent call last): File "tennis_line.py", line 66, in <module> cv2.setMouseCallback(wname, onMouse, [wname, self.frame, ptlist]) NameError: name 'self' is not defined

プログラム

python

1import numpy as np 2import cv2 3 4 5VIDEO_DATE = 'tennis.AVI' 6 7 8class PointList(): 9 def __init__(self, npoints): 10     self.video = cv2.VideoCapture(VIDEO_DATE) 11 self.frame = None 12 self.npoints = npoints 13 self.ptlist = np.empty((npoints, 2), dtype=int) 14 self.pos = 0 15 16 def add(self, x, y): 17 if self.pos < self.npoints: 18 self.ptlist[self.pos, :] = [x, y] 19 self.pos += 1 20 return True 21 return False 22 23 def run(self): 24 while(self.video.isOpened()): 25 26    end_flag,selt.frame = self.video.read() 27 28def onMouse(self,event, x, y, flag, params): 29 wname, self.frame, ptlist = params 30 if event == cv2.EVENT_MOUSEMOVE: # マウスが移動したときにx線とy線を更新する 31 self.frame2 = np.copy(self.frame) 32 h, w = self.frame2.shape[0], self.frame2.shape[1] 33 cv2.line(self.frame2, (x, 0), (x, h - 1), (255, 0, 0)) 34 cv2.line(self.frame2, (0, y), (w - 1, y), (255, 0, 0)) 35 cv2.imshow(wname, self.frame2) 36 37 if event == cv2.EVENT_LBUTTONDOWN: # レフトボタンをクリックしたとき、ptlist配列にx,y座標を格納する 38 if ptlist.add(x, y): 39 print('[%d] ( %d, %d )' % (ptlist.pos - 1, x, y)) 40 cv2.circle(self.frame, (x, y), 3, (0, 0, 255), 3) 41 cv2.imshow(wname, self.frame) 42 else: 43 print('All points have selected. Press ESC-key.') 44 if(ptlist.pos == ptlist.npoints): 45 print(ptlist.ptlist) 46 cv2.line(self.frame, (ptlist.ptlist[0][0], ptlist.ptlist[0][1]), 47 (ptlist.ptlist[1][0], ptlist.ptlist[1][1]), (0, 255, 0), 3) 48 cv2.line(self.frame, (ptlist.ptlist[1][0], ptlist.ptlist[1][1]), 49 (ptlist.ptlist[2][0], ptlist.ptlist[2][1]), (0, 255, 0), 3) 50 cv2.line(self.frame, (ptlist.ptlist[2][0], ptlist.ptlist[2][1]), 51 (ptlist.ptlist[3][0], ptlist.ptlist[3][1]), (0, 255, 0), 3) 52 cv2.line(self.frame, (ptlist.ptlist[3][0], ptlist.ptlist[3][1]), 53 (ptlist.ptlist[0][0], ptlist.ptlist[0][1]), (0, 255, 0), 3) 54 55 56if __name__ == '__main__': 57 wname = "MouseEvent" 58 cv2.namedWindow(wname) 59 npoints = 4 60 ptlist = PointList(npoints) 61  cv2.setMouseCallback(wname, onMouse, [wname, self.frame, ptlist]) 62  cv2.imshow(wname, self.frame) 63  cv2.waitKey() 64  cv2.destroyAllWindows()

参考サイト

https://qiita.com/otakoma/items/04e525ac74b7191dffe6
https://qiita.com/hitomatagi/items/3d8973f855e963c9d999

補足情報(FW/ツールのバージョンなど)

Python3.5.3\Opencv3.4.1\Raspberry Pi3 Model B++

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

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

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

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

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

hayataka2049

2018/08/22 06:18 編集

プログラムの部分をコードブロックで囲んでください。あと、エラーは省略せず全文掲載してください(出た行数などがわかるように)
guest

回答1

0

ベストアンサー

質問文の追記ありがとございます。


NameError: name 'self' is not defined

Google翻訳
NameError:name 'self'は定義されていません

エラーメッセージの直訳は変数:selfが宣言されていなからです。

Python

1ptlist = PointList(npoints) 2cv2.setMouseCallback(wname, onMouse, [wname, ptlist.frame, ptlist])

実行時エラーを無くすには関連する部分を上記コードに変更すれば良いのですが。


質問タイトルのやりたい事はこれでは満たせないので、
修正版サンプルコードを参考情報として置いておきます。
どういう点を修正したのかをコードの差分比較ツールで確認して見てくださいな。

Python

1# -*- coding: utf-8 -*- 2import numpy as np 3import cv2 4 5 6VIDEO_DATE = 'tennis.AVI' 7WINDOW_NAME = "MouseEvent" 8 9 10class PointList(): 11 def __init__(self, npoints): 12 self.video = cv2.VideoCapture(VIDEO_DATE) 13 self.frame = None 14 self.npoints = npoints 15 self.ptlist = np.empty((npoints, 2), dtype=int) 16 self.pos = 0 17 cv2.setMouseCallback(WINDOW_NAME, self.onMouse) 18 19 def add(self, x, y): 20 if self.pos < self.npoints: 21 self.ptlist[self.pos, :] = [x, y] 22 self.pos += 1 23 return True 24 return False 25 26 def run(self): 27 while(self.video.isOpened()): 28 end_flag, self.frame = self.video.read() 29 if not end_flag: # EOF 30 break 31 if(self.pos == self.npoints): 32 # コメントアウト 33 #print(self.ptlist) 34 cv2.line(self.frame, (self.ptlist[0][0], self.ptlist[0][1]), 35 (self.ptlist[1][0], self.ptlist[1][1]), (0, 255, 0), 3) 36 cv2.line(self.frame, (self.ptlist[1][0], self.ptlist[1][1]), 37 (self.ptlist[2][0], self.ptlist[2][1]), (0, 255, 0), 3) 38 cv2.line(self.frame, (self.ptlist[2][0], self.ptlist[2][1]), 39 (self.ptlist[3][0], self.ptlist[3][1]), (0, 255, 0), 3) 40 cv2.line(self.frame, (self.ptlist[3][0], self.ptlist[3][1]), 41 (self.ptlist[0][0], self.ptlist[0][1]), (0, 255, 0), 3) 42 cv2.imshow(WINDOW_NAME, self.frame) 43 if cv2.waitKey(10) ==27: # Escキーで抜ける 44 break 45 46 def onMouse(self,event, x, y, flag, params): 47 if event == cv2.EVENT_MOUSEMOVE: # マウスが移動したときにx線とy線を更新する 48 self.frame2 = np.copy(self.frame) 49 h, w = self.frame2.shape[0], self.frame2.shape[1] 50 cv2.line(self.frame2, (x, 0), (x, h - 1), (255, 0, 0)) 51 cv2.line(self.frame2, (0, y), (w - 1, y), (255, 0, 0)) 52 cv2.imshow(WINDOW_NAME, self.frame2) 53 54 if event == cv2.EVENT_LBUTTONDOWN: # レフトボタンをクリックしたとき、ptlist配列にx,y座標を格納する 55 if self.add(x, y): 56 print('[%d] ( %d, %d )' % (ptlist.pos - 1, x, y)) 57 cv2.circle(self.frame, (x, y), 3, (0, 0, 255), 3) 58 cv2.imshow(WINDOW_NAME, self.frame) 59 else: 60 print('All points have selected. Press ESC-key.') 61 62 63if __name__ == '__main__': 64 cv2.namedWindow(WINDOW_NAME) 65 npoints = 4 66 ptlist = PointList(npoints) 67 ptlist.run() 68 cv2.destroyAllWindows() 69

投稿2018/08/22 08:34

編集2018/08/22 19:21
umyu

総合スコア5846

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

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

snake207

2018/08/22 08:56

回答、ありがとうございます。 実行してみると、選択した座標は出ますが線が出ないため、綺麗に選択する事ができませんでした。 どうすれば、線(枠)が引かれた状態で動画を表示させるか考えたいと思います。 そのために何か、案がございましたら教えていただけると幸いです。
umyu

2018/08/22 09:03

@snake207さんへ この部分にcv2.imshowがいるような気も。 ←
umyu

2018/08/22 09:06

要するにー cv2.lineを実行したあとにcv2.imshowですよね。同じようにcv2.imshowがいるのではという指摘コメントです。
snake207

2018/08/22 09:07

そこにcv2.imshowを入れてみましたが、ダメでした。画像とは違い、動画は1フレームごとなので選択した座標で枠を表示させるのは難しいんでしょうか?
umyu

2018/08/22 09:12 編集

あと、マウスイベント側は座標だけを持って、run内で、表示するという形にしてみてはー ちょーと、理想的なイメージみたいなのが質問文からは読み取れなかったので。質問文のコードを踏襲する形になりましたが、本質的にはマウスイベント内で描画処理(cv2.lineとcv2.circleとcv2.imshow)は避けたほうが無難です
snake207

2018/08/22 09:13

run内で選択した座標の点を表示させるということですか?
umyu

2018/08/22 09:13

そーです。
snake207

2018/08/22 09:17 編集

分かりました。 貴重なご意見ありがとうございます。 参考にさせていただきます。
umyu

2018/08/22 09:21

@snake207さんへ 回答を変更しました、ご参考まで
umyu

2018/08/22 09:22

クリック時に途中の線を表示したい場合は、 self.ptlistをnumpy配列からやめて、リストにして、座標をtupleで格納してfor文で回すようにしてくださいな。
snake207

2018/08/22 10:03 編集

クリック時にも途中の線を表示したいのですが、 self.ptlistをnumpy配列からやめて、リストにして、座標をtupleで格納して for文で回す方法が分かりません。 よければ、教えていただける嬉しいです。
umyu

2018/08/22 10:33 編集

えっとぉー、このプログラムを改造するのではなく、listは分かりますか? listにtupleを格納するプログラムをまず作ってみてくださいな。 分かりませんではなく、質問するときのヒントを参考に https://teratail.com/help/question-tips 調べたことやってみたことをメモに書きながらプログラムを作成することをお勧めします。
snake207

2018/08/22 10:42 編集

分かりました。 自分で一度、プログラムを作成してみます。
umyu

2018/08/22 10:42

listはなんでも格納できるので、listの個々の要素がx,y座標のtupleということです。
snake207

2018/08/22 11:15

listにtupleを格納 list= [(5,6),7,8,9] この場合、5と6がtupleですよね?
snake207

2018/08/22 11:50 編集

numpy配列を使わないということは、import numpy as npがまずいらなくなりますよね? self.ptlistをリストにして座標をtupleで格納することで クリック時にも途中の線を表示できるようになるということですね。 ところで、リストの宣言はどこですればいいでしょうか? self.ptlist = [] ←初期化はこれでいいでしょうか?
umyu

2018/08/22 16:52 編集

1,import numpy as npの件 質問者さんがonMouseイベント内でnp.copy(self.frame)を書いてますよー。。 2,はい、そうです。あとはtupleに格納する部分がうまく実装できたら if(self.pos == self.npoints):文の条件を変更してfor文に変更ですねー。 for文の箇所は難易度が高めなので、答えを書きます。コードの▲はスペース代わりです。 if len(self.ptlist) > 1: ▲shift_lst = self.ptlist[1:] + [self.ptlist[0]] ▲for xy1, xy2 in zip(self.ptlist, shift_lst): ▲▲cv2.line(self.frame, xy1, xy2, (0, 255, 0), 3) 2,リストの初期化の件はそれでOKです。
snake207

2018/08/22 21:08

分かりました、ありがとうございます。回答での質問にも丁寧に答えていただき、非常に助かりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問