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

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

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

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

Python 3.x

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

Q&A

解決済

1回答

4287閲覧

マウスでの座標取得がうまくいきません。

chachamaru0421

総合スコア17

OpenCV

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

Python 3.x

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

0グッド

0クリップ

投稿2019/01/08 06:07

編集2019/01/11 06:22

前提・実現したいこと

マウスで画像の座標を取得し、自動追跡するシステムを作っています。
追跡することはできたのですが、マウスで一回クリックして追跡する点を選択すると、なぜか一点ではなく複数点選択されているようで、クリックが10回未満で追跡を開始してしまいます。
きちんと一点ずつ選択できるようにしたいです。

該当のソースコード

python

1import cv2 2import numpy as np 3 4#フレーム数 5FRAME = 108 6frame = 2 7#インターバル 8INTERVAL = 30 9# 反復アルゴリズムの終了条件 10CRITERIA = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03) 11 12#マウスを用いた座標取得 13class mouseParam: 14 def __init__(self, input_img_name): 15 #マウス入力用のパラメータ 16 self.mouseEvent = {"x":None, "y":None, "event":None, "flags":None} 17 #マウス入力の設定 18 cv2.setMouseCallback(input_img_name, self.__CallBackFunc, None) 19 #コールバック関数 20 def __CallBackFunc(self, eventType, x, y, flags, userdata): 21 self.mouseEvent["x"] = x 22 self.mouseEvent["y"] = y 23 self.mouseEvent["event"] = eventType 24 self.mouseEvent["flags"] = flags 25 #マウス入力用のパラメータを返すための関数 26 def getData(self): 27 return self.mouseEvent 28 #マウスイベントを返す関数 29 def getEvent(self): 30 return self.mouseEvent["event"] 31 #マウスフラグを返す関数 32 def getFlags(self): 33 return self.mouseEvent["flags"] 34 #xの座標を返す関数 35 def getX(self): 36 return self.mouseEvent["x"] 37 #yの座標を返す関数 38 def getY(self): 39 return self.mouseEvent["y"] 40 #xとyの座標を返す関数 41 def getPos(self): 42 return (self.mouseEvent["x"], self.mouseEvent["y"]) 43 44#取得した座標から特徴点を取得する 45class Motion: 46 #コンストラクタ 47 def __init__(self): 48 #表示ウィンドウ(特徴点追跡用) 49 cv2.namedWindow("motion") 50 #表示ウィンドウ(特徴点指定用) 51 cv2.namedWindow("input window") 52 #インターバル 53 self.interval = INTERVAL 54 #現在のフレーム(カラー) 55 self.frame = None 56 #現在のフレーム(グレー) 57 self.gray_next = None 58 #前回のフレーム(グレー) 59 self.gray_prev = None 60 #特徴点 61 self.features = None 62 #特徴点のステータス 63 self.status = None 64 #特徴点のステータス(一番最初の画像で取得した特徴点) 65 self.status_src = None 66 #特徴点(一番最初の画像で取得した特徴点) 67 self.features_src = None 68 #メインループ 69 def run(self): 70 #最初のフレームの処理 71 self.frame = cv2.imread("IMG_1.tiff") 72 self.gray_prev = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY) 73 self.gray_next = cv2.cvtColor(self.frame,cv2.COLOR_BGR2GRAY) 74 #最初の特徴点10点を指定 75 cv2.imshow("input window",self.frame) 76 #コールバックの設定 77 mouseData = mouseParam("input window") 78 while 1: 79 cv2.waitKey(10) 80 #左クリックがあったら表示 81 if mouseData.getEvent() == cv2.EVENT_LBUTTONDOWN: 82 mouseData.getX() 83 mouseData.getY() 84 mouseData.getPos() 85 print(mouseData.getX()) 86 print(mouseData.getY()) 87 self.onMouse(mouseData.getX(),mouseData.getY(),mouseData.getPos()) 88 #右クリックがあったら終了 89 elif mouseData.getEvent() == cv2.EVENT_RBUTTONDOWN: 90 break; 91 #特徴点描画と10点の特徴点を取得 92 if self.features is not None: 93 if len(self.features) >= 10: 94 #オプティカルフローの計算 95 features_prev = self.features 96 #グレースケールに変換 97 self.gray_next = cv2.cvtColor(self.frame,cv2.COLOR_BGR2GRAY) 98 self.features, self.status, err = cv2.calcOpticalFlowPyrLK( \ 99 self.gray_prev, \ 100 self.gray_next, \ 101 features_prev, \ 102 None, \ 103 winSize = (10, 10), \ 104 maxLevel = 3, \ 105 criteria = CRITERIA, \ 106 flags = 0) 107 #有効な特徴点のみ残す 108 self.refreshFeatures() 109 if len(self.features) >= 10: 110 #最初の特徴点を格納しておく 111 self.status_src = self.status 112 self.features_src = self.features 113 print("特徴点10個取得出来ました") 114 break; 115 #画像毎の特徴点を抽出し、追跡する 116 for frame in range(2,FRAME): 117 #グレースケールに変換 118 self.gray_next = cv2.cvtColor(self.frame,cv2.COLOR_BGR2GRAY) 119 #self.gray_next = self.frame 120 #特徴点が登録されている場合にOpticalFlowを計算 121 if self.features is not None: 122 #オプティカルフローの計算 123 features_prev = self.features 124 self.features, self.status, err = cv2.calcOpticalFlowPyrLK( \ 125 self.gray_prev, \ 126 self.gray_next, \ 127 features_prev, \ 128 None, \ 129 winSize = (10, 10), \ 130 maxLevel = 3, \ 131 criteria = CRITERIA, \ 132 flags = 0) 133 #有効な特徴点のみ残す 134 self.refreshFeatures() 135 #フレームに有効な特徴点を描画 136 if self.features is not None: 137 for features in self.features: 138 cv2.circle(self.frame,(features[0][0],features[0][1]),2,(15,241,255),-1,8,0) 139 #表示 140 cv2.imshow("motion",self.frame) 141 #次のループ処理の準備 142 self.gray_prev = self.gray_next 143 #画像を読み込む 144 self.frame = cv2.imread("IMG_"+str(frame)+".tiff") 145 #インターバル 146 key = cv2.waitKey(self.interval) 147 #終了処理 148 cv2.destroyAllWindows() 149 #マウスクリックで特徴点を指定する 150 #クリックされた近傍に既存の特徴点がある場合は既存の特徴点を削除する 151 #クリックされた近傍に既存の特徴点がない場合は新規特徴点を追加する 152 def onMouse(self,x,y,XY): 153 #最初の特徴点追加 154 if self.features is None: 155 self.addFeature(x,y) 156 return 157 #クリック点がすでに取得済みの座標点であれば追加しない 158 for click in self.features: 159 #print(click) 160 if np.all(click == XY): 161 return 162 #探索半径(pixel) 163 radius = 5 164 #既存の特徴点が近傍にあるか探索 165 index = self.getFeatureIndex(x,y,radius) 166 #クリックされた近傍に既存の特徴点があるので既存の特徴点を削除する 167 if index >= 0: 168 self.features = np.delete(self.features, index,0) 169 self.status = np.delete(self.status,index,0) 170 #クリックされた近傍に既存の特徴点がないので新規に特徴点を追加する 171 else: 172 self.addFeature(x,y) 173 return 174 #指定した半径内にある既存の特徴点のインデックスを1つ取得する 175 #指定した半径内に特徴点がない場合 index = -1 を応答 176 def getFeatureIndex(self,x,y,radius): 177 index = -1 178 #特徴点が一つも登録されていない 179 if self.features is None: 180 print("features is None") 181 return index 182 max_r2 = radius ** 2 183 index = 0 184 for point in self.features: 185 dx = x - point[0][0] 186 dy = y - point[0][1] 187 r2 = dx ** 2 + dy ** 2 188 if r2 <= max_r2: 189 #この特徴点は指定された半径内 190 return index 191 else: 192 #この特徴点は指定された半径外 193 index += 1 194 #全ての特徴点が指定された半径の外側にある 195 print("feature is out of radius") 196 return -1 197 # 特徴点を新規に追加する 198 def addFeature(self, x, y): 199 # 特徴点が未登録 200 if self.features is None: 201 # ndarrayの作成し特徴点の座標を登録 202 self.features = np.array([[[x, y]]],np.float32) 203 self.status = np.array([1]) 204 # 特徴点を高精度化 205 cv2.cornerSubPix(self.gray_next, self.features, (10, 10), (-1, -1), CRITERIA) 206 # 特徴点を追加登録 207 else: 208 # 既存のndarrayの最後に特徴点の座標を追加 209 self.features = np.append(self.features, [[[x, y]]], axis = 0).astype(np.float32) 210 self.status = np.append(self.status, 1) 211 # 特徴点を高精度化 212 cv2.cornerSubPix(self.gray_next, self.features, (10, 10), (-1, -1), CRITERIA) 213 # 有効な特徴点のみ残す 214 def refreshFeatures(self): 215 # 特徴点が未登録 216 if self.features is None: 217 return 218 # 全statusをチェックする 219 i = 0 220 while i < len(self.features): 221 # 特徴点として認識できず 222 if self.status[i] == 0: 223 # 既存のndarrayから削除 224 self.features = np.delete(self.features, i, 0) 225 self.status = np.delete(self.status, i, 0) 226 i -= 1 227 i += 1 228 229if __name__ == '__main__': 230 Motion().run()

実行結果例

521
165
521
165
feature is out of radius
521
165
feature is out of radius
521
165
feature is out of radius
521
165
feature is out of radius
521
165
feature is out of radius
521
165
feature is out of radius
458
183
feature is out of radius
458
183
feature is out of radius
458
183
feature is out of radius
特徴点10個取得出来ました

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

Windows7 32bit
Python ver.3.7.1
OpenCV ver.3.4.3

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

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

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

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

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

can110

2019/01/10 08:12

同じクラス名が複数定義されていたり、クラス定義のみで実行部分がないなど第三者が動作を検証できないソースになっているようです。 現象が再現する完全で最小限のコードを提示すると回答得られるかもしれません。
chachamaru0421

2019/01/11 04:06

ご指摘ありがとうございます。 申し訳ないのですが、当人Pythonをよく分かっておらず、削れる部分が分かりません…。 jupyter notebook 5.7.0と、 spyder 3.3.2 で、動作確認済みです。
can110

2019/01/11 04:36

そもそもとして動作しないコードですので回答は難しいです。
chachamaru0421

2019/01/11 05:48

しつこくすみません。 FRAMEの数や画像名を変えても動きませんか? ちなみに、こちらのサイトを参考に組んでいます。 ○http://whitecat-student.hatenablog.com/entry/2016/11/09/225631 ○https://qiita.com/hitomatagi/items/3d8973f855e963c9d999
can110

2019/01/11 05:50

逆に確認してほしいのですが、提示されたソースコードをそのままコピーしてそちらの環境では動作しますか?
chachamaru0421

2019/01/11 06:02

大変失礼致しました。コピペをミスしていたようです。class Motion以下、これで動くかと思います。 #取得した座標から特徴点を取得する class Motion: #コンストラクタ def __init__(self): #表示ウィンドウ(特徴点追跡用) cv2.namedWindow("motion") #表示ウィンドウ(特徴点指定用) cv2.namedWindow("input window") #インターバル self.interval = INTERVAL #現在のフレーム(カラー) self.frame = None #現在のフレーム(グレー) self.gray_next = None #前回のフレーム(グレー) self.gray_prev = None #特徴点 self.features = None #特徴点のステータス self.status = None #特徴点のステータス(一番最初の画像で取得した特徴点) self.status_src = None #特徴点(一番最初の画像で取得した特徴点) self.features_src = None #メインループ def run(self): n = 1 #最初のフレームの処理 self.frame = cv2.imread("IMG_1.tiff") self.gray_prev = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY) self.gray_next = cv2.cvtColor(self.frame,cv2.COLOR_BGR2GRAY) #最初の特徴点10点を指定 cv2.imshow("input window",self.frame) #コールバックの設定 mouseData = mouseParam("input window") while 1: cv2.waitKey(10) #左クリックがあったら表示 if mouseData.getEvent() == cv2.EVENT_LBUTTONDOWN: mouseData.getX() mouseData.getY() mouseData.getPos() print(mouseData.getX()) print(mouseData.getY()) self.onMouse(mouseData.getX(),mouseData.getY(),mouseData.getPos()) #右クリックがあったら終了 elif mouseData.getEvent() == cv2.EVENT_RBUTTONDOWN: break; #特徴点描画と10点の特徴点を取得 if self.features is not None: if len(self.features) >= 10: #オプティカルフローの計算 features_prev = self.features #グレースケールに変換 self.gray_next = cv2.cvtColor(self.frame,cv2.COLOR_BGR2GRAY) self.features, self.status, err = cv2.calcOpticalFlowPyrLK( \ self.gray_prev, \ self.gray_next, \ features_prev, \ None, \ winSize = (10, 10), \ maxLevel = 3, \ criteria = CRITERIA, \ flags = 0) #有効な特徴点のみ残す self.refreshFeatures() if len(self.features) >= 10: #最初の特徴点を格納しておく self.status_src = self.status self.features_src = self.features print("特徴点10個取得出来ました") break; #画像毎の特徴点を抽出し、追跡する for frame in range(2,FRAME): #グレースケールに変換 self.gray_next = cv2.cvtColor(self.frame,cv2.COLOR_BGR2GRAY) #self.gray_next = self.frame #特徴点が登録されている場合にOpticalFlowを計算 if self.features is not None: #オプティカルフローの計算 features_prev = self.features self.features, self.status, err = cv2.calcOpticalFlowPyrLK( \ self.gray_prev, \ self.gray_next, \ features_prev, \ None, \ winSize = (10, 10), \ maxLevel = 3, \ criteria = CRITERIA, \ flags = 0) #有効な特徴点のみ残す self.refreshFeatures() #フレームに有効な特徴点を描画 if self.features is not None: for features in self.features: cv2.circle(self.frame,(features[0][0],features[0][1]),2,(15,241,255),-1,8,0) #表示 cv2.imshow("motion",self.frame) #次のループ処理の準備 self.gray_prev = self.gray_next #画像を読み込む self.frame = cv2.imread("IMG_"+str(frame)+".tiff") #インターバル key = cv2.waitKey(self.interval) #終了処理 cv2.destroyAllWindows() #マウスクリックで特徴点を指定する #クリックされた近傍に既存の特徴点がある場合は既存の特徴点を削除する #クリックされた近傍に既存の特徴点がない場合は新規特徴点を追加する def onMouse(self,x,y,XY): #最初の特徴点追加 if self.features is None: self.addFeature(x,y) return #クリック点がすでに取得済みの座標点であれば追加しない for click in self.features: #print(click) if np.all(click == XY): return #探索半径(pixel) radius = 5 #既存の特徴点が近傍にあるか探索 index = self.getFeatureIndex(x,y,radius) #クリックされた近傍に既存の特徴点があるので既存の特徴点を削除する if index >= 0: self.features = np.delete(self.features, index,0) self.status = np.delete(self.status,index,0) #クリックされた近傍に既存の特徴点がないので新規に特徴点を追加する else: self.addFeature(x,y) return #指定した半径内にある既存の特徴点のインデックスを1つ取得する #指定した半径内に特徴点がない場合 index = -1 を応答 def getFeatureIndex(self,x,y,radius): index = -1 #特徴点が一つも登録されていない if self.features is None: print("features is None") return index max_r2 = radius ** 2 index = 0 for point in self.features: dx = x - point[0][0] dy = y - point[0][1] r2 = dx ** 2 + dy ** 2 if r2 <= max_r2: #この特徴点は指定された半径内 return index else: #この特徴点は指定された半径外 index += 1 #全ての特徴点が指定された半径の外側にある print("feature is out of radius") return -1 # 特徴点を新規に追加する def addFeature(self, x, y): # 特徴点が未登録 if self.features is None: # ndarrayの作成し特徴点の座標を登録 self.features = np.array([[[x, y]]],np.float32) self.status = np.array([1]) # 特徴点を高精度化 cv2.cornerSubPix(self.gray_next, self.features, (10, 10), (-1, -1), CRITERIA) # 特徴点を追加登録 else: # 既存のndarrayの最後に特徴点の座標を追加 self.features = np.append(self.features, [[[x, y]]], axis = 0).astype(np.float32) self.status = np.append(self.status, 1) # 特徴点を高精度化 cv2.cornerSubPix(self.gray_next, self.features, (10, 10), (-1, -1), CRITERIA) # 有効な特徴点のみ残す def refreshFeatures(self): # 特徴点が未登録 if self.features is None: return # 全statusをチェックする i = 0 while i < len(self.features): # 特徴点として認識できず if self.status[i] == 0: # 既存のndarrayから削除 self.features = np.delete(self.features, i, 0) self.status = np.delete(self.status, i, 0) i -= 1 i += 1
can110

2019/01/11 06:06

インデントがなくなっています。質問本文のソースコードを修正ください。
guest

回答1

0

自己解決

解決していませんが、別で再度質問をさせていただきました。

投稿2019/01/16 05:24

chachamaru0421

総合スコア17

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問