OpenCVとC++を使った色追跡の実装方法:HSV変換から軌跡の描画まで
色追跡(カラートラッキング)は、色検出とよく似た画像処理です。追跡を実現するには、検出したオブジェクトの面積を計算し、その領域の現在位置を求める処理を数行追加します。最後に、OpenCVのline()関数を使って、オブジェクトが移動した軌跡を線として描画します。
この記事では、トラックバーでHSVのしきい値をリアルタイムに調整しながら、Webカメラの映像から特定色のオブジェクトを検出し、その動きを追跡する方法を解説します。
色追跡の基本的な流れ
- 映像の取得:VideoCaptureクラスでWebカメラからフレームを取得します。
- HSVへの変換:cvtColor()関数でBGR画像をHSV形式に変換します。HSVは色相・彩度・明度の3要素で色を表すため、照明の変化の影響を受けにくく、特定色の検出に適しています。
- 色範囲の抽出:inRange()関数とcreateTrackbar()で作成したトラックバーにより、指定したHSV範囲内の色だけを残します。
- ノイズ除去:erode()とdilate()によるモルフォロジー演算(オープニングとクロージング)で、小さなノイズを取り除き、検出領域の小さな穴を埋めます。
- 重心の計算:moments()関数で画像モーメントを求め、m00(面積)、m01・m10からオブジェクトの重心座標を計算します。
- 軌跡の描画:前回の座標と現在の座標を結ぶ赤い線をline()関数で描き、オブジェクトの動きを可視化します。
サンプルコード
#include<iostream>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
int main(int argc, char** argv) {
VideoCapture video_load(0);//デフォルトカメラから映像を取得//
namedWindow("Adjust");//画像を表示するウィンドウを作成//
int Hue_Low = 0;//色相(Hue)の下限//
int Hue_high = 22;//色相(Hue)の上限//
int Sat_Low = 99;//彩度(Saturation)の下限//
int Sat_high = 255;//彩度(Saturation)の上限//
int Val_Low = 0;//明度(Value)の下限//
int Val_high = 255;//明度(Value)の上限//
createTrackbar("LowH", "Adjust", &Hue_Low, 179);//最小色相を調整するトラックバー//
createTrackbar("HighH", "Adjust", &Hue_high, 179);//最大色相を調整するトラックバー//
createTrackbar("LowS", "Adjust", &Sat_Low, 255);//最小彩度を調整するトラックバー//
createTrackbar("HighS", "Adjust", &Sat_high, 255);//最大彩度を調整するトラックバー//
createTrackbar("LowV", "Adjust", &Val_Low, 255);//最小明度を調整するトラックバー//
createTrackbar("HighV", "Adjust", &Val_high, 255);//最大明度を調整するトラックバー//
int Horizontal_Last = -1;//初期の水平方向位置//
int vertical_Last = -1;//初期の垂直方向位置//
Mat temp;//映像ストリームからフレームを読み込むための行列//
video_load.read(temp);//映像ストリームからフレームを読み込み//
Mat track_motion = Mat::zeros(temp.size(), CV_8UC3);//検出用の黒い行列を作成//
while (true) {
Mat actual_Image;//実際の画像を格納する行列//
bool temp_load = video_load.read(actual_Image);//映像からフレームを読み込む//
Mat converted_to_HSV;//変換後の画像を保存する行列//
cvtColor(actual_Image, converted_to_HSV, COLOR_BGR2HSV);//BGR画像をHSVに変換//
Mat adjusted_frame;//検出した色を格納する行列//
inRange(converted_to_HSV, Scalar(Hue_Low, Sat_Low, Val_Low),
Scalar(Hue_high, Sat_high, Val_high), adjusted_frame);//トラックバーの値を反映//
erode(adjusted_frame, adjusted_frame, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));//モルフォロジーオープニングで前景の小さな物体を除去//
dilate(adjusted_frame, adjusted_frame, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));//モルフォロジーオープニングで前景の小さな物体を除去//
dilate(adjusted_frame, adjusted_frame, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));//モルフォロジークロージングで前景の小さな穴を埋める//
erode(adjusted_frame, adjusted_frame, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));//モルフォロジークロージングで前景の小さな穴を埋める//
Moments detecting_object = moments(adjusted_frame);//検出した色のフレームからモーメントを生成//
double vertical_moment = detecting_object.m01;//垂直方向の位置を取得//
double horizontal_moment = detecting_object.m10;//水平方向の位置を取得//
double tracking_area = detecting_object.m00;//オブジェクトの面積を取得//
if (tracking_area > 10000) {//オブジェクトの面積が10000ピクセルより大きい場合//
int posX = horizontal_moment / tracking_area;//オブジェクトの水平位置を計算//
int posY = vertical_moment / tracking_area;//オブジェクトの垂直位置を計算//
if (Horizontal_Last >= 0 && vertical_Last >= 0 && posX >= 0 && posY >= 0) {//検出されたオブジェクトが移動している場合//
line(track_motion, Point(posX, posY), Point(Horizontal_Last, vertical_Last), Scalar(0, 0, 255), 2);//検出オブジェクトの移動経路に赤い線を描画//
}
Horizontal_Last = posX;//新しい水平位置を記録//
vertical_Last = posY;//新しい垂直位置を記録//
}
imshow("Detected_Object", adjusted_frame);//検出したオブジェクトを表示//
actual_Image = actual_Image + track_motion;//元の映像フレームに連続した線を重ねて描画//
imshow("Actual", actual_Image);//元の映像を表示//
cout << "position of the object is:" << Horizontal_Last << "," << vertical_Last << endl;//追跡した座標値を表示//
if (waitKey(30) == 27) {//Escキーが押されるとループを抜ける//
cout << "esc key is pressed by user" << endl;
break;
}
}
return 0;
}
実行結果
プログラムを実行すると、「Adjust」ウィンドウ上のトラックバーで色相・彩度・明度の範囲を調整できます。検出条件を満たすオブジェクトが画面内で動くと、元の映像上にその移動経路が赤い線で次々と描かれていきます。また、コンソールにはオブジェクトの現在座標が随時出力されます。


まとめ
本サンプルでは、HSV色空間での閾値処理と画像モーメントを組み合わせることで、シンプルながら実用的な色追跡を実現しています。面積が10000ピクセルを超える場合のみ追跡することで、誤検出を抑制している点もポイントです。Escキーを押すとループが終了し、プログラムが終了します。トラックバーの値を調整すれば、さまざまな色のオブジェクトに柔軟に対応できます。
-
C++とOpenCVで色空間を変換する方法!cvtColor()関数の使い方を解説
色空間とは 色空間(Color Space)とは、色を表現するためのモデルのことです。色の記述方法にはさまざまな種類があり、代表的なものとしてRGB、CMYK、HSV、グレースケールなどが挙げられます。 imgproc.hppヘッダーについて 本記事では、「imgproc.hpp」というヘッダーを使用します。この名前は「Image Processing(画像処理)」の略です。OpenCVで色空間を変換するには、「cvtColor()」関数を使用する必要があります。この関数は「imgproc」ヘッダーファイル内で定義されているため、あらかじめ「imgproc.hpp」をインクルードしておきまし
-
C++とOpenCVで画像のチャンネル数を取得する方法を解説
この記事では、OpenCVを使って画像のチャンネル数を調べる方法について解説します。プログラムを実行すると、コンソール画面に画像のチャンネル数が表示されます。チャンネル数を取得するには、OpenCVが提供するchannels()メソッドを使用します。このメソッドは、Matクラスのオブジェクト(画像行列)に対して呼び出すことで、その画像のチャンネル数を整数値として返します。例えば、カラー画像の場合は通常3チャンネル(BGR)、グレースケール画像の場合は1チャンネルとなります。画像処理を行う際、扱っている画像がカラーかモノクロかを判別するために、チャンネル数の確認は非常に重要な処理の一つです。以下