ちょっとしたことから、すごく使えそうな気がしてきて、今更ながらmeanshiftで遊んでみた。
つまり、構想はこれでターゲット物体捕捉して、物体認識もして表示すれば単品だけど、使えるかなということ。
まずは、Roiできるかがポイント。
【参考】
とりあえず、まんまかもだけど、インスピレーションをもらえた
1.Raspberry Pi サーボモーターとOpen CVで物体追跡カメラ(Meanshift)
ソースは以下の記事を参考にさせていただきました。
2.Python3 OpenCV3を使って物体検出
コードは以下に置きました
Video-Stream / meanshift.py
現行版なので、本文と一部異なります。
環境
構築は、参考2のようにやればいいのね。
---以下参考2引用
pipでインストールしたモジュール一覧
gnureadline==6.3.3
ipython==3.1.0
matplotlib==1.4.3
nose==1.3.7
numpy==1.9.2
Pillow==2.9.0
pyparsing==2.0.3
python-dateutil==2.4.2
pytz==2015.4
scipy==0.16.0
six==1.9.0
sympy==0.7.6
requirements.txtに上記の一覧を記述して、
$ pip install -r requirements.txt
とすればOpenCV以外の同じ環境が構築できる。
---ここまで引用
とはいえ、今回はいじらずに行けました。
>pip list
Package Version
---------------------------------- -----------
ipython 5.1.0
matplotlib 2.2.2
nose 1.3.7
numpy 1.14.2
Pillow 3.3.1
pycparser 2.14
python-dateutil 2.5.3
pytz 2016.6.1
scipy 0.18.1
six 1.10.0
sympy 1.0
コードと工夫したこと
# -*- coding: utf-8 -*-
import numpy as np
import cv2
if __name__ == '__main__':
cap = cv2.VideoCapture(0)
# 追跡する枠の座標とサイズ
x = 600
y = 200
w = 200
h = 200
track_window = (x, y, w, h)
# フレームの取得
ret,frame = cap.read()
# 追跡する枠を決定
roi = frame[y:y+h, x:x+w]
# 追跡する枠の内部を切り抜いてHSV変換
hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
## マスク画像の生成
img_mask = cv2.inRange(hsv_roi, np.array((0., 60.,32.)), np.array((180.,255.,255.)))
## 正規化するためのヒストグラムの生成
roi_hist = cv2.calcHist([hsv_roi], [0], img_mask, [180], [0,180])
## ノルム正規化
cv2.normalize(roi_hist, roi_hist, 0, 255, cv2.NORM_MINMAX)
term_crit = ( cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1 )
while(True):
ret, frame = cap.read()
if ret == True:
# フレームをHSV変換する
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# 上で計算したヒストグラムを特徴量として、画像の類似度を求める
dst = cv2.calcBackProject([hsv],[0],roi_hist,[0,180], 1)
# 物体検出する
ret, track_window = cv2.meanShift(dst, track_window, term_crit)
#ret, track_window = cv2.CamShift(dst, track_window, term_crit)
# 物体検出で取得した座標を元のフレームで囲う
x,y,w,h = track_window
img_dst = cv2.rectangle(frame, (x,y), (x+w, y+h), 255, 2)
cv2.imshow('SHOW MEANSHIFT IMAGE', img_dst)
# qを押したら終了。
k = cv2.waitKey(1)
if k == ord('q'):
break
else:
break
#ret, track_window = cv2.CamShift(dst, track_window, term_crit)
はウワンが追記
【参考】
Meanshift と Camshift
これでも動くと思うが、ウワンのカメラだと初期動作が遅くて動いてくれなかった。
また、ターゲットを捕捉するのが難しくて、何度も失敗。
ということで、ターゲットを捕捉できるように以下の変更を加えた。
# 追跡する枠の座標とサイズ
x = 600
y = 200
w = 200
h = 200
track_window = (x, y, w, h)
# フレームの取得
ret,frame = cap.read()
# 追跡する枠を決定
roi = frame[y:y+h, x:x+w]
の部分を以下とした。
# 追跡する枠の座標とサイズ
x = 200
y = 200
w = 200
h = 200
track_window = (x, y, w, h)
# フレームの取得
ret,frame = cap.read()
cv2.waitKey(2)
# 追跡する枠を決定
while True:
ret,frame = cap.read()
cv2.imshow("org",frame)
roi = frame[y:y+h, x:x+w]
cv2.imshow("roi",roi)
if cv2.waitKey(20)>0:
break
つまり、一度初期起動させ、その後取得する。しかも動画を直接見ながらWhileでターゲットを確実に補足できたところで、何かキーを押すとroiが取得できるように変更した。これで、やると失敗はなくなった。
結果
例は青い物体でのものであったが、赤いリンゴのお菓子袋でためしてみた。
以前の記事から青の範囲との比較
OpenCV / read_save_doga.py
47 # define range of blue color in HSV
48 lower_blue = np.array([110,50,50])
49 upper_blue = np.array([130,255,255])
# 上記のコード
img_mask = cv2.inRange(hsv_roi, np.array((0., 60.,32.)), np.array((180.,255.,255.)))
上記はほぼ全色入っている
ということで見事に捕捉してくれた。実は顔なんかも捕捉できているので、ほぼなんでも捕捉できるものと思わわれる。
ちなみに、CamShiftはさらに捕捉するまで枠の大きさを変えた探索する。物体の見た目の大きさ(遠ざかったり、近づいたりで)が変わっても、その大きさに対応して捕捉する。
捕捉できなければ、撮影画像一面に広がる。。。
ただし、枠が横に長くなってしまったり、縦に長くなったりもして評価は難しいところです。
まとめ
・meanshift&CamShiftで物体捕捉して遊んでみた
・roiの使い方次第でいろいろ試せそう
というか、SSPのRoiで物体認識が使えるような予感