Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
4
Help us understand the problem. What is going on with this article?
@MuAuan

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

More than 1 year has passed since last update.

ちょっとしたことから、すごく使えそうな気がしてきて、今更ながら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で物体認識が使えるような予感

4
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
MuAuan
2021年為になる記事にする 記事420いいね2000フォロワー200 2020年;いい記事を書く 記事359/350いいね1590/1500フォロワ ー144/150 2019年 記事275/300いいね1035/1000フォロワー97/100 2018年 記事140/200いいね423/500フォロワー48/50 7/8/2018 記事90いいね227フォロワー25

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
4
Help us understand the problem. What is going on with this article?