移動する物体を追跡する

動画からダンゴムシの動きをトラッキングしています。このチュートリアルを実施すれば、他の多くの問題に対しても自身で解決できる能力を身につけられるでしょう。画像の2値化から輪郭検出、動画の書き出しまで広い内容を含んでいます。

手元に良い感じのサンプル動画がなかったため、庭先でダンゴムシを撮影してきました。今回はこの動画を解析します。動画は何でも良いのですが、背景が均一で追跡した物体とのコントラストの差ができるだけ大きいようにするのが良いでしょう。今回の動画は背景とのコントラストの差が小さくダンゴムシ追跡の難易度は少し高めです。


最終的な目的はダンゴムシの追跡ですが、まずは動画を再生して表示するだけのプログラムを作成します。動画へのパスは各々で動画の置いてある場所に合わせてください。

#include "opencv/cv.h"
#include "opencv/highgui.h"
using namespace cv;

int main(){
    Mat img;
    VideoCapture cap("pillbug.mp4");
    int max_frame=cap.get(CV_CAP_PROP_FRAME_COUNT);
    for(int i=0; i<max_frame;i++){ cap>>img;
        imshow("Video",img);
        waitKey(1);
    }
    return 0;
}

ダンゴムシが地面より黒いことを利用する

適当な閾値を設定し、動画の各フレームを2値化してみましょう。私がやってみたところ、この動画では閾値は固定70くらいがちょうど良さそうでした。当然ですが、この値は動画によって異なります。最後に、表示されたウィンドウのスクリーンショットを載せています。ダンゴムシのいる部分は黒く、他の部分は白くなっていますが、右下の部分で若干のノイズがみられ黒くなっている部分が見えます。したがって、今の時点で黒い部分をダンゴムシであるとは言えませんが、大きくかたまった黒い領域はダンゴムシのいる部分だけですので検出することができそうです。
3

#include "opencv/cv.h"
#include "opencv/highgui.h"
using namespace cv;

int main(){
    Mat img;
    Mat gray_img; //追加
    Mat bin_img; //追加
    VideoCapture cap("pillbug.mp4");
    int max_frame=cap.get(CV_CAP_PROP_FRAME_COUNT);
    for(int i=0; i<max_frame;i++){ cap>>img;
        cvtColor(img, gray_img, CV_BGR2GRAY);  //追加 グレースケールに変換
        threshold(gray_img,bin_img,70,255,THRESH_BINARY);  //追加 閾値80で2値画像に変換
        imshow("Video",bin_img); //変更
        waitKey(1);
    }
    return 0;
}

  • オバタ

    私は大学4年生でこのwebページをよく参考にさせてもらってます.
    とてもわかりやすく勉強になります.ありがとうございます.

    このプログラムを真似させてもらい,自分の持っている動画を用いて実行してみたところ
    vector subscript out of range とエラーが出てしまいました.

    このエラーの解決法などありましたら教えていただくことは可能でしょうか.

    コードは以下のように書いています.
    #include
    #include “opencv/cv.h”
    #include “opencv/highgui.h”
    #include
    #include
    #include
    //#include //追加
    #include //追加

    using namespace cv;
    using namespace std;

    int main() {

    //Mat img = imread(“C:\img2.png”, IMREAD_GRAYSCALE);
    //Mat img2 = img.clone();//コピー元(img)とコピー先を別データとしてコピーする,深いコピー

    Mat frame(500,500,CV_8UC1);
    Mat gray_frame; //グレースケールを保存するための行列管理構造体
    Mat thre_frame; //二値化を保存するための行列管理構造体
    //Mat frame2 = frame.clone();

    VideoCapture cap(“C:\細胞引張試験_A7r5元の速度.avi”);
    // 動画ファイルが開けたか調べる
    if (cap.isOpened() == false) {
    printf(“ファイルが開けません。n”);
    return -1;
    }
    //int max_frame = cap.get(CV_CAP_PROP_FRAME_COUNT); //動画の総フレーム数取得

    for (int i = 0; i> frame;
    if (frame.empty())break;
    cvtColor(frame, gray_frame, CV_BGR2GRAY);//グレースケール化
    threshold(gray_frame, thre_frame, 70, 255, THRESH_BINARY);//二値化処理

    printf(“test”);
    vector< vector > contours;
    findContours(thre_frame, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);

    double max_area = 0;
    int max_area_contour = -1;
    for (int j = 0; j<contours.size(); j++) {
    double area = contourArea(contours.at(j));
    if (max_area<area) {
    max_area = area;
    max_area_contour = j;
    }
    }

    int count = contours.at(max_area_contour).size();
    double x = 0;
    double y = 0;
    for (int k = 0; k<count; k++) {
    x += contours.at(max_area_contour).at(k).x;
    y += contours.at(max_area_contour).at(k).y;
    }
    x /= count;
    y /= count;

    circle(frame, Point(x, y), 50, Scalar(0, 0, 255), 3, 4);

    Moments mu = moments(contours[max_area]);
    Point2f mc = Point2f(mu.m10 / mu.m00, mu.m01 / mu.m00);

    circle(frame, mc, 4, Scalar(100), 2, 4);

    printf("x: %f y: %f", mc.x, mc.y);

    waitKey(0);

    imshow("frame", frame);
    }
    return 0;
    }