1. 程式人生 > >Dlib機器學習庫學習系列三----人臉對齊(特徵點檢測)

Dlib機器學習庫學習系列三----人臉對齊(特徵點檢測)

        本篇部落格是Dlib庫學習的第三篇---人臉對齊。人臉對齊與人臉檢測工程建立與配置基本相同,在此不再贅述。可參照我上一篇部落格。閒話少說,來點乾貨。

     步驟一:建立並配置工程,參照上一篇部落格。

     步驟二:下載形狀模型檔案

     下載地址:模型檔案

         步驟三:具體程式碼,這段程式碼也是dlib提供的例子,我自己新增的中文註釋!

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

This example program shows how to find frontal human faces in an image and
estimate their pose.  The pose takes the form of 68 landmarks.  These are
points on the face such as the corners of the mouth, along the eyebrows, on
the eyes, and so forth.
****這個例子展示了怎樣在一張圖片中找到正臉和他們的姿勢.姿勢是由68個點的形式組成的.


//This face detector is made using the classic Histogram of Oriented
Gradients (HOG) feature combined with a linear classifier, an image pyramid,
and sliding window detection scheme.//
****人臉檢測器的原理

The pose estimator was created by
using dlib's implementation of the paper://根據這篇論文編寫的程式
One Millisecond Face Alignment with an Ensemble of Regression Trees by
Vahid Kazemi and Josephine Sullivan, CVPR 2014
and was trained on the iBUG 300-W face landmark dataset.

Also, note that you can train your own models using dlib's machine learning
tools.  See train_shape_predictor_ex.cpp to see an example.
****我們可以訓練自己的模型,用train_shape_predictor_ex.exe


Finally, note that the face detector is fastest when compiled with at least
SSE2 instructions enabled.  So if you are using a PC with an Intel or AMD
chip then you should enable at least SSE2 instructions.  If you are using
cmake to compile this program you can enable them by using one of the
following commands when you create the build project:
cmake path_to_dlib_root/examples -DUSE_SSE2_INSTRUCTIONS=ON
cmake path_to_dlib_root/examples -DUSE_SSE4_INSTRUCTIONS=ON
cmake path_to_dlib_root/examples -DUSE_AVX_INSTRUCTIONS=ON
This will set the appropriate compiler options for GCC, clang, Visual
Studio, or the Intel compiler.  If you are using another compiler then you
need to consult your compiler's manual to determine how to enable these
instructions.  Note that AVX is the fastest but requires a CPU from at least
2011.  SSE4 is the next fastest and is supported by most current machines.
*/


#include <dlib/image_processing/frontal_face_detector.h>
#include <dlib/image_processing/render_face_detections.h>
#include <dlib/image_processing.h>
#include <dlib/gui_widgets.h>
#include <dlib/image_io.h>
#include <iostream>

using namespace dlib;
using namespace std;

// ----------------------------------------------------------------------------------------

int main(int argc, char** argv)
{
	try
	{
		// This example takes in a shape model file and then a list of images to
		// process.  We will take these filenames in as command line arguments.
		// Dlib comes with example images in the examples/faces folder so give
		// those as arguments to this program.
		// 這個例子需要一個形狀模型檔案和一系列的圖片.
		if (argc == 1)
		{
			cout << "Call this program like this:" << endl;
			cout << "./face_landmark_detection_ex shape_predictor_68_face_landmarks.dat faces/*.jpg" << endl;
			cout << "\nYou can get the shape_predictor_68_face_landmarks.dat file from:\n";
			cout << "http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2" << endl;//從這個地址下載模型標記點資料
			return 0;
		}

		// We need a face detector.  We will use this to get bounding boxes for
		// each face in an image.
		//****需要一個人臉檢測器,獲得一個邊界框
		frontal_face_detector detector = get_frontal_face_detector();

		// And we also need a shape_predictor.  This is the tool that will predict face
		// landmark positions given an image and face bounding box.  Here we are just
		// loading the model from the shape_predictor_68_face_landmarks.dat file you gave
		// as a command line argument.
		//****也需要一個形狀預測器,這是一個工具用來預測給定的圖片和臉邊界框的標記點的位置。
		//****這裡我們僅僅從shape_predictor_68_face_landmarks.dat檔案載入模型
		shape_predictor sp;//定義個shape_predictor類的例項
		deserialize(argv[1]) >> sp;


		image_window win, win_faces;
		// Loop over all the images provided on the command line.
		// ****迴圈所有圖片
		for (int i = 2; i < argc; ++i)
		{
			cout << "processing image " << argv[i] << endl;
			array2d<rgb_pixel> img;//注意變數型別 rgb_pixel 三通道彩色影象
			load_image(img, argv[i]);
			// Make the image larger so we can detect small faces.
			pyramid_up(img);

			// Now tell the face detector to give us a list of bounding boxes
			// around all the faces in the image.
			std::vector<rectangle> dets = detector(img);//檢測人臉,獲得邊界框
			cout << "Number of faces detected: " << dets.size() << endl;//檢測到人臉的數量

			// Now we will go ask the shape_predictor to tell us the pose of
			// each face we detected.
			//****呼叫shape_predictor類函式,返回每張人臉的姿勢
			std::vector<full_object_detection> shapes;//注意形狀變數的型別,full_object_detection
			for (unsigned long j = 0; j < dets.size(); ++j)
			{
				full_object_detection shape = sp(img, dets[j]);//預測姿勢,注意輸入是兩個,一個是圖片,另一個是從該圖片檢測到的邊界框
				cout << "number of parts: " << shape.num_parts() << endl;
				//cout << "pixel position of first part:  " << shape.part(0) << endl;//獲得第一個點的座標,注意第一個點是從0開始的
				//cout << "pixel position of second part: " << shape.part(1) << endl;//獲得第二個點的座標
				/*自己改寫,打印出全部68個點*/
				for (int i = 1; i < 69; i++)
				{
					cout << "第 " << i<< " 個點的座標: " << shape.part(i-1) << endl;
				}
				// You get the idea, you can get all the face part locations if
				// you want them.  Here we just store them in shapes so we can
				// put them on the screen.
				shapes.push_back(shape);
			}

			// Now let's view our face poses on the screen.
			//**** 顯示結果
			win.clear_overlay();
			win.set_image(img);
			win.add_overlay(render_face_detections(shapes));

			// We can also extract copies of each face that are cropped, rotated upright,
			// and scaled to a standard size as shown here:
			//****我們也能提取每張剪裁後的人臉的副本,旋轉和縮放到一個標準尺寸
			dlib::array<array2d<rgb_pixel> > face_chips;
			extract_image_chips(img, get_face_chip_details(shapes), face_chips);
			win_faces.set_image(tile_images(face_chips));

			cout << "Hit enter to process the next image..." << endl;
			cin.get();
		}
	}
	catch (exception& e)
	{
		cout << "\nexception thrown!" << endl;
		cout << e.what() << endl;
	}
}

// ----------------------------------------------------------------------------------------
其他的和上一篇部落格相同,祝大家好運!