このアプリケーションでは、ビデオ内で検出された顔のランドマークを検出できる。このアプリケーションは、まず現在のビデオフレーム内で顔を検出し、その後それらの顔のランドマークを見つける。入力としてビデオを渡すだけでよい。
// Command to be typed for running the sample
./sampleDetectLandmarks -file=trained_model.dat -face_cascade=lbpcascadefrontalface.xml -video=/path_to_video/video.avi
コマンドパラメータの説明
* model_filename f : (必須) 読み込む学習済みモデルを格納したバイナリファイルへのパス [例 - /data/file.dat]
- video v : (必須) 顔のランドマークを検出するビデオへのパス。[例 - /data/video.avi]
- face_cascade c : (必須) 顔検出器として使用したい顔カスケードのxmlファイルへのパス。
コードの理解
このチュートリアルでは、顔のランドマーク検出のサンプルコードを説明する。さっそくコードに入ろう。
c++
CascadeClassifier face_cascade;
bool myDetector( InputArray image, OutputArray ROIs );
bool myDetector( InputArray image, OutputArray ROIs ){
Mat gray;
std::vector<Rect> faces;
if(image.channels()>1){
cvtColor(image.getMat(),gray,COLOR_BGR2GRAY);
}
else{
gray = image.getMat().clone();
}
equalizeHist( gray, gray );
face_cascade.detectMultiScale( gray, faces, 1.1, 3,0, Size(30, 30) );
Mat(faces).copyTo(ROIs);
return true;
}
facemark APIは、顔ランドマーク検出で独自の顔検出器を使用する機能をユーザーに提供する。上記のコードはサンプルの顔検出器を生成する。上記の関数はfacemark API内の関数ポインタに渡される。
c++
VideoCapture cap(video);
if(!cap.isOpened()){
cerr<<"Video cannot be loaded. Give correct path"<<endl;
return -1;
}
上記のコードはビデオキャプチャオブジェクトを作成し、その後ビデオを読み込む。ビデオが正しく読み込まれない場合はユーザーに通知し、そうでなければコードは続行する。
c++
Mat img = imread(image);
face_cascade.load(cascade_name);
FacemarkKazemi::Params params;
params.configfile = configfile_name;
Ptr<Facemark> facemark = FacemarkKazemi::create(params);
facemark->setFaceDetector(myDetector);
上記のコードは顔ランドマーク検出クラスのポインタを作成する。上で作成した顔検出器は、顔を検出するためにfacemarkポインタへ関数ポインタとして渡す必要がある。
c++
vector<Rect> faces;
vector< vector<Point2f> > shapes;
Mat img;
上記のコードは、検出された顔を格納するベクトルと、現在のフレームで検出された各顔の形状を格納するベクトルのベクトルを作成する。
c++
while(1){
faces.clear();
shapes.clear();
cap>>img;
resize(img,img,Size(600,600),0,0,INTER_LINEAR_EXACT);
facemark->getFaces(img,faces);
if(faces.size()==0){
cout<<"No faces found in this frame"<<endl;
}
else{
for( size_t i = 0; i < faces.size(); i++ )
{
cv::rectangle(img,faces[i],Scalar( 255, 0, 0 ));
}
if(facemark->fit(img,faces,shapes))
{
for(unsigned long i=0;i<faces.size();i++){
for(unsigned long k=0;k<shapes[i].size();k++)
cv::circle(img,shapes[i][k],3,cv::Scalar(0,0,255),FILLED);
}
}
}
namedWindow("Detected_shape");
imshow("Detected_shape",img);
if(waitKey(1) >= 0) break;
}
次に上記のコードは各フレームを読み込み、顔と、検出された各形状に対応するランドマークを検出する。その後、現在のフレームを表示する。
上記のコードを実行すると、このような結果が得られる
サンプル動画: