こんにちは、えんせきです。
何か処理するって記事を書いたけど、何も処理してなかったので画像の中のものをトラッキングすることにした。
つまりなにしたの?
Python+OpenCVのTracking手法のうちBoosting、MIL、KCF、TLD、MedianFlowの5つを実行してみた。
GOTURNもあるけどこっちはうまく動いていない。単純に学習済のモデルのダウンロードが終わっていない。
Trackingとは?
簡単に言うと、目で追い続けるのをコンピュータにやらせようって話。ただ、コンピュータは、画像のどの領域が何であるかとかものは落ちる時下に行くとか慣性の法則とかを知らないので人間が思うよりも難しい。
それを実現する画像処理の方法がOpenCVに6つ実装されている。
OpenCVで使えるTracking
Boosting
AdaBoostで動いている。分類器ベースで実行されていて、新しいフレームが来ると前の写っていた場所の近傍のすべてのピクセル上で分類を実行して、分類器のスコアから新しい場所を検出する
伝統的な手法だけど、今これを採用する理由はあんまりない。
MIL(Multiple Instance Learning)
考え方としてはBoostingにとても近いけど、分類対象の場所の近傍のサンプルについてもいくつか正の場所として扱うことが特徴。外堀が埋まってたら真ん中はトラッキング対象でしょうって感じで扱われているみたい。
ただ今更これを採用する理由もない。
KCF(Kernelized Correlation Filters)
カーネルだって!おらわくわくしてきたぞ!MILの近傍サンプルにはそれぞれ同士でオーバーラップする部分があって、その領域を加味することで性能を上げたらしい。
OpenCV3.1以降であればこれがおすすめ。
TLD(Tracking, learning and detection)
学習と検出によってトラッキングする。これまでに検出した範囲を学習してまた検出するみたい。性質上、似たような他のものとの入れ替わりには引っ張られたりすることがある。ただ、長い間遮られたりするものやスケールが大幅に変わるものには適しているっぽい。
MedianFlow
オブジェクトを時間的に順方向および逆方向の両方で追跡して、これらの軌跡間の差異を測定する。動きが小さくて、遮りがなくて、予測しやすい時(たとえばすごく引きで撮ってる時の車とか。。。)にはすごく向いている。
実行してみた結果
Webカメラがよしなに明るさを変更すると結構外れやすかったりする。
領域は広い方がトラッキングし続けてくれるけど、計算に時間がかかってFPSは落ちがち。
当たり前といえば当たり前だけど、検出するものの選択を自分でやらなければならない。
Yolo v2とかで矩形にしてからターゲットを選んでトラッキングするとかやりたくなる。
実装例
import cv2 def frame_resize(frame, n=2): """ スクリーンショットを撮りたい関係で1/4サイズに縮小 """ return cv2.resize(frame, (int(frame.shape[1]/2), int(frame.shape[0]/2))) if __name__ == '__main__': """ Tracking手法を選ぶ。適当にコメントアウトして実行する。 """ # Boosting # tracker = cv2.TrackerBoosting_create() # MIL # tracker = cv2.TrackerMIL_create() # KCF tracker = cv2.TrackerKCF_create() # TLD #GPUコンパイラのエラーが出ているっぽい # tracker = cv2.TrackerTLD_create() # MedianFlow # tracker = cv2.TrackerMedianFlow_create() # GOTURN # モデルが無いよって怒られた # https://github.com/opencv/opencv_contrib/issues/941#issuecomment-343384500 # https://github.com/Auron-X/GOTURN-Example # http://cs.stanford.edu/people/davheld/public/GOTURN/trained_model/tracker.caffemodel # tracker = cv2.TrackerGOTURN_create() cap = cv2.VideoCapture(1) while True: ret, frame = cap.read() if not ret: continue frame = frame_resize(frame) bbox = (0,0,10,10) bbox = cv2.selectROI(frame, False) ok = tracker.init(frame, bbox) cv2.destroyAllWindows() break while True: # VideoCaptureから1フレーム読み込む ret, frame = cap.read() frame = frame_resize(frame) if not ret: k = cv2.waitKey(1) if k == 27 : break continue # Start timer timer = cv2.getTickCount() # トラッカーをアップデートする track, bbox = tracker.update(frame) # FPSを計算する fps = cv2.getTickFrequency() / (cv2.getTickCount() - timer); # 検出した場所に四角を書く if track: # Tracking success p1 = (int(bbox[0]), int(bbox[1])) p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3])) cv2.rectangle(frame, p1, p2, (0,255,0), 2, 1) else : # トラッキングが外れたら警告を表示する cv2.putText(frame, "Failure", (10,50), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,255,0), 1, cv2.LINE_AA); # FPSを表示する cv2.putText(frame, "FPS : " + str(int(fps)), (10,20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,255,0), 1, cv2.LINE_AA); # 加工済の画像を表示する cv2.imshow("Tracking", frame) # キー入力を1ms待って、k が27(ESC)だったらBreakする k = cv2.waitKey(1) if k == 27 : break # キャプチャをリリースして、ウィンドウをすべて閉じる cap.release() cv2.destroyAllWindows()