3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Opencv: meanshift&CamShiftで遊んでみた♬

Last updated at Posted at 2018-05-28

ちょっとしたことから、すごく使えそうな気がしてきて、今更ながら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

コードと工夫したこと

参考2のオリジナルコード.py
# -*- 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.)))

上記はほぼ全色入っている

ということで見事に捕捉してくれた。実は顔なんかも捕捉できているので、ほぼなんでも捕捉できるものと思わわれる。
apple_meanshift.jpg

ちなみに、CamShiftはさらに捕捉するまで枠の大きさを変えた探索する。物体の見た目の大きさ(遠ざかったり、近づいたりで)が変わっても、その大きさに対応して捕捉する。
捕捉できなければ、撮影画像一面に広がる。。。
ただし、枠が横に長くなってしまったり、縦に長くなったりもして評価は難しいところです。

まとめ

・meanshift&CamShiftで物体捕捉して遊んでみた
・roiの使い方次第でいろいろ試せそう
   というか、SSPのRoiで物体認識が使えるような予感

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?