DlibとOpenCVを用いたVtuber撮影システムの開発　#2(顔認識)


**[前回の記事 DlibとOpenCVを用いたVtuber撮影システムの開発　#1(開発環境構築)](https://qiita.com/ToneTec/items/a5ada446721c614c2dce)**
###1.　Dlib_WebcamFaceTrackerの開発
さて、早速フェイストラッキング用プログラム、「Dlib_WebcamFaceTracker」を開発しましょう。
この開発では以下のものを使用します。
■開発ツール
・Visual Studio2015 Community
■学習済みモデル(顔認識AI)
・shape_predictor_68_face_landmarks.dat.bz2
　⇒解凍して生成された「shape_predictor_68_face_landmarks.dat」を「sp.dat」にリネームしてください
■仕様
・Webカメラの画像から顔と顔の器官点を検出し、顔の角度をUDPで送信する。

なお、下のリンクから各種設定済みのVisualStudioプロジェクトをDLできます。
これを使用する場合は**3.動作確認**から手順を開始してください。
https://github.com/ProcamperKamekichi/Dlib_BasicSample

###2 実装
####2-1.　VsualStudioプロジェクトの作成
1．スタートメニューから新しいプロジェクト　を選択
2．「新しいプロジェクト」ウィザードからテンプレート>Win32コンソールアプリケーション　を選択
3．名前を「Dlib_WebcamFaceTracker」と入力
4．ソリューション名を「Dlib_BasicSample」と入力
5．「ソリューションのディレクトリを作成」チェックを"ON"にする
6．「OK」をクリック
以下の図を参考にしてください
![image.png](https://qiita-image-store.s3.amazonaws.com/0/150780/775d6bce-8656-ea86-5f21-ad4fea3a189b.png)

7．「Win32アプリケーション　ウィザード」を以下のように設定して「完了」をクリック
![image.png](https://qiita-image-store.s3.amazonaws.com/0/150780/3a8b9a7e-780b-8fe5-38c0-11c8fdf24243.png)


####2-2.　サンプルコード作成
それでは、サンプルコードを作成しましょう。
以下のコードをそのまま「Dlib_WebcamFaceTracker.cpp」にコピペしてください

```C++:Dlib_WebcamFaceTracker.cpp
#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <dlib/opencv.h>
#include <dlib/image_processing/frontal_face_detector.h>
#include <dlib/image_processing/render_face_detections.h>
#include <dlib/image_processing.h>
#include "picojson.h"
#include <windows.h>

//フィルタ用の係数
#define LPF_VALUE_PRE  0.4
#define LPF_VALUE_CUR  (1 - LPF_VALUE_PRE)
#define FACIAL_POINTS   68

//カメラのパラメータ(固定値)
double K[9] = { 6.5308391993466671e+002, 0.0, 3.1950000000000000e+002, 0.0, 6.5308391993466671e+002, 2.3950000000000000e+002, 0.0, 0.0, 1.0 };
double D[5] = { 7.0834633684407095e-002, 6.9140193737175351e-002, 0.0, 0.0, -1.3073460323689292e+000 };

class face
{
public:
	float horizontal_pos;
	float vertical_pos;
	float yaw;
	float pitch;
	float roll;
	float eye_L_X;
	float eye_L_Y;
};

using namespace std;

/* ローカル関数 */
static void DrawFaceBox(cv::Mat frame, std::vector<cv::Point2d> reprojectdst);
static void SetInitialPoints(std::vector<cv::Point3d> * in_BoxPoints, std::vector<cv::Point3d> * in_FaceLandmarkPoints);

int main(int argc, char** argv)
{
	/************ カメラ番号取得 ************/
	int cam_num;
	face actor;
	//cout << "input camera num --> "; cin >> cam_num;
	//getchar();
	//カメラオープン
	cv::VideoCapture cap(0);
	if (!cap.isOpened())
	{
		std::cout << "Unable to connect to camera" << std::endl;
		return EXIT_FAILURE;
	}
	//------------------------------------//

	/************ ソケット初期化 ************/
	int sock;
	WSAData wsaData;
	struct sockaddr_in addr;
	WSAStartup(MAKEWORD(2, 0), &wsaData);
	sock = socket(AF_INET, SOCK_DGRAM, 0);

	addr.sin_family = AF_INET;
	addr.sin_port = htons(22222);
	addr.sin_addr.s_addr = inet_addr("127.0.0.1");

	sendto(sock, "HELLO", 5, 0, (struct sockaddr *)&addr, sizeof(addr));
	//-------------------------------//


	/************ 検出器の初期化************/
	//顔検出器
	//(DlibのAPIに実装されているものをそのまま使用する
	dlib::frontal_face_detector detector = dlib::get_frontal_face_detector();

	//顔器官点検出器
	//外部ファイルから検出器を読み込み(EXEコール時の第1引数)
	dlib::shape_predictor predictor;
	dlib::deserialize("sp.dat") >> predictor;
	//-------------------------------//


	//カメラの組み込み関数と歪み係数を設定
	cv::Mat cam_matrix = cv::Mat(3, 3, CV_64FC1, K);
	cv::Mat dist_coeffs = cv::Mat(5, 1, CV_64FC1, D);

	//顔器官の3D座標初期値
	std::vector<cv::Point3d> object_pts;
	//顔向きを示す矩形の3D座標初期値
	std::vector<cv::Point3d> reprojectsrc;
	//初期値を設定
	SetInitialPoints(&reprojectsrc, &object_pts);

	//result
	cv::Mat rotation_vec;                           //回天ベクトル
	cv::Mat rotation_mat;                           //回天行列
	cv::Mat translation_vec;                        //変換ベクトル
	cv::Mat pose_mat = cv::Mat(3, 4, CV_64FC1);     //姿勢(3X4の配列)
	cv::Mat euler_angle = cv::Mat(3, 1, CV_64FC1);  //オイラー角(3X1の配列)
	cv::Mat prev_euler_angle = cv::Mat(3, 1, CV_64FC1); //前フレームでのオイラー角(3X1の配列)

														//2D座標格納データ
	std::vector<cv::Point2d> reprojectdst;
	reprojectdst.resize(8);

	//顔認識には使用しない
	//使用するAPIの引数を埋めるために使用する
	cv::Mat out_intrinsics = cv::Mat(3, 3, CV_64FC1);
	cv::Mat out_rotation = cv::Mat(3, 3, CV_64FC1);
	cv::Mat out_translation = cv::Mat(3, 1, CV_64FC1);

	//画面表示用テキスト
	std::ostringstream outtext;

	//メインループ
	while (1)
	{
		//カメラから現在の画像フレームを取得
		cv::Mat temp;
		cap >> temp;
		//DlibのAPIで使用するために変換
		dlib::cv_image<dlib::bgr_pixel> cimg(temp);

		//画像データを顔検出器にかける
		std::vector<dlib::rectangle> faces = detector(cimg);

		// 1個以上の顔を検出している場合
		if (faces.size() > 0)
		{
			//そのフレームで検出された最初の顔を、顔器官点検出器にかける
			dlib::full_object_detection shape = predictor(cimg, faces[0]);
			//顔器官点検出器から、顔の領域を取得
			auto rect = shape.get_rect();

			//器官点を描画
			for (unsigned int i = 0; i < FACIAL_POINTS; ++i)
			{
				cv::circle(
					temp,                   //描画先の画像データ
					cv::Point(              //顔器官点の2D点オブジェクト
						shape.part(i).x(),
						shape.part(i).y()),
					2,                      //点のサイズ
					cv::Scalar(0, 0, 255),  //点の色
					-1);
			}

			//画面上の2D座標の一部を格納
			//顔の姿勢検出のため、一部の顔器官点を別の場所に格納する
			std::vector<cv::Point2d> image_pts;
			image_pts.push_back(cv::Point2d(shape.part(17).x(), shape.part(17).y())); //#17 右眉右端
			image_pts.push_back(cv::Point2d(shape.part(21).x(), shape.part(21).y())); //#21 右眉左端
			image_pts.push_back(cv::Point2d(shape.part(22).x(), shape.part(22).y())); //#22 左眉右端
			image_pts.push_back(cv::Point2d(shape.part(26).x(), shape.part(26).y())); //#26 左眉左端

			image_pts.push_back(cv::Point2d(shape.part(36).x(), shape.part(36).y())); //#36 右目右端
			image_pts.push_back(cv::Point2d(shape.part(39).x(), shape.part(39).y())); //#39 右目左端
			image_pts.push_back(cv::Point2d(shape.part(42).x(), shape.part(42).y())); //#42 左目右端
			image_pts.push_back(cv::Point2d(shape.part(45).x(), shape.part(45).y())); //#45 左目左端
			image_pts.push_back(cv::Point2d(shape.part(31).x(), shape.part(31).y())); //#31 鼻右
			image_pts.push_back(cv::Point2d(shape.part(35).x(), shape.part(35).y())); //#35 鼻左
			image_pts.push_back(cv::Point2d(shape.part(48).x(), shape.part(48).y())); //#48 口右
			image_pts.push_back(cv::Point2d(shape.part(54).x(), shape.part(54).y())); //#54 口左
			image_pts.push_back(cv::Point2d(shape.part(57).x(), shape.part(57).y())); //#57 口中央下
			image_pts.push_back(cv::Point2d(shape.part(8).x(), shape.part(8).y()));   //#8  顎

																					  //顔器官点の3D座標初期値、カメラ情報、検出した2D座標から
																					  //顔器官点の3D座標現在値と姿勢情報を算出する
			cv::solvePnP(object_pts, image_pts, cam_matrix, dist_coeffs, rotation_vec, translation_vec);

			//顔向き矩形の3D座標初期値と直前に取得した姿勢情報から
			//顔向き矩形の3D座標現在値を算出する
			cv::projectPoints(reprojectsrc, rotation_vec, translation_vec, cam_matrix, dist_coeffs, reprojectdst);

			//顔向き矩形を描画する
			DrawFaceBox(temp, reprojectdst);

			//顔向き矩形の対角線交点の座標を算出
			cv::Point2d P1(reprojectdst[8].x, reprojectdst[8].y);
			cv::Point2d P2(reprojectdst[9].x, reprojectdst[9].y);
			cv::Point2d P3(reprojectdst[10].x, reprojectdst[10].y);
			cv::Point2d P4(reprojectdst[11].x, reprojectdst[11].y);
			double S1 = ((P4.x - P2.x) * (P1.y - P2.y) - (P4.y - P2.y) * (P1.x - P2.x)) / 2;
			double S2 = ((P4.x - P2.x) * (P2.y - P3.y) - (P4.y - P2.y) * (P2.x - P3.x)) / 2;
			long Center_X = P1.x + (P3.x - P1.x) * S1 / (S1 + S2);
			long Center_Y = P1.y + (P3.y - P1.y) * S1 / (S1 + S2);
			//顔の現在位置として使用する
			cv::Point2d CenterPoint(Center_X, Center_Y);
			actor.horizontal_pos = ((float)Center_X / 2) / 640;
			actor.vertical_pos = ((float)Center_Y / 2) / 360;

			//算出した現在の顔の姿勢情報を行列からオイラー角に変換する
			//オイラー角→0度、30度、90度などの一般的な「角度」の表現方法
			cv::Rodrigues(rotation_vec, rotation_mat);
			cv::hconcat(rotation_mat, translation_vec, pose_mat);
			cv::decomposeProjectionMatrix(pose_mat, out_intrinsics, out_rotation, out_translation, cv::noArray(), cv::noArray(), cv::noArray(), euler_angle);

			//この手の顔認識は、光やカメラ、背景の状態などによって常にノイズが入っている
			//(早い話が、顔が常にブルブル震えた状態になる)
			//そこで、一定値以下の姿勢変化は無視し、かつ変化量がスムーズになるよう
			//フィルタ処理をかけ、姿勢の変化を滑らかにする
			//ついでに、左右35度以上には曲がらないように制限する。
			for (int i = 0; i < 3; i++)
			{
				if (euler_angle.at<double>(i) > 35) euler_angle.at<double>(i) = 35;
				if (euler_angle.at<double>(i) < -35) euler_angle.at<double>(i) = -35;
				if ((std::abs(prev_euler_angle.at<double>(i) - euler_angle.at<double>(i)) > 1))
				{
					if (prev_euler_angle.at<double>(i) > euler_angle.at<double>(i))
					{
						euler_angle.at<double>(i) -= 0.005;
					}
					else
					{
						euler_angle.at<double>(i) += 0.005;
					}
					euler_angle.at<double>(i) = (LPF_VALUE_PRE * prev_euler_angle.at<double>(i))
						+ (LPF_VALUE_CUR * euler_angle.at<double>(i));
				}
				else
				{
					euler_angle.at<double>(i) = prev_euler_angle.at<double>(i);
				}
			}
			prev_euler_angle.at<double>(0) = euler_angle.at<double>(0);
			prev_euler_angle.at<double>(1) = euler_angle.at<double>(1);
			prev_euler_angle.at<double>(2) = euler_angle.at<double>(2);

			//取得した顔の位置、姿勢を画面上に表示する
			outtext << "X: " << std::setprecision(3) << euler_angle.at<double>(0);
			cv::putText(temp, outtext.str(), cv::Point(50, 40), cv::FONT_HERSHEY_SIMPLEX, 0.75, cv::Scalar(0, 0, 0));
			outtext.str("");
			outtext << "Y: " << std::setprecision(3) << euler_angle.at<double>(1);
			cv::putText(temp, outtext.str(), cv::Point(50, 60), cv::FONT_HERSHEY_SIMPLEX, 0.75, cv::Scalar(0, 0, 0));
			outtext.str("");
			outtext << "Z: " << std::setprecision(3) << euler_angle.at<double>(2);
			cv::putText(temp, outtext.str(), cv::Point(50, 80), cv::FONT_HERSHEY_SIMPLEX, 0.75, cv::Scalar(0, 0, 0));
			outtext.str("");

			outtext << "Pos_X: " << std::setprecision(3) << actor.horizontal_pos;
			cv::putText(temp, outtext.str(), cv::Point(50, 100), cv::FONT_HERSHEY_SIMPLEX, 0.75, cv::Scalar(0, 0, 0));
			outtext.str("");

			outtext << "Pos_Y: " << std::setprecision(3) << actor.vertical_pos;
			cv::putText(temp, outtext.str(), cv::Point(50, 120), cv::FONT_HERSHEY_SIMPLEX, 0.75, cv::Scalar(0, 0, 0));
			outtext.str("");
			actor.yaw = euler_angle.at<double>(1);
			actor.pitch = euler_angle.at<double>(0);
			actor.roll = euler_angle.at<double>(2);

			//Unity側への送信用データを作成する
			picojson::object obj;
			//顔位置X座標
			obj.emplace(std::make_pair("horizontal_pos", actor.horizontal_pos));
			//顔位置Y座標
			obj.emplace(std::make_pair("vertical_pos", actor.vertical_pos));
			//顔姿勢 Y軸
			obj.emplace(std::make_pair("yow", actor.yaw));
			//顔姿勢 X軸
			obj.emplace(std::make_pair("pitch", actor.pitch));
			//顔姿勢 Z軸
			obj.emplace(std::make_pair("roll", actor.roll));
			//全部の顔器官点を格納
			picojson::array mouse;
			for (unsigned int i = 0; i < FACIAL_POINTS; ++i)
			{
				picojson::array coord;
				coord.push_back(picojson::value((double)shape.part(i).x()));
				coord.push_back(picojson::value((double)shape.part(i).y()));
				mouse.push_back(picojson::value(coord));
			}
			obj.emplace(std::make_pair("obj", picojson::value(mouse)));
			//文字列に変換
			picojson::value val(obj);

			//シリアライズ
			std::string msg = val.serialize();
			//送信
			sendto(sock, msg.c_str(), msg.size(), 0, (struct sockaddr *)&addr, sizeof(addr));

			//顔器官点をクリア
			image_pts.clear();
			//press esc to end
			//escで終了
			auto key = cvWaitKey(2);
			if (key == '\x1b')
			{
				break;
			}
		}
		Sleep(1 / 1000);
		//カメラから取得した映像を出力
		cv::imshow("demo", temp);
		//なぜかこれやると映像出力が動く
		cvWaitKey(1);
	}

	return 0;
}


void DrawFaceBox(cv::Mat frame, std::vector<cv::Point2d> reprojectdst)
{
	cv::line(frame, reprojectdst[8], reprojectdst[9], cv::Scalar(0, 0, 255));
	cv::line(frame, reprojectdst[9], reprojectdst[10], cv::Scalar(0, 0, 255));
	cv::line(frame, reprojectdst[10], reprojectdst[11], cv::Scalar(0, 0, 255));
	cv::line(frame, reprojectdst[11], reprojectdst[8], cv::Scalar(0, 0, 255));

	cv::line(frame, reprojectdst[8], reprojectdst[10], cv::Scalar(0, 0, 255));
	cv::line(frame, reprojectdst[9], reprojectdst[11], cv::Scalar(0, 0, 255));
}

void SetInitialPoints(std::vector<cv::Point3d> * in_BoxPoints, std::vector<cv::Point3d> * in_FaceLandmarkPoints)
{
	std::vector<cv::Point3d> reprojectsrc = (std::vector<cv::Point3d>) *in_BoxPoints;
	std::vector<cv::Point3d> object_pts = (std::vector<cv::Point3d>) *in_FaceLandmarkPoints;

	reprojectsrc.push_back(cv::Point3d(10.0, 10.0, 10.0));
	reprojectsrc.push_back(cv::Point3d(10.0, 10.0, -10.0));
	reprojectsrc.push_back(cv::Point3d(10.0, -10.0, -10.0));
	reprojectsrc.push_back(cv::Point3d(10.0, -10.0, 10.0));
	reprojectsrc.push_back(cv::Point3d(-10.0, 10.0, 10.0));
	reprojectsrc.push_back(cv::Point3d(-10.0, 10.0, -10.0));
	reprojectsrc.push_back(cv::Point3d(-10.0, -10.0, -10.0));
	reprojectsrc.push_back(cv::Point3d(-10.0, -10.0, 10.0));

	reprojectsrc.push_back(cv::Point3d(-10.0, -10.0, 0));
	reprojectsrc.push_back(cv::Point3d(10.0, -10.0, 0));
	reprojectsrc.push_back(cv::Point3d(10.0, 10.0, 0));
	reprojectsrc.push_back(cv::Point3d(-10.0, 10.0, 0));

	//顔器官点の3D座標初期値,  この点を基準に、顔の姿勢を算出する 
	//参照元 http://aifi.isr.uc.pt/Downloads/OpenGL/glAnthropometric3DModel.cpp
	object_pts.push_back(cv::Point3d(6.825897, 6.760612, 4.402142));     //#33 右眉右端
	object_pts.push_back(cv::Point3d(1.330353, 7.122144, 6.903745));     //#29 右眉左端
	object_pts.push_back(cv::Point3d(-1.330353, 7.122144, 6.903745));    //#34 左眉右端
	object_pts.push_back(cv::Point3d(-6.825897, 6.760612, 4.402142));    //#38 左眉左端
	object_pts.push_back(cv::Point3d(5.311432, 5.485328, 3.987654));     //#13 右目右端
	object_pts.push_back(cv::Point3d(1.789930, 5.393625, 4.413414));     //#17 右目左端
	object_pts.push_back(cv::Point3d(-1.789930, 5.393625, 4.413414));    //#25 左目右端
	object_pts.push_back(cv::Point3d(-5.311432, 5.485328, 3.987654));    //#21 左目左端
	object_pts.push_back(cv::Point3d(2.005628, 1.409845, 6.165652));     //#55 鼻右
	object_pts.push_back(cv::Point3d(-2.005628, 1.409845, 6.165652));    //#49 鼻左
	object_pts.push_back(cv::Point3d(2.774015, -2.080775, 5.048531));    //#43 口右
	object_pts.push_back(cv::Point3d(-2.774015, -2.080775, 5.048531));   //#39 口左
	object_pts.push_back(cv::Point3d(0.000000, -3.116408, 6.097667));    //#45 口中央下
	object_pts.push_back(cv::Point3d(0.000000, -7.415691, 4.070434));    //#6 顎
	*in_BoxPoints = reprojectsrc;
	*in_FaceLandmarkPoints = object_pts;
}
```
コピペした後、おそらくはエディタが**こんな感じ**にコンパイルエラーだらけになっていると思います。以下の操作を行ってコンパイルエラーを解消しましょう。
![スクリーンショット 2018-11-12 00.27.22.png](https://qiita-image-store.s3.amazonaws.com/0/150780/659c2246-241e-479e-20a2-2061e8e402b8.png)


####2-3.　PicoJsonのインストール
まずはPicoJsonをインストールします。
1．[PicoJson開発者のGithub](https://github.com/kazuho/picojson)　から
「Clone or Download」>　DownloadZip　を選択して、ファイル一式をダウンロードしてください。（下図参照）
![スクリーンショット 2018-11-12 00.37.32.png](https://qiita-image-store.s3.amazonaws.com/0/150780/c3e438db-499d-adae-57aa-9554ad6c725d.png)
2．ダウンロードしたファイルを任意のフォルダに解凍します。
3．解凍したフォルダにある「picojson.h」をVisualStudioのソリューションエクスプローラー＞ヘッダーファイル
にドラッグアンドドロップしてください。
これで、PicoJsonの導入は完了です。


####2-4.　インクルードディレクトリの設定
インクルードディレクトリを設定します。
1．下の図を参考に、ソリューションエクスプローラー ⇒ Dlib_WebCamFaceTracker右クリック ⇒ プロパティをクリックして下さい。
「Dlib_WebCamFaceTrackerのプロパティページ」ウィンドウが開いたら、次の手順に進んでください。
![2019-03-27 (5).png](https://qiita-image-store.s3.amazonaws.com/0/150780/ea65dc35-fe98-25c5-86f0-48cc722dff1f.png)


2．「Dlib_WebCamFaceTrackerのプロパティページ」にて、下の図を参考に
構成プロパティ ⇒ VC++ディレクトリ ⇒ インクルードディレクトリ ⇒ V ⇒ 〈編集...〉をクリックして下さい。
「インクルードディレクトリ」ウィンドウが出現したら、次の手順に進んでください。
![2019-03-27 (7).png](https://qiita-image-store.s3.amazonaws.com/0/150780/45f27b98-e610-7535-5cb8-c5dd4ad7b0b0.png)

3．「インクルードディレクトリ」ウィンドウ内にて、以下のパスを追加してください
　C:\dnn\dlib-19.16\
　C:\dnn\opencv\build\include
![2019-03-27 (9).png](https://qiita-image-store.s3.amazonaws.com/0/150780/1f138899-0913-7b17-6797-07d9a8e07b04.png)


####2-5.　ライブラリディレクトリの設定
上に続き、ライブラリディレクトリを設定します。
1．構成プロパティ ⇒ リンカー ⇒ 全般 の追加のライブラリディレクトリ ⇒ 〈編集...〉をクリックして下さい。
「追加のライブラリディレクトリ」ウィンドウが出現したら、次の手順に進んでください。

![2019-03-27 (12).png](https://qiita-image-store.s3.amazonaws.com/0/150780/21772e6c-cc7e-f12c-7fc5-0c70c1b5436b.png)

2．「追加のライブラリディレクトリ」ウィンドウにて、以下のパスを追加してください
　C:\dnn\opencv\build\x64\vc15\lib
　C:\dnn\dlib-19.16\dlib\build\Release
![2019-03-27 (13).png](https://qiita-image-store.s3.amazonaws.com/0/150780/8cedcb97-a9f7-21c2-b8f8-1ce95a15b774.png)

####2-6.　ライブラリファイルの設定
最後に、ライブラリファイルを設定します。
1．構成プロパティ ⇒ リンカー ⇒ 入力 ⇒ 追加の依存ファイル ⇒〈編集...〉をクリックして下さい。
「追加の依存ファイル」ウィンドウが出現したら、次の手順に進んでください。

2．「追加の依存ファイル」ウィンドウにて、以下のファイル名を追加してください。
　dlib19.16.0_release_64bit_msvc1900.lib
　opencv_world343.lib
　wsock32.lib
![2019-03-28 (7).png](https://qiita-image-store.s3.amazonaws.com/0/150780/ba936159-6f0a-9ae1-7af7-52e269c31d93.png)

これで、すべてのコンパイルエラーが解消されたはずです。
もし解消されない場合、下のQA欄を参考に対応してみてください
###3.動作確認
さて、ではビルドしてみましょう。下の図を参考に、プロジェクトをビルドしてください![2019-03-28 (2).png](https://qiita-image-store.s3.amazonaws.com/0/150780/add06d48-a50e-27fc-0478-f8f9cdda5d0b.png)

ビルドが成功したら、　Visual Studio 2015\Projects\Dlib_BasicSample\x64\Release　のフォルダ内に以下のファイルをコピーしてください
　opencv_world343.dll
　sp.dat

これで、すべての準備が完了しました。

PCにWebカメラを接続し、Dlib_WebcamFaceTracker.exeをクリックして下さい
下のような画面が表示されれば成功です
![Desktop 2019-03-28 0-34-45-802.png](https://qiita-image-store.s3.amazonaws.com/0/150780/2a5d4189-9918-ec96-32dc-52751d0b5386.png)


###4.プログラム解説
T.B.D


次の記事　にて、2．FaceController　を開発します。

###5.Q&A　
Q1．コンパイルエラーが消えません
A1．構成プロパティ⇒C/C++⇒プリコンパイル済みヘッダーを開き、「プリコンパイル済みヘッダーを使用しない」が選択されているか確認してください

Q2．やっぱりコンパイルエラーが消えないんだけど？
A2．「Dlib_WebCamFaceTrackerのプロパティページ」上部、矢印の部分が「すべての構成」「X64」になっているか確認してください。
そうでない場合は、矢印部分を「すべての構成」「x64」に設定し、**2-4.　インクルードディレクトリの設定**を実行してみてください。
![2019-03-28 (8).png](https://qiita-image-store.s3.amazonaws.com/0/150780/b718af60-af4c-d511-57a5-6106c1c47275.png)

Q3．コンパイルエラーは消えたけど、ビルド中にエラーが出ます。
A3．**2-6ライブラリファイルの設定**のファイル名が正しいかどうか確認してください。
　dlib19.16.0_release_64bit_msvc1900.lib
　opencv_world343.lib
これらのファイルは、Dlib,OpenCVのバージョンが異なる場合、変更されている可能性があります。
下記パスを確認し、ファイル名が正しいかどうか確認してみてください。
C:\dnn\opencv\build\x64\vc15\lib
C:\dnn\dlib-19.16\dlib\build\Release;
※前回の記事「DlibとOpenCVを用いたVtuber撮影システムの開発　#1(開発環境構築)」の表記とは異なるパスにDlib,OpenCVをインストールした場合は、そのパスを確認してください


##参考文献
[Visual Studio 2017でDlibをビルドする -環境構築編-]
(https://blog.nextscape.net/archives/Date/2017/12/dlib-01)
[Visual Studio 2017でDlibをビルドする -サンプル実行編-]
(https://blog.nextscape.net/archives/Date/2017/12/dlib-02)
[顔向き推定について調査中]
(https://qiita.com/nonbiri15/items/f6910a993457a1862632)
[実質無料でバーチャルユーチューバーになる方法 こたつにっき]
(http://kotatu99.hateblo.jp/entry/2018/03/04/195505)
[C++からjsonを簡単に生成する方法(picojson)]
(http://blog.livedoor.jp/itahidamito/archives/51726902.html)