のんびりしているエンジニアの日記

ソフトウェアなどのエンジニア的な何かを書きます。

Opencvの使い方(7) 物体追跡

Sponsored Links

皆さんこんにちは
お元気ですか。私は元気です。

さて、今日は物体追跡をどうやるのかを調べてました
人物追跡はもう少し後かな。全然やったことがないので、さっぱりな分野でしたので、サンプルを探せば、なんと公式サンプルが落ちておりました。

本日はサンプルソースコードの解説です。これを改良して、人物追跡+パーティクルフィルタにつなげていこうと思います。

まず、物体追跡アルゴリズムの手順ですが以下の通りです

1.画像をRGB→HSVに変換する
2.HSV→Hのヒストグラム作成+正規化
3.バックプロジェクションの計算
4.CamShift

1.画像のHSV変換

cvtColor(image,hsv,COLOR_BGR2HSV);
BGR(Opencvのデータはこの順番です)→HSVに変換します。

2.ヒストグラムの生成と正規化を行います。

calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);
normalize(hist, hist, 0, 255, NORM_MINMAX);

3.calkBackProject
調べた所によると頻度の高い輝度が明るい画素として表示されるような計算を実行する。

calcBackProject(&hue, 1, 0, hist, backproj, &phranges);

4.CamShift
物体の大きさや位置、回転方向を決定します。
TermCriteriaの部分が停止基準のようです。

RotatedRect trackBox = CamShift(backproj, trackWindow,
                                    TermCriteria( TermCriteria::EPS | TermCriteria::COUNT,10,1));

以下にサンプルを単純にしたものを掲載します。

コード

#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace cv;
using namespace std;

Mat image;

bool backprojMode = false;
bool selectObject = false;
int trackObject = 0;
bool showHist = true;
Point origin;
Rect selection;
int LINE_AA=16;


//マウスクリック時の行動
void onMouse(int event,int x,int y,int,void*){
    if(selectObject){
        selection.x = MIN(x, origin.x);
        selection.y = MIN(y, origin.y);
        selection.width = std::abs(x - origin.x);
        selection.height = std::abs(y - origin.y);
        selection &= Rect(0, 0, image.cols, image.rows);
    }

    switch(event){
    case EVENT_LBUTTONDOWN:
        origin = Point(x,y);
        selection = Rect(x,y,0,0);
        selectObject = true;
        break;
    case EVENT_LBUTTONUP:
        selectObject = false;
        if( selection.width > 0 && selection.height > 0 )
            trackObject = -1;
        break;
    }
}

int main(void){
	VideoCapture video;
	video.open(0);

	Rect trackWindow;
	int hsize = 16;
	float hranges[] = {0,180};
	const float* phranges = hranges;

	if(!video.isOpened()){
		cout << "can't open your video" << endl;
	}

	namedWindow("Camera",0);
	setMouseCallback("Camera",onMouse, 0 );
	Mat frame, hsv, hue, mask, hist, histimg = Mat::zeros(200, 320, CV_8UC3), backproj;
	bool paused = false;

	while(1){
		Mat frame;
		video >> frame;

		//終了判定の条件
		if(frame.empty()){
			break;
		}

		frame.copyTo(image);

		if(!paused)
        {
            cvtColor(image,hsv,COLOR_BGR2HSV);

            if(trackObject){
                //色が範囲内に収まっているかどうか
                //収まっていれば0 収まってなければ255を入れる。
                inRange(hsv, Scalar(0, 0, 0),
                        Scalar(180, 255, 255), mask);
                //cout << mask << endl;
                int ch[] = {0, 0};
                hue.create(hsv.size(), hsv.depth());
                mixChannels(&hsv, 1, &hue, 1, ch, 1);

                //trackingしたヒストグラムの生成を行う。
                //実行は最初の一度のみ
                if(trackObject < 0){
                    Mat roi(hue, selection), maskroi(mask, selection);
                    //ヒストグラムの生成と正規化
                    calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);
                    normalize(hist, hist, 0, 255, NORM_MINMAX);

                    trackWindow = selection;
                    trackObject = 1;
                }

                calcBackProject(&hue, 1, 0, hist, backproj, &phranges);
                backproj &= mask;

                //物体の中心、サイズ、姿勢を求める関数の実行
                RotatedRect trackBox = CamShift(backproj, trackWindow,
                                    TermCriteria( TermCriteria::EPS | TermCriteria::COUNT,10,1));

                if(trackWindow.area() <= 1){
                    int cols = backproj.cols, rows = backproj.rows, r = (MIN(cols, rows) + 5)/6;
                    //共通部分を抽出
                    trackWindow = Rect(trackWindow.x - r, trackWindow.y - r,
                                       trackWindow.x + r, trackWindow.y + r) &
                                  Rect(0, 0, cols, rows);
                }

                if(backprojMode)
                    cvtColor(backproj, image, COLOR_GRAY2BGR);
                ellipse(image, trackBox, Scalar(0,0,255), 3, LINE_AA);
            }
        }
        //trackObjectが存在しない時はこちらへ
        else if(trackObject < 0)
            paused = false;

        //選択オブジェクトがある時に色を変える。
        if(selectObject && selection.width > 0 && selection.height > 0){
            Mat roi(image, selection);
            bitwise_not(roi, roi);
        }

        imshow( "Camera", image );

        char c = (char)waitKey(10);
}

動作

こんな感じで追跡します。あまり精度が良くない気がするのですが。。。。
f:id:tereka:20141109001929p:plain