Opencv與dlib聯合進行人臉關鍵點檢測與識別
阿新 • • 發佈:2019-02-03
前言
依賴庫:opencv 2.4.9 /dlib 19.0/libfacedetection
本篇不記錄如何配置,重點在實現上。使用libfacedetection實現人臉區域檢測,聯合dlib標記人臉特徵點,最後使用opencv的FaceRecognizer實現人臉識別。
準備工作
1、配置好Opencv2.4.9。(Opencv3.1需要另外下載一個包才有FaceRecognizer)
2、配置好dlib 19.0(版本其實沒有多大關係)
3、配置好ShiQi.Yu的人臉檢測庫
思想
訓練模組:人臉檢測——>獲取人臉區域的點座標——>人臉關鍵點標記——>人臉對正——>歸一化處理——>儲存圖片——>手動篩選圖片——>訓練樣本——>得到train.xml
識別模組:讀取train.xml——>迴圈(人臉檢測——>獲取人臉區域的點座標——>人臉關鍵點標記——>人臉對正——>歸一化處理——>送入model->predict——>預測出結果——>putText在方框上寫出名字)
結果
識別速度:0.15~0.25秒,Release平臺。
識別精度:還可以
使用了一段中國好聲音的視訊做識別。
當然,這裡用的是Fisherface演算法,主要還是樣本不多,已經可以搞定了。
程式碼
ReadCSV.h
#include <opencv.hpp>
#include <iostream>
#include <fstream>
using namespace cv;
using namespace std;
static void read_csv(const string& filename, cv::vector <Mat>& images, cv::vector<int>& labels, char separator = ';') {
std::ifstream file(filename.c_str(), ifstream::in);
if (!file) {
string error_message = "No valid input file was given, please check the given filename.";
CV_Error(CV_StsBadArg, error_message);
}
string line, path, classlabel;
while (getline(file, line)) {
stringstream liness(line);
getline(liness, path, separator);
getline(liness, classlabel);
if (!path.empty() && !classlabel.empty()) {
images.push_back(imread(path, 0));
labels.push_back(atoi(classlabel.c_str()));
}
}
}
FaceRotate.h
#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<dlib/opencv/cv_image.h>
#include <dlib/opencv.h>
using namespace dlib;
frontal_face_detector detector = get_frontal_face_detector();
shape_predictor sp;//Already get
FaceRecognition.cpp
#include <FaceDetect.h>
#include <ReadCSV.h>
const int namenumber = 4;//測試的人臉數量
const string textname[namenumber] = { "Hariem", "Miss.Na", "Mr.Wang", "Jay.Chou" };//做一個儲存人臉名字的陣列
Ptr<FaceRecognizer> GetTrainModel(string fn_csv)//輸入CSV檔案的路徑名
{
vector<Mat> images;
vector<int> labels;
try {
read_csv(fn_csv, images, labels);
}
catch (cv::Exception& e) {
cerr << "Error opening file \"" << fn_csv << "\". Reason: " << e.msg << endl;
// 檔案有問題,我們啥也做不了了,退出了
exit(1);
}
// 如果沒有讀取到足夠圖片,我們也得退出.
if (images.size() <= 1) {
string error_message = "This demo needs at least 2 images to work. Please add more images to your data set!";
CV_Error(CV_StsError, error_message);
}
Ptr<FaceRecognizer> model = createEigenFaceRecognizer(80);//建立人臉識別類 可修改 LBPHFace、EigenFace、FisherFace
model->train(images, labels);
return model;
}
int main()
{
Dlib_Predefine();//載入dlib的檔案
Ptr<FaceRecognizer> model = GetTrainModel("face.csv");//獲得模型
VideoCapture cap("好聲音.mp4");
Mat frame,gray;
while (true)
{
cap >> frame;
if (!frame.empty())
{
gray = FaceDetect(frame);
if (!gray.empty())
putText(frame, textname[model->predict(gray)], Point(50, 50), FONT_HERSHEY_DUPLEX, 3, Scalar(230, 255, 0), 2);//model->predict(frame) = predictLabel 名字寫在 1 1
imshow("Face Recogniton", frame);
waitKey(1);
}
else{ cout << "The Video's end." <<endl; break; }
}
}
FaceDetect.cpp
用了掩碼。
#include <FaceDetect.h>
#include <FaceRotate.h>
void Dlib_Predefine()
{
deserialize("shape_predictor_68_face_landmarks.dat") >> sp;//讀入標記點檔案
}
cv::Mat FaceToOne(cv::Mat source)//歸一化處理函式
{
cv::equalizeHist(source, source);//直方圖均衡
cv::resize(source, source, cv::Size(92, 112));//裁剪
cv::Mat Mask = cv::imread("mask.jpg", 0);
cv::Mat changedMask;
source.copyTo(changedMask, Mask);
return changedMask;
}
Mat FaceDetect(Mat frame)//臉是否存在
{
Mat gray, error;
cvtColor(frame, gray, CV_BGR2GRAY);
int * pResults = NULL;
pResults = facedetect_frontal_tmp((unsigned char*)(gray.ptr(0)), gray.cols, gray.rows, gray.step, 1.2f, 5, 24);
int peopleNUM = (pResults ? *pResults : 0);
for (int i = 0; i < peopleNUM; i++)//代表有幾張人臉(pResults ? *pResults : 0)
{
short * p = ((short*)(pResults + 1)) + 6 * i;
Rect opencvRect(p[0], p[1], p[2], p[3]);
//gray = gray(opencvRect);
cv::rectangle(frame, opencvRect, Scalar(230, 255, 0));
dlib::rectangle dlibRect((long)opencvRect.tl().x, (long)opencvRect.tl().y, (long)opencvRect.br().x - 1, (long)opencvRect.br().y - 1);
//人臉對齊技術提高了準確率
dlib::full_object_detection shape = sp(dlib::cv_image<uchar>(gray), dlibRect);//標記點
std::vector<full_object_detection> shapes;
shapes.push_back(shape);//把點儲存在了shape中
dlib::array<array2d<rgb_pixel>> face_chips;
extract_image_chips(dlib::cv_image<uchar>(gray), get_face_chip_details(shapes), face_chips);
Mat pic = toMat(face_chips[0]);
cvtColor(pic, pic, CV_BGR2GRAY);
return FaceToOne(pic);
}
return error;
}
FaceDetect.h
#include <opencv.hpp>
#include "facedetect-dll.h"
using namespace cv;
using namespace std;
Mat FaceDetect(Mat frame);
void Dlib_Predefine();//dlib 預定義的函式
FaceRotate.h
#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<dlib/opencv/cv_image.h>
#include <dlib/opencv.h>
using namespace dlib;
frontal_face_detector detector = get_frontal_face_detector();
shape_predictor sp;//Already get
Mask圖片: