前提・実現したいこと
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
回答2件
あなたの回答
tips
プレビュー