C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++とOpenCVで目の位置をリアルタイムに追跡する方法

この記事では、OpenCVを使ってカメラ映像から目の位置を追跡する方法を解説します。

目のトラッキングの基本的な考え方

OpenCVによる目の検出が完了していれば、その後のトラッキングは非常にシンプルな作業です。この手法では、検出した目を円で囲み、その円の中心を追跡することで目の中心位置を把握します。

円の中心を追跡するためには、X座標とY座標を保持する2つの整数型変数が必要になります。これらはmain()関数内の冒頭2行(9行目と10行目)で宣言されており、変数名は「x_axis」と「y_axis」です。

コードの42行目と43行目では、検出した目の水平方向・垂直方向の座標値がそれぞれx_axisとy_axisにコピーされます。続く44行目ではcout文を使ってこの座標値をコンソールに出力しており、これによって目の位置情報をリアルタイムに取得できる仕組みです。

サンプルコード

以下が、C++とOpenCVを組み合わせて目の位置を追跡する完全なサンプルコードです。コメントも日本語化しているので、処理の流れが理解しやすくなっています。

#include<iostream>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/objdetect/objdetect.hpp>
using namespace cv;
using namespace std;
int main() {
    int x_axis;//座標値を格納する整数型変数の宣言//
    int y_axis;//座標値を格納する整数型変数の宣言//
    Mat frame;//ビデオフレームを格納する行列の宣言//
    namedWindow("Detect");//作業結果を表示するウィンドウの宣言//
    VideoCapture image(0);//デフォルトカメラから映像を取得//
    if (!image.isOpened()){ //映像ソースが見つからない場合のエラーメッセージ//
        cout << "Couldn't load video from the source.Make sure your camera is working properly." << endl;
        system("pause");
        return 0;
    }
    double height = image.set(CAP_PROP_FRAME_HEIGHT, 480);//各フレームの高さを設定//
    double width = image.set(CAP_PROP_FRAME_WIDTH, 640);//各フレームの幅を設定//
    CascadeClassifier face_cascade, eyes_cascade;//CascadeClassifierオブジェクトの宣言//
    face_cascade.load("C:/opencv/sources/data/haarcascades/haarcascade_frontalface_alt.xml");//カスケード分類器の読み込み//
    eyes_cascade.load("C:/opencv/sources/data/haarcascades/haarcascade_eye.xml");
    while (true) {
        bool temp = image.read(frame);//カメラからフレームを読み込みmatrixに格納//
        std::vector<Rect>faces;//facesという名前のベクターを宣言//
        face_cascade.detectMultiScale(frame, faces, 1.1, 2, 0 | CASCADE_SCALE_IMAGE, Size(100, 100));//顔の検出//
        for (int i = 0; i < faces.size(); i++){ //顔の位置を特定//
            Point center(faces[i].x + faces[i].width * 0.5, faces[i].y + faces[i].height * 0.5);//顔の中心を取得//
            ellipse(frame, center, Size(faces[i].width * 0.5, faces[i].height * 0.5), 0, 0, 360, Scalar(255, 0, 255), 4, 8, 0);//顔に楕円を描画//
            Mat faceROI = frame(faces[i]);//顔の領域を目の関心領域(ROI)として取得//
            std::vector<Rect>eyes;//eyesという名前のベクターを宣言//
            eyes_cascade.detectMultiScale(faceROI, eyes, 1.1, 2, 0 | CASCADE_SCALE_IMAGE, Size(5, 5));//各顔の中から目を検出//
            for (size_t j = 0; j < eyes.size(); j++){ //目の位置を特定//
                Point center(faces[i].x + eyes[j].x + eyes[j].width * 0.5, faces[i].y + eyes[j].y + eyes[j].height * 0.5);//両目の中心を取得//
                int radius = cvRound((eyes[j].width + eyes[j].height) * 0.25);//目を囲む円の半径を算出//
                circle(frame, center, radius, Scalar(255, 0, 0), 4, 8, 0);//両目の周囲に円を描画//
                x_axis = eyes[j].x;//目のX軸方向の位置をx_axisに格納//
                y_axis = eyes[j].y;//目のY軸方向の位置をy_axisに格納//
                cout << "Position of the eyes is:" << "(" << x_axis << "," << y_axis << ")" << endl;//座標値を表示//
            }
        }
        imshow("Detect", frame);//「Detect」ウィンドウに結果を表示//
        if (waitKey(30) == 27){ //各フレームの待機時間は30ミリ秒(ESCキーで終了)//
            break;
        }
    }
    return 0;
}

コードのポイント

  • カスケード分類器の準備: 顔検出には「haarcascade_frontalface_alt.xml」、目の検出には「haarcascade_eye.xml」を使用します。パスは環境に合わせて変更してください。
  • 段階的な検出: まず画像全体から顔を検出し、次に検出された顔領域(ROI)の中からのみ目を検出することで、精度と処理速度の両方を向上させています。
  • 終了操作: 各フレーム間に30ミリ秒の待機時間を設けており、ESCキー(キーコード27)を押すとプログラムが終了します。

実行結果

プログラムを実行すると、カメラ映像内の顔が楕円で、両目が青い円で囲まれ、同時にコンソールには目の現在位置を示す座標値が出力され続けます。

C++とOpenCVで目の位置をリアルタイムに追跡する方法


C++とOpenCVで目の位置をリアルタイムに追跡する方法

  1. C++とOpenCVを使って線を描画する方法

    OpenCVで線を描画するには、始点と終点の2つの座標が必要です。さらに、線を描くためのキャンバス(描画領域)も用意しなければなりません。線を描画するために必要な要素OpenCVでは、キャンバスとして機能するのが行列(Mat)です。この行列に対して、線の始点と終点を定義し、加えて以下の情報も指定します。線の色線の太さつまり、OpenCVで線を描くには、行列・2つの点・色・線の太さという4つの要素を宣言しておく必要があります。必要なヘッダーファイルOpenCVで線を描画するには、<imgproc.hpp>ヘッダーをインクルードします。これは、line()関数がこのヘッダー内で定義され

  2. C++とOpenCVで画像のチャンネル数を取得する方法を解説

    この記事では、OpenCVを使って画像のチャンネル数を調べる方法について解説します。プログラムを実行すると、コンソール画面に画像のチャンネル数が表示されます。チャンネル数を取得するには、OpenCVが提供するchannels()メソッドを使用します。このメソッドは、Matクラスのオブジェクト(画像行列)に対して呼び出すことで、その画像のチャンネル数を整数値として返します。例えば、カラー画像の場合は通常3チャンネル(BGR)、グレースケール画像の場合は1チャンネルとなります。画像処理を行う際、扱っている画像がカラーかモノクロかを判別するために、チャンネル数の確認は非常に重要な処理の一つです。以下