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

C++とOpenCVで特定の色を検出する方法を解説

この記事では、C++とOpenCVを使用して、カメラ映像の中から特定の色を検出し、その色を基準にオブジェクトを追跡する方法を解説します。

ただし、色検出や色ベースのトラッキングシステムの性能は実行環境に大きく依存します。部屋の照明を変えたり背景色を変更したりすると、検出精度に大きな影響が及ぶ点に注意してください。

色検出の基本的な流れ

OpenCVで色を検出する際は、一般的に次のような手順を踏みます。

  1. カメラから映像(フレーム)を取得する
  2. BGR形式の画像をHSV形式に変換する
  3. inRange()関数で指定した色の範囲だけを抽出する(二値化)
  4. モルフォロジー演算でノイズを除去する
  5. 結果を画面に表示する

HSV色空間は「色相(Hue)」「彩度(Saturation)」「明度(Value)」の3要素で色を表現するため、RGBよりも特定の色を直感的に指定しやすいのが特徴です。OpenCVでは色相が0〜179、彩度と明度が0〜255の範囲で表されます。

サンプルコード

以下のプログラムは、トラックバーでHSVのしきい値をリアルタイムに調整しながら、特定の色を持つオブジェクトを検出する例です。

#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_Lower_Value = 0;//Hueの初期値(下限)//
    int Hue_Lower_Upper_Value = 22;//Hueの初期値(上限)//
    int Saturation_Lower_Value = 0;//彩度の初期値(下限)//
    int Saturation_Upper_Value = 255;//彩度の初期値(上限)//
    int Value_Lower = 0;//明度の初期値(下限)//
    int Value_Upper = 255;//明度の初期値(上限)//
    createTrackbar("Hue_Lower", "Adjust", &Hue_Lower_Value, 179);//Hue下限用トラックバー//
    createTrackbar("Hue_Upper", "Adjust", &Hue_Lower_Upper_Value, 179);//Hue上限用トラックバー//
    createTrackbar("Sat_Lower", "Adjust", &Saturation_Lower_Value, 255);//彩度下限用トラックバー//
    createTrackbar("Sat_Upper", "Adjust", &Saturation_Upper_Value, 255);//彩度上限用トラックバー//
    createTrackbar("Val_Lower", "Adjust", &Value_Lower, 255);//明度下限用トラックバー//
    createTrackbar("Val_Upper", "Adjust", &Value_Upper, 255);//明度上限用トラックバー//
    while (1) {
        Mat actual_Image;//元画像を格納する行列//
        bool temp = video_load.read(actual_Image);//動画ストリームから元画像を読み込む//
        Mat convert_to_HSV;//変換後の画像を格納する行列//
        cvtColor(actual_Image, convert_to_HSV, COLOR_BGR2HSV);//BGR画像をHSVに変換して格納//
        Mat detection_screen;//検出結果を表示するウィンドウ用の行列//
        inRange(convert_to_HSV,Scalar(Hue_Lower_Value,Saturation_Lower_Value, Value_Lower),Scalar(Hue_Lower_Upper_Value,Saturation_Upper_Value, Value_Upper), detection_screen);//トラックバーで調整した範囲の色を抽出//
        erode(detection_screen, detection_screen, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));//収縮処理:前景の小さなノイズを除去//
        dilate(detection_screen, detection_screen, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));//膨張処理:前景の小さなノイズを除去//
        dilate(detection_screen, detection_screen, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));//膨張処理:前景の小さな穴を埋める//
        erode(detection_screen, detection_screen, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));//収縮処理:前景の小さな穴を埋める//
        imshow("Threesholded Image", detection_screen);//検出結果を表示//
        imshow("Original", actual_Image);//元画像を表示//
        if (waitKey(30) == 27){ //Escキーが押されたらループを抜ける//
            break;
        }
    }
    return 0;
}

コードのポイント

cvtColor()によるHSV変換

cvtColor()関数にCOLOR_BGR2HSVフラグを渡すことで、カメラから取得したBGR画像をHSV色空間へ変換できます。

inRange()による色の抽出

inRange()関数は、指定した下限値と上限値の範囲内にあるピクセルを白(255)、範囲外のピクセルを黒(0)とした二値画像を生成します。トラックバーの値を変更すれば、検出したい色をリアルタイムに調整可能です。

モルフォロジー演算によるノイズ除去

erode()(収縮)とdilate()(膨張)を組み合わせたオープニング処理により、前景に残った小さなノイズを除去します。さらに逆の順序で組み合わせたクロージング処理によって、検出領域内部の小さな穴を埋めることで、より安定した検出結果が得られます。

実行結果

プログラムを実行すると、「Adjust」ウィンドウ上のトラックバーでHSVの各パラメータを調整できます。「Threesholded Image」ウィンドウには検出結果が白黒の二値画像として表示され、「Original」ウィンドウにはカメラの元画像が表示されます。Escキーを押すとプログラムが終了します。

C++とOpenCVで特定の色を検出する方法を解説

  1. C++とOpenCVで色空間を変換する方法!cvtColor()関数の使い方を解説

    色空間とは 色空間(Color Space)とは、色を表現するためのモデルのことです。色の記述方法にはさまざまな種類があり、代表的なものとしてRGB、CMYK、HSV、グレースケールなどが挙げられます。 imgproc.hppヘッダーについて 本記事では、「imgproc.hpp」というヘッダーを使用します。この名前は「Image Processing(画像処理)」の略です。OpenCVで色空間を変換するには、「cvtColor()」関数を使用する必要があります。この関数は「imgproc」ヘッダーファイル内で定義されているため、あらかじめ「imgproc.hpp」をインクルードしておきまし

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

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