目標
このチュートリアルでは、以下のことができるようになる
- Facemark オブジェクトを生成する。
- facemark アルゴリズムにユーザー定義の顔検出器を設定する
- アルゴリズムを学習させる。
- 学習済みモデルを使用して、与えられた画像から顔のランドマークを検出する。
準備
このチュートリアルを続ける前に、顔のランドマーク検出のデータセットをダウンロードしておく必要がある。http://www.ifp.illinois.edu/~vuongle2/helen/ から取得できる helen データセットのダウンロードを推奨する(注意! このアルゴリズムはこのデータセットでの学習に約 9GB の RAM を必要とする)。
アノテーション形式が API でサポートされていることを確認すること。アノテーションファイルの内容は以下のスニペットのようになっているはずである:
version: 1
n_points: 68
{
212.716603 499.771793
230.232816 566.290071
...
}
次に行うことは、画像ファイルの一覧とアノテーションファイルの一覧をそれぞれ含む2つのテキストファイルを作成することである。両方のファイルで画像とアノテーションの順序が一致していることを確認すること。さらに、相対パスではなく絶対パスを使うことを推奨する。Linux マシンでファイル一覧を作成する例
ls $PWD/trainset/*.jpg > images_train.txt
ls $PWD/trainset/*.pts > annotation_train.txt
images_train.txt の内容例
/home/user/helen/trainset/100032540_1.jpg
/home/user/helen/trainset/100040721_1.jpg
/home/user/helen/trainset/100040721_2.jpg
/home/user/helen/trainset/1002681492_1.jpg
annotation_train.txt の内容例
/home/user/helen/trainset/100032540_1.pts
/home/user/helen/trainset/100040721_1.pts
/home/user/helen/trainset/100040721_2.pts
/home/user/helen/trainset/1002681492_1.pts
facemark オブジェクトの生成
/*create the facemark instance*/
FacemarkLBF::Params params;
params.model_filename = "helen.model"; // the trained model will be saved using this filename
Ptr<Facemark> facemark = FacemarkLBF::create(params);
カスタム顔検出関数の設定
まず、独自の顔検出関数を作成する必要がある。カスタムパラメータを保存するために struct を作成する必要があるかもしれない。あるいは、これらのパラメータを myDetector 関数内にハードコードしてしまってもよい。
struct Conf {
cv::String model_path;
double scaleFactor;
Conf(cv::String s, double d){
model_path = s;
scaleFactor = d;
face_detector.load(model_path);
};
CascadeClassifier face_detector;
};
bool myDetector(InputArray image, OutputArray faces, Conf *conf){
Mat gray;
if (image.channels() > 1)
cvtColor(image, gray, COLOR_BGR2GRAY);
else
gray = image.getMat().clone();
equalizeHist(gray, gray);
std::vector<Rect> faces_;
conf->face_cascade.detectMultiScale(gray, faces_, conf->scaleFactor, 2, CASCADE_SCALE_IMAGE, Size(30, 30) );
Mat(faces_).copyTo(faces);
return true;
}
次のスニペットは、カスタム検出器を facemark オブジェクトに設定し、それを使って顔を検出する方法を示している。一部の facemark オブジェクトは学習プロセス中に顔検出器を使用する場合があることに留意すること。
Conf config("../data/lbpcascade_frontalface.xml", 1.4);
facemark->setFaceDetector(myDetector, &config); // we must guarantee proper lifetime of "config" object
以下は、ユーザー定義の顔検出関数を使って顔を検出するためのスニペットである。
Mat img = imread("../data/himym3.jpg");
std::vector<cv::Rect> faces;
facemark->getFaces(img, faces, config);
for(int j=0;j<faces.size();j++){
cv::rectangle(img, faces[j], cv::Scalar(255,0,255));
}
imshow("result", img);
waitKey(0);
facemark オブジェクトの学習
- まず、学習パラメータを設定する必要がある
params.n_landmarks = 68; // number of landmark points
params.initShape_n = 10; // number of multiplier for make data augmentation
params.stages_n=5; // amount of refinement stages
params.tree_n=6; // number of tree in the model for each landmark point
params.tree_depth=5; //he depth of decision tree
facemark = FacemarkLBF::create(params);
- そして次に、用意したデータセットからファイルリストを読み込む必要がある。
std::vector<String> images_train;
std::vector<String> landmarks_train;
loadDatasetList("images_train.txt","annotation_train.txt",images_train,landmarks_train);
- 次のステップは、学習サンプルを facemark オブジェクトに追加することである。
Mat image;
std::vector<Point2f> facial_points;
for(size_t i=0;i<images_train.size();i++){
image = imread(images_train[i].c_str());
loadFacePoints(landmarks_train[i],facial_points);
facemark->addTrainingSample(image, facial_points);
}
- 学習処理を実行する
/*train the Algorithm*/
facemark->training();
学習済みモデルを使って、与えられた画像から顔のランドマークを検出する。
- まず最初に、学習済みモデルを読み込む。事前学習済みモデルはこのリンクからダウンロードすることもできる https://raw.githubusercontent.com/kurnianggoro/GSOC2017/master/data/lbfmodel.yaml
facemark->loadModel(params.model_filename);
- 顔を検出する
facemark->getFaces(img, faces, config);
- フィッティング処理を実行する
std::vector<std::vector<Point2f> > landmarks;
facemark->fit(img, faces, landmarks);
- 結果を表示する
for(int j=0;j<faces.size();j++){
face::drawFacemarks(img, landmarks[j], Scalar(0,0,255));
}
imshow("result", img);
waitKey(0);