SeetaFace人脸识别系统

来源:互联网 发布:淘宝商城开店要多少钱 编辑:程序博客网 时间:2024/06/09 17:40

简介

SeetaFace人脸识别解决方案已开源许久,一直拖到最近才看。它提供了一套完整的人脸检测,人脸对齐和人脸验证方案,比较适合做学习。由于开源的代码是DLL项,现编译完成之后,对其进了一定封装,,实现了人脸特征提取,入库保存,以及人脸识别等。
对该系统的介绍可以参见:SeetaFace开源人脸识别引擎介绍
本文主要参考:SeetaFace教程: 在 VS 中的编译安装和环境配置  并做了部分整合与修改。

准备

在这之前,请自行下载SeetaFace源码,并编译出三个lib文件和三个dll文件。我编译出的是
FaceIdentification.lib  FaceIdentification.dll
FaceAlignment.lib   FaceAlignment.dll
FaceDetection.lib    FaceDetection.dll

编译时直接打开源码里面的example解决方案即可,编译dll文件时无需任何额外的依赖项,只有在测试时才需要opencv。如果不太明白,也可参考上面简介中给出的SeetaFace教程链接,不过我觉得他那有点多余。

项目

新建win32控制台项目,此时需要opencv,我在测试时使用的是opencv2.4.10,其他的应该也行。
① 将项目属性改为x64
② 在配置属性-VC++目录中,将opencv的包含目录和库目录修改好,记得使用x64的lib库
③ 链接器-输入,加入FaceIdentification.lib  FaceAlignment.lib  FaceDetection.lib  opencv_core2410.lib  opencv_highgui2410.lib  opencv_imgproc2410.lib
④ 与这6个lib文件相对于的dll文件放入可执行文件目录下即可。
⑤ 将seetaface源码中的三个model,放在一起,存于项目文件夹下即可。images文件夹中为一些测试图片
项目整体结构

源码

FeatureGroup.h

#ifndef FEATUREGROUP_H#define FEATUREGROUP_H#include <fstream>#include <io.h>#include <queue>#include <string>#include "FaceRecognition.h"struct Feature{std::string filename;float* data;float similarity_with_goal;friend bool operator < (Feature f1, Feature f2){return f1.similarity_with_goal < f2.similarity_with_goal;}};class FeatureGroup{public:FeatureGroup(int feat_dims, FaceRecognition* fr);FeatureGroup(string model_file, FaceRecognition* fr);bool AddFeature(float* feat, string filename);bool SaveModel(string model_file);int GetFeatureDims();bool FindTopK(int k, float* feat, std::vector<Feature>& result);~FeatureGroup();public:std::vector<Feature> features;private:int feat_dims;  FaceRecognition* fr;};#endif //FEATUREGROUP_H

FeatureGroup.cpp
#include "FeatureGroup.h"FeatureGroup::FeatureGroup(int feat_dims, FaceRecognition* fr){this->feat_dims = feat_dims;this->fr = fr;}FeatureGroup::FeatureGroup(string model_file, FaceRecognition* fr){std::ifstream file;file.open(model_file);int size;float* new_feat;char* buffer = new char[1000];//从模型读取数据file >> size;file >> this->feat_dims;for (int i = 0; i < size; i++){Feature tmp;file.getline(buffer, 1000);while (buffer[0] == '\0' || buffer[0] == ' '){file.getline(buffer, 1000);}tmp.filename = buffer;new_feat = new float[this->feat_dims];for (int j = 0; j < this->feat_dims; j++){file >> new_feat[j];}tmp.data = new_feat;this->features.push_back(tmp);}file.close();this->fr = fr;}int FeatureGroup::GetFeatureDims(){return this->feat_dims;}bool FeatureGroup::AddFeature(float* feat, string filename){Feature tmp;float* new_feat = new float[this->feat_dims];//memcpy(new_feat, feat, sizeof(new_feat) * this->feat_dims);// 这句话执行有问题,改成下面的循环for (int i = 0; i < this->feat_dims; i++){new_feat[i] = feat[i];}tmp.data = new_feat;tmp.filename = filename;this->features.push_back(tmp);return true;}bool FeatureGroup::SaveModel(string model_file){std::ofstream file;file.open(model_file);file << int(this->features.size()) << std::endl; //先输出特征的个数file << this->feat_dims << std::endl; //再输出特征的维数//依次写入数据for (int i = 0; i < int(this->features.size()); i++){file << this->features[i].filename << std::endl;for (int j = 0; j < this->feat_dims; j++){file << this->features[i].data[j] << " ";}file << std::endl;}file.close();return true;}bool FeatureGroup::FindTopK(int k, float* feat, std::vector<Feature>& result){std::cout << "Calculating Similarities..." << std::endl;for (int i = 0; i < int(this->features.size()); i++){this->features[i].similarity_with_goal = this->fr->FeatureCompare(this->features[i].data, feat);}std::cout << "Finding Topk..." << std::endl;std::priority_queue<Feature> q;for (int i = 0; i < int(this->features.size()); i++){q.push(this->features[i]);}for (int i = 0; i < k; i++){if (q.empty())return true;result.push_back(q.top());q.pop();}return true;}FeatureGroup::~FeatureGroup()  //如果出错,再回来修改{for (int i = 0; i < int(this->features.size()); i++){delete [](this->features[i].data);}}

FaceRecognition.h
#ifndef FACERECOGNITION_H#define FACERECOGNITION_H#include <string>#include<iostream>using std::string;#include <opencv/cv.h>#include <opencv/highgui.h>#include "face_detection.h"#include "face_alignment.h"#include "face_identification.h"class Detector : public seeta::FaceDetection{public:Detector(const char * model_name);};class FaceRecognition{public:FaceRecognition();float* NewFeatureBuffer();float FeatureCompare(float* feat1, float* feat2);int GetFeatureDims();bool GetFeature(string filename, float* feat);~FaceRecognition();public:Detector* detector;seeta::FaceAlignment* point_detector;seeta::FaceIdentification* face_recognizer;};#endif // !FACERECOGNITION_H

FaceRecognition.cpp
#include "FaceRecognition.h"Detector::Detector(const char* model_name) :seeta::FaceDetection(model_name){this->SetMinFaceSize(40);this->SetScoreThresh(2.f);this->SetImagePyramidScaleFactor(0.8f);this->SetWindowStep(4, 4);}FaceRecognition::FaceRecognition(){this->detector = new Detector("model/seeta_fd_frontal_v1.0.bin");this->point_detector = new seeta::FaceAlignment("model/seeta_fa_v1.1.bin");this->face_recognizer = new seeta::FaceIdentification("model/seeta_fr_v1.0.bin");}float* FaceRecognition::NewFeatureBuffer(){return new float[this->face_recognizer->feature_size()];}int FaceRecognition::GetFeatureDims(){return this->face_recognizer->feature_size();}float FaceRecognition::FeatureCompare(float* feat1, float* feat2){return this->face_recognizer->CalcSimilarity(feat1, feat2);}bool FaceRecognition::GetFeature(string filename, float* feat){//load image and convert to graycv::Mat src_img_color = cv::imread(filename, 1);cv::Mat src_img_gray;cv::cvtColor(src_img_color, src_img_gray, CV_BGR2GRAY);//convert to ImageData typeseeta::ImageData src_img_data_color(src_img_color.cols, src_img_color.rows, src_img_color.channels());src_img_data_color.data = src_img_color.data;seeta::ImageData src_img_data_gray(src_img_gray.cols, src_img_gray.rows, src_img_gray.channels());src_img_data_gray.data = src_img_gray.data;//Detect facesstd::vector<seeta::FaceInfo> faces = this->detector->Detect(src_img_data_gray);int32_t face_num = static_cast<int32_t>(faces.size());if (face_num == 0){std::cout << "Faces are not detected." << std::endl;return false;}//Detect 5 facial landmarksseeta::FacialLandmark points[5];this->point_detector->PointDetectLandmarks(src_img_data_gray, faces[0], points);//Extract face identity featurethis->face_recognizer->ExtractFeatureWithCrop(src_img_data_color, points, feat);return true;}FaceRecognition::~FaceRecognition(){if (detector)delete detector;if (point_detector)delete point_detector;if (face_recognizer)delete face_recognizer;}


mian.cpp
#include "FaceRecognition.h"#include "FeatureGroup.h"/** given two images and calculate the similarity*/int faceverification(){FaceRecognition fr;float* feat1 = fr.NewFeatureBuffer();float* feat2 = fr.NewFeatureBuffer();std::vector<std::pair<string, string>> pic_pair;pic_pair.push_back(std::make_pair("0_1.jpg", "0_2.jpg"));pic_pair.push_back(std::make_pair("1_1.jpg", "1_2.jpg"));pic_pair.push_back(std::make_pair("2_1.jpg", "2_2.jpg"));double averageDetectTime = 0.0;for (size_t i = 0; i < pic_pair.size(); i++){long t0 = cv::getTickCount();fr.GetFeature(pic_pair[i].first, feat1);fr.GetFeature(pic_pair[i].second, feat2);float sim = fr.FeatureCompare(feat1, feat2);std::cout << "similarity:" << sim << std::endl;long t1 = cv::getTickCount();double secs = (t1 - t0) / cv::getTickFrequency();averageDetectTime += secs;std::cout << "Image pair " << i << " takes " << secs << " seconds to detect,alignment and verification !" << std::endl;;}std::cout << std::endl << "All verification takes " << averageDetectTime << " secs!" << std::endl;std::cout << "The average verification times for one image takes " << double(averageDetectTime / pic_pair.size() / 2) << " secs !" << std::endl;delete feat1;delete feat2;return 0;}bool GetAllFileNames(string file_path, std::vector<string>& files){intptr_t hFile = 0;//文件信息  struct _finddata_t fileinfo;string p;if ((hFile = _findfirst(p.assign(file_path).append("\\*").c_str(), &fileinfo)) != -1){do{//如果是目录,迭代之  //如果不是,加入列表  if ((fileinfo.attrib &  _A_SUBDIR)){if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)GetAllFileNames(p.assign(file_path).append("\\").append(fileinfo.name), files);}else{char *ext = strrchr(fileinfo.name, '.');if (ext){ext++;if (_stricmp(ext, "jpg") == 0 || _stricmp(ext, "png") == 0)files.push_back(p.assign(file_path).append("\\").append(fileinfo.name));}}} while (_findnext(hFile, &fileinfo) == 0);_findclose(hFile);}return true;}int main(int argc, char* argv[]){int choice;std::cout << "Input 1 to build database index, 2 to test image: " ;std::cin >> choice;if (1 == choice){std::vector<string> filenames;GetAllFileNames("./images", filenames);std::cout << "Detected " << filenames.size() << " images..." << std::endl;FaceRecognition fr;FeatureGroup fg(fr.GetFeatureDims(), &fr);float * feat = fr.NewFeatureBuffer();double averageExtractFeatureTime = 0.0;for (int i = 0; i < filenames.size(); i++){long t0 = cv::getTickCount();if (fr.GetFeature(filenames[i], feat)){fg.AddFeature(feat, filenames[i]);}long t1 = cv::getTickCount();double secs = (t1 - t0) / cv::getTickFrequency();averageExtractFeatureTime += secs;if ((i + 1) % 5 == 0){std::cout << i + 1 << " / " << int(filenames.size()) << "  has been extracted!"<< std::endl;}}std::cout << std::endl << "All verification takes " << averageExtractFeatureTime << " secs!" << std::endl;std::cout << "The average extract feature times for one image takes " << double(averageExtractFeatureTime / filenames.size() / 2) << " secs !" << std::endl;fg.SaveModel("feature.index");std::cout << "Feature Extraction has been finished!" << std::endl;}else if (2 == choice){FaceRecognition fr;string pic_file_path;std::cout << "Loading DataBase..." << std::endl;FeatureGroup fg("feature.index", &fr);std::cout << "Database has been loaded!" << std::endl;float * feat = fr.NewFeatureBuffer();while (true){std::vector<Feature> result;std::cout << "please input your filename:";std::cin >> pic_file_path;if (!fr.GetFeature(pic_file_path, feat)){std::cout << "Wrong Filename or Can't detect face..." << std::endl;continue;}fg.FindTopK(10, feat, result);for (int i = 0; i < result.size(); i++){std::cout << "Top " << i + 1 << " : " << result[i].filename << " Similarity: " << result[i].similarity_with_goal << std::endl;}}std::cout << std::endl;}return 0;}


最后,将完整的项目代码献上:链接: http://pan.baidu.com/s/1nvyNbRF 密码: 3g4b
0 0