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

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

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

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

OpenCV

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

Python 3.x

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

Q&A

解決済

2回答

2310閲覧

OpenCVを用いて、マウスで画像の座標を取り自動追跡し、csvファイルに正しく出力したい

chachamaru0421

総合スコア17

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

OpenCV

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

Python 3.x

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

0グッド

0クリップ

投稿2019/01/16 05:23

編集2019/01/18 03:12

前提・実現したいこと

100枚ほどの画像を使って特徴点の追跡を行い、追跡した座標をcsvファイルに出力することを目標としています。現在出力はできているのですが、出力される座標がおかしく、その原因が分からず困っています。

該当のソースコード

Python

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

出力例

540     151
460.95853 176.9362
460.95853 176.9362
460.95853 176.9362
460.95853 176.9362
460.95853 176.9362
460.95853 176.9362
433     212
429     404
642.06934 356.36328
642.06934 356.36328
642.06934 356.36328
642.0694 356.36325
642.0698 356.3633
629     223

6点取ったのですが、たくさん出力されてしまいます。

補足情報

Windows7 32bit
Python 3.7.1
OpenCV 3.4.3

参考にしたサイト

https://qiita.com/hitomatagi/items/3d8973f855e963c9d999
http://whitecat-student.hatenablog.com/entry/2016/11/09/225631

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

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

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

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

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

stdio

2019/01/16 05:38

出力される座標がおかしいとありますが、どのようにおかしいのですか? デバックを他人に丸投げするのはここでは禁止されていますが、 出力を拝見する限り、何もおかしい様に見えませんが... どの辺がおかしいと思うのですか?
chachamaru0421

2019/01/16 05:44

ここでは、6点だけ点を取りました。なので、座標も取った点と同じ数(6行)だけ出力されて欲しいのですが、15行も出力されてしまいます。 伝えるのが下手で申し訳ないですが、伝わりましたら幸いです。
stdio

2019/01/16 05:57

機械学習系ですので、お使いになられているAPIの仕様を詳しく調べた方が良い気がします。 配列の数が6以下か6以上を判定して、出力しないようにすればいいのでは? 余談ですが、 タイトルが「マウスで画像の座標を取り、csvファイルに出力したい」ですので、 機械学習系ならそうと教えて頂きたいものです。かなり誤解を生む書き方していますよ。
Takaya901

2019/01/16 08:04

保存された画像には6点のみ描画されていますか?
chachamaru0421

2019/01/16 08:24 編集

stdioさん> ご助言ありがとうございます。 6以上などの判定を加えると、これで言えば 540     151 460.95853 176.9362 460.95853 176.9362 460.95853 176.9362 460.95853 176.9362 460.95853 176.9362 となってしまい、2点しか取っていないのに、6点取ったと判定してしまうようです。 Takaya901さん> 画像には6点のみ表示されています。
Takaya901

2019/01/16 08:38

self.featuresの中身はおそらく正しいようなので(一応printして確認したほうがいいかもしれません),csv書き込み時の問題でしょうか. 540 151などの整数の組が正しい座標のように見えます(5組しかありませんが)が,画像に描画されているのはこの5点でしょうか.cv2.imshowで表示するなりペイントで開くなりするとマウスで確認できると思います.
chachamaru0421

2019/01/17 03:25

Takaya901さん> ご助言ありがとうございます。上記の点とは取った座標が異なりますが、printしてみたところ、以下のようになりました。(長くて見づらく、申し訳ないです。) 一点目 [[[538. 149.]]] 2点目 feature is out of radius [[[538. 149. ]] [[460.96143 176.93602]]] feature is out of radius [[[538. 149. ]] [[460.9589 176.93573]] [[460.96143 176.93602]]] 3点目 feature is out of radius [[[538. 149. ]] [[460.95856 176.93594]] [[460.9589 176.93573]] [[421.9548 333.7005 ]]] feature is out of radius [[[538. 149. ]] [[460.95853 176.9361 ]] [[460.95856 176.93594]] [[421.9509 333.70065]] [[421.9548 333.7005 ]]] feature is out of radius [[[538. 149. ]] [[460.95853 176.93616]] [[460.95853 176.9361 ]] [[421.94885 333.7005 ]] [[421.9509 333.70065]] [[421.9548 333.7005 ]]] 4点目 feature is out of radius [[[538. 149. ]] [[460.95853 176.93619]] [[460.95853 176.93616]] [[421.94775 333.70044]] [[421.94885 333.7005 ]] [[421.9509 333.70065]] [[414.54623 418.25998]]] feature is out of radius [[[538. 149. ]] [[460.95853 176.9362 ]] [[460.95853 176.93619]] [[421.94714 333.70038]] [[421.94775 333.70044]] [[421.94885 333.7005 ]] [[414.53958 418.26166]] [[414.54623 418.25998]]] feature is out of radius [[[538. 149. ]] [[460.95853 176.9362 ]] [[460.95853 176.9362 ]] [[421.94684 333.70035]] [[421.94714 333.70038]] [[421.94775 333.70044]] [[414.53778 418.26212]] [[414.53958 418.26166]] [[414.54623 418.25998]]] 5点目 feature is out of radius [[[538. 149. ]] [[460.95853 176.9362 ]] [[460.95853 176.9362 ]] [[421.94666 333.70035]] [[421.94684 333.70035]] [[421.94714 333.70038]] [[414.5373 418.26224]] [[414.53778 418.26212]] [[414.53958 418.26166]] [[611. 286. ]]] 6点目 feature is out of radius [[[538. 149. ]] [[460.95853 176.9362 ]] [[460.95853 176.9362 ] [[421.94656 333.70035]] [[421.94666 333.70035]] [[421.94684 333.70035]] [[414.53717 418.26227]] [[414.5373 418.26224]] [[414.53778 418.26212]] [[611. 286. ]] [[627. 224. ]]] csvファイルへの出力は6点目のときのprint文と同様でした。 また、ペイントで画像に描写された点の座標を確認したところ、 538 149 460 176 421 333 414 418 611 286 627 224 であったため、正しく描写されていると思われます。
guest

回答2

0

自己解決

cv2.cornerSubPixをコメントアウトしたら、よくわかりませんができました。
Takaya901さん、たくさん相談に乗ってくださりありがとうございました。

投稿2019/01/28 02:25

chachamaru0421

総合スコア17

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

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

0

座標が小数なのはcornerSubPixしているからなんですね.見落としていました.

1回のクリックで'feature is out of radius'が複数回printされているということは,onMouseがクリックしている間,つまり左ボタンが押されている間呼ばれ続けているのかもしれません.クリックではなく長押ししてみて大量にfeaturesが追加されるか,EVENT_LBUTTONDOWNをEVENT_LBUTTONUPに変えたらどうなるかなど試してみてはどうでしょうか.

余談ですが,OpenCVによるオプティカルフローの計算は機械学習ではないと思います.画像処理のアルゴリズムの1つなので.

#追記1
以下のように,ボタンが離されるまで次のループに行かないようにするとどうでしょう.

python

1if mouseData.getEvent() == cv2.EVENT_LBUTTONDOWN: 2 mouseData.getX() 3 mouseData.getY() 4 mouseData.getPos() 5 print(mouseData.getX()) 6 print(mouseData.getY()) 7 self.onMouse(mouseData.getX(),mouseData.getY(),mouseData.getPos()) 8 while mouseData.getEvent() != cv2.EVENT_LBUTTONUP: 9 #または, while mouseData.getEvent() == cv2.EVENT_LBUTTONDOWN: 10 continue

#追記2
失礼しました。
getFeatureIndexが正しく機能していればonMouseが複数回呼ばれても大丈夫なはずなので、そこを見直して見てください。

投稿2019/01/17 05:51

編集2019/01/18 03:16
Takaya901

総合スコア181

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

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

chachamaru0421

2019/01/17 06:59

Takaya901さんの仰る通り、長押ししている間じゅう呼ばれていました!気付かせてくださり、ありがとうございます。 EVENT_LBUTTONUPで上手く動きそうに見えるのですが、そうすると無反応になってしまいました。連打しているとたまに反応しますが、feature is out of radiusが大量に出てきます。 甘えてばかりで申し訳ありませんが、何か思い当ることがあれば、教えていただけると幸いです。
chachamaru0421

2019/01/18 03:23 編集

お力添え、本当に感謝致します。 上記の文を加えてみたところ、1点目を選択するためにクリックすると、座標はprintされましたが、それ以降プログラムが停止してしまいました…。
chachamaru0421

2019/01/18 04:12

すみません。つまり、getFeatureIndexに問題があるということでしょうか。
Takaya901

2019/01/18 04:27

私も詳しく見れていませんが,もしかしたらそうかもしれません
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問