人脸识别
1、参考网站:https://zhuanlan.zhihu.com/p/36416906
人脸识别系统:
1)人脸检测:检测出人脸在图像中的大小和位置,libfacedetection(ShiqiYu),seetaface(ShiguangShan),深度学习
2)人脸对齐:将人脸变换到统一的角度和姿态,对人脸关键点进行相似变换(旋转,缩放,平移),尽可能转换到标准人脸
3)人脸特征表示:向量化人脸特征,分类器判别人脸识别结果。
论文地址:https://arxiv.org/pdf/1612.02295.pdf
①人工特征论文:Blessing of Dimisionality: High Dimensional Feature and Its Efficient Compression for Face Verification(LFW数据集精度95.17%)
②深度学习人脸识别:Large-margin softmax loss for convolutional neural networks(特征与分类器间余弦角度)
论文理解:
对于一个二分类问题,softmax强制要求(即将某个样本x归为第一类,计算公式可以表述为)。如果我们将变成(m是正整数)来考虑,则当时,以下不等式自然成立:
因此,只需要保证成立,不等式自然会成立
几何解释(这里需要说明一下,论文中没有从数学公式上体现出Boundary,只是这样做了之后,效果的确提升了):
特征体现:
L1距离与cos距离
参考网站:https://zhuanlan.zhihu.com/p/34404607
突然觉得这个理论不成立呀,因为实际上样本分布是不变的,改变的是分类超平面,准备继续看一遍原文!!!
2、带遮挡的人脸识别
参考论文:http://www2.ece.ohio-state.edu/~aleix/FG08.pdf
3、人脸数据集
1)wider
参考论文:http://mmlab.ie.cuhk.edu.hk/projects/WIDERFace/support/paper.pdf
简述:32203张图,393703个人脸标签,包含了不同的规模,不同的姿势,不同的遮挡;
统一评测方法:随机40%训练集,10%验证集,50%测试集;
数据来源:Large Scale Ontology for Multimedia (LSCOM) 中的视频事件,谷歌、bing等搜索引擎,人工筛选(去掉不带有人脸的图)
4、人脸识别实现算法(深度学习)
1)人脸检测
MTCNN中提供了详细的检测人脸框与5个人脸关键点的配置与实现过程,但只是实现了人脸检测功能,实现结果如下:
2)人脸检测+人脸对齐
人脸对齐主要需要对人脸的各个部位进行矫正,MTCNN虽然提供了检测人脸5个关键点的方法,但没有提供人脸对齐(矫正)的方法。另外https://blog.csdn.net/zxj942405301/article/details/71799279提供了人脸对齐(矫正)的接口,我们可以借用一下,最终结果如下:
①原图 ②对齐后
实现代码:
①参考上述博主中的链接:http://pan.baidu.com/s/1pLBGwuZ密码:fcyc
②Makefile文件+main.cpp,直接上代码吧!!!
Makefile:
# this is a makefile for caffe
TARGET := classify
# caffe directory
CAFFE_DIR := $/caffe-master
# caffe include
CAFFE_INCLUDE := $(CAFFE_DIR)/include
# caffe build
CAFFE_BUILD := $(CAFFE_DIR)/build
# caffe build lib
CAFFE_BUILD_LIB := $(CAFFE_BUILD)/lib
# caffe build src
CAFFE_BUILD_SRC := $(CAFFE_BUILD)/src
# dependency libraries and caffe linking libs
LFLAGS := -pthread -lnsl -lX11
LFLAGS += -lcaffe -lglog -lgflags -lopencv_flann -lprotobuf -lboost_system -lboost_filesystem -lboost_thread -lboost_coroutine -lboost_context -lboost_regex -lm -lhdf5_hl -lhdf5 -lleveldb -lsnappy -llmdb -lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_objdetect -lstdc++ -lcblas -latlas
LFLAGS += -Wl,-rpath=$(CAFFE_BUILD_LIB) -L/usr/lib/x86_64-linux-gnu/hdf5/serial
LFLAGS += -L/usr/local/lib -lopencv_core -lopencv_imgcodecs -lopencv_highgui
# rules
CFLAGS := -g -I . -I $(CAFFE_INCLUDE) -I $(CAFFE_DIR)/src -I $(CAFFE_BUILD_SRC) -I/usr/include/hdf5/serial -I ./ -Wall -DCPU_ONLY -DUSE_OPENCV
CC := g++
SRC += main.cpp MTCNN.cpp #这里一定是所有的cpp文件
$(TARGET):$(SRC)
$(CC) -o $(TARGET) -O0 -std=c++11 $(SRC) $(CFLAGS) $(LFLAGS) -L$(CAFFE_BUILD_LIB) -Wno-sign-compare
clean :
@rm -f $(TARGET)
main.cpp
/*人脸检测、人脸对齐
主要代码:getFaceRects()
*/
#include <iostream>
#include "MTCNN.h"
#include <glob.h>
#include <vector>
#include <boost/algorithm/string.hpp>
using std::vector;
vector<string> globVector(const string& pattern){
glob_t glob_result;
glob(pattern.c_str(),GLOB_TILDE,NULL,&glob_result);
vector<string> files;
for(unsigned int i=0;i<glob_result.gl_pathc;++i){
files.push_back(string(glob_result.gl_pathv[i]));
}
globfree(&glob_result);
return files;
}
template <class T>
void ClearVector( vector<T>& vt )
{
vector<T> veTemp;
veTemp.swap(vt);
}
int main(int argc, char const *argv[])
{
/* code 批处理文件夹下所有的*.jpg文件,首先检测出人脸,再做人脸对齐(矫正-仿射变换)*/
/*这是https://github.com/kpzhang93/MTCNN_face_detection_alignment/tree/master/code/codes/MTCNNv2/model
中8个caffemodel、deploy文件所在目录路径*/
const string& modelPath="$/MTCNN_face_detection_alignment/code/codes/MTCNNv2/model";
string outputPath="$图像输出路径/";
const string& imagePath = "$图像输入路径/*.jpg";
vector<string> files = globVector(imagePath);//获取目录imagePath下所有*.jpg文件,存储到vector中,
for (int i=0;i<files.size();i++)
{
cout<<files[i]<<endl;
vector<string> tokens;
boost::split(tokens, files[i], boost::is_any_of("/"));
cout<<tokens[tokens.size()-1]<<endl;
vector<Mat> alignedFace;
MTCNN mcnn = MTCNN(modelPath);
Mat img = imread(files[i]);
vector<Rect> faceRects;
alignedFace = mcnn.getFaceRects(img, &faceRects);
cout<<"**alignedFace.size=**"<<alignedFace.size()<<endl;
int tempFaceRowId=0;
int tempFaceColId=0;
for (int j=0;j<alignedFace.size();j++)
{
// cout<<alignedFace[j].size()<<endl;
if(tempFaceRowId<alignedFace[j].rows || tempFaceColId < alignedFace[j].cols)
{
imwrite(outputPath+tokens[tokens.size()-1],alignedFace[j]);
}
tempFaceRowId = alignedFace[j].rows;
tempFaceColId = alignedFace[j].cols;
}
ClearVector(tokens);
ClearVector(alignedFace);
ClearVector(faceRects);
cout<<"***this is a test***"<<endl;
}
// namedWindow("MyWindow", CV_WINDOW_NORMAL);
// imshow("MyWindow", myImage);
waitKey(0);
// destroyWindow("MyWindow");
return 0;
}
另外,gdb调试可能你会用到,调试方法可以参照博客:https://blog.csdn.net/lantuxin/article/details/80012111中第7点。
3)人脸识别
上述人脸检测、人脸对齐完成之后,人脸识别实际就是分类原理。
带遮挡的人脸识别框架参考网站:https://github.com/WeitaoVan/faceID#readme_caffe
具体实现过程:
①将对齐后的人脸放到face_example/data/中,可以分为train和val两个文件夹存储,并在data目录下生成train.txt和val.txt,可以参考https://blog.csdn.net/gaohuazhao/article/details/69568267
②修改solver和train_test相关的*.prototxt,主要是改其中的数据路径和最终分类类别。
补充说明:带遮挡的人脸识别框架参考网站中有一个错误很坑,一个x的参数写进了train_centerMask2Pool2_ori.prototxt中,不过删除就行了。