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

C++とOpenCVで検出した顔をトリミング(切り抜き)する方法

この記事では、OpenCVを使って検出した顔をトリミング(切り抜き)する方法を解説します。検出した顔を切り抜くには、複数の行列(Mat)が必要になります。最も適切な方法は、画像の配列を使用することです。

必要な行列(Mat)の宣言

本プログラムでは、次の2行のコードで2つの画像行列を宣言しています。

  • Mat cropped_faces[4];
  • Mat faceROI[4];

1つ目の行列「cropped_faces」は切り抜いた画像を保存するためのもので、2つ目の行列「faceROI」は関心領域(ROI:Region of Interest)を定義するために使用します。

顔領域の切り抜き処理の流れ

検出処理では、まずプログラムが画像内の顔の位置を特定し、その結果をベクターに格納します。このプログラムでは、ベクター名を「faces」としています。ベクターには複数の要素(検出された複数の顔)を格納できます。

続いて、次の2行のコードによって、ベクターを識別して画像内の位置を特定し、最終的に顔領域を「faceROI[i]」行列へ切り抜きます。

  • faceROI[i] = image_with_humanface(faces[i]);
  • cropped_faces[i] = faceROI[i];

1行目では、「image_with_humanface」という名前の画像から顔を含む領域を特定し、切り抜いた結果を「faceROI[i]」という行列に格納します。2行目では、切り抜いた画像を別の行列配列に渡しています。この行列配列は、切り抜いた画像を画面に表示するために使われます。

サンプルプログラム

以下のプログラムは、検出した顔を切り抜き、それぞれ別のウィンドウに表示します。

#include<iostream>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
//「rectangle()」関数の定義を含むヘッダー//
#include<opencv2/objdetect/objdetect.hpp>
//CascadeClassifierクラスの定義を含むヘッダー//
#include<string>
using namespace std;
using namespace cv;
int main(int argc, char** argv) {
   Mat image_with_humanface;//人の顔が写った画像を読み込むための行列を宣言//
   Mat cropped_faces[3];//切り抜いた顔を表示するための3要素の行列配列を宣言//
   Mat faceROI[3];//切り抜いた顔を保持するための3要素の行列配列を宣言//
   image_with_humanface = imread("friends3.jpg");//人の顔が含まれる画像を読み込む//
   namedWindow("Face1");//1つ目の切り抜き顔を表示するウィンドウを宣言//
   namedWindow("Face2");//2つ目の切り抜き顔を表示するウィンドウを宣言//
   namedWindow("Face3");//3つ目の切り抜き顔を表示するウィンドウを宣言//
   string trained_classifier_location = "C:/opencv/sources/data/haarcascades/haarcascade_frontalface_alt.xml";//学習済みXML分類器の場所を文字列として定義//
   CascadeClassifier faceDetector;//CascadeClassifierクラスのオブジェクト「faceDetector」を宣言//
   faceDetector.load(trained_classifier_location);//オブジェクトに学習済みXML分類器を読み込む//
   vector<Rect>faces;//「faces」という名前の矩形ベクターを宣言//
   vector<Rect>boundary;//「boundary」という名前の矩形ベクターを宣言//
   faceDetector.detectMultiScale(image_with_humanface, faces, 1.1, 4, CASCADE_SCALE_IMAGE, Size(20, 20));//「image_with_humanface」行列内の顔を検出//
   for (size_t i = 0; i < faces.size(); i++){ //顔の周囲に矩形を描画するループ//
      faceROI[i] = image_with_humanface(faces[i]);
      cropped_faces[i] = faceROI[i];
      int x = faces[i].x;//顔矩形の開始点のx座標(行方向の初期値)を取得//
      int y = faces[i].y;//顔矩形の開始点のy座標(列方向の初期値)を取得//
      int h = y + faces[i].height;//矩形の高さを計算//
      int w = x + faces[i].width;//矩形の幅を計算//
      rectangle(image_with_humanface, Point(x, y), Point(w, h), Scalar(255, 0, 255), 2, 8, 0);//顔の周囲に矩形を描画//
   }
   imshow("Face1", cropped_faces[0]);//1つ目の切り抜き顔を表示//
   imshow("Face2", cropped_faces[1]);//2つ目の切り抜き顔を表示//
   imshow("Face3", cropped_faces[2]);//3つ目の切り抜き顔を表示//
   waitKey(0);//キー入力を待ってプログラムを終了する
   return 0;
}

実行結果

プログラムを実行すると、元画像から検出された各顔が個別のウィンドウに切り抜かれて表示されます。

C++とOpenCVで検出した顔をトリミング(切り抜き)する方法

補足ポイント

サンプルコードでは配列サイズを3要素としていますが、実際に扱う画像に写る人数に合わせて、cropped_facesfaceROIの配列サイズを調整してください。また、detectMultiScale()のパラメータ(スケール係数、minNeighborsなど)を変更することで、検出精度を調整できます。検出された顔の数はfaces.size()で取得できるため、これを利用すれば動的な処理にも対応可能です。

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

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

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

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