目录

1 人脸检测

2 人脸对齐代码

2.1 FaceProprocess.h

2.2 main.cpp

2.3 makefile

3 对齐效果


人脸识别一般需要经过人脸检测,人脸对齐,特征提取及相似度比对,具体原理可以见:

人脸检测-人脸对齐-人脸识别原理及方法_陈 洪 伟的博客-CSDN博客

该篇文章主要对人脸对齐进行补充,

1 人脸检测

我们用ldh的图片进行检测,得到人脸框和5个关键点。

检测得到的矩形框和关键点如下:

orgimg.shape:  (640, 640, 3)
x1:243.000000,y1:140.000000,x2:447.000000,y2:394.000000
point_0_x:307.000000
point_0_y:252.000000
point_1_x:390.000000
point_1_y:241.000000
point_2_x:359.000000
point_2_y:305.000000
point_3_x:332.000000
point_3_y:340.000000
point_4_x:395.000000
point_4_y:332.000000

结果图如下

2 人脸对齐代码

2.1 FaceProprocess.h

//
// Created by Jack Yu on 23/03/2018.
//#ifndef FACE_DEMO_FACEPREPROCESS_H
#define FACE_DEMO_FACEPREPROCESS_H#include<opencv2/opencv.hpp>
#include <opencv2/core.hpp>using namespace cv;namespace FacePreprocess {cv::Mat meanAxis0(const cv::Mat &src){int num = src.rows;int dim = src.cols;// x1 y1// x2 y2cv::Mat output(1,dim,CV_32F);for(int i = 0 ; i <  dim; i ++){float sum = 0 ;for(int j = 0 ; j < num ; j++){sum+=src.at<float>(j,i);}output.at<float>(0,i) = sum/num;}return output;}cv::Mat elementwiseMinus(const cv::Mat &A,const cv::Mat &B){cv::Mat output(A.rows,A.cols,A.type());assert(B.cols == A.cols);if(B.cols == A.cols){for(int i = 0 ; i <  A.rows; i ++){for(int j = 0 ; j < B.cols; j++){output.at<float>(i,j) = A.at<float>(i,j) - B.at<float>(0,j);}}}return output;}cv::Mat varAxis0(const cv::Mat &src){cv:Mat temp_ = elementwiseMinus(src,meanAxis0(src));cv::multiply(temp_ ,temp_ ,temp_ );return meanAxis0(temp_);}int MatrixRank(cv::Mat M){Mat w, u, vt;SVD::compute(M, w, u, vt);Mat1b nonZeroSingularValues = w > 0.0001;int rank = countNonZero(nonZeroSingularValues);return rank;}//    References
//    ----------
//    .. [1] "Least-squares estimation of transformation parameters between two
//    point patterns", Shinji Umeyama, PAMI 1991, DOI: 10.1109/34.88573
//
//    """
//
//    Anthor:Jack Yucv::Mat similarTransform(cv::Mat src,cv::Mat dst) {int num = src.rows;int dim = src.cols;cv::Mat src_mean = meanAxis0(src);cv::Mat dst_mean = meanAxis0(dst);cv::Mat src_demean = elementwiseMinus(src, src_mean);cv::Mat dst_demean = elementwiseMinus(dst, dst_mean);cv::Mat A = (dst_demean.t() * src_demean) / static_cast<float>(num);cv::Mat d(dim, 1, CV_32F);d.setTo(1.0f);if (cv::determinant(A) < 0) {d.at<float>(dim - 1, 0) = -1;}Mat T = cv::Mat::eye(dim + 1, dim + 1, CV_32F);cv::Mat U, S, V;SVD::compute(A, S,U, V);// the SVD function in opencv differ from scipy .int rank = MatrixRank(A);if (rank == 0) {assert(rank == 0);} else if (rank == dim - 1) {if (cv::determinant(U) * cv::determinant(V) > 0) {T.rowRange(0, dim).colRange(0, dim) = U * V;} else {
//            s = d[dim - 1]
//            d[dim - 1] = -1
//            T[:dim, :dim] = np.dot(U, np.dot(np.diag(d), V))
//            d[dim - 1] = sint s = d.at<float>(dim - 1, 0) = -1;d.at<float>(dim - 1, 0) = -1;T.rowRange(0, dim).colRange(0, dim) = U * V;cv::Mat diag_ = cv::Mat::diag(d);cv::Mat twp = diag_*V; //np.dot(np.diag(d), V.T)Mat B = Mat::zeros(3, 3, CV_8UC1);Mat C = B.diag(0);T.rowRange(0, dim).colRange(0, dim) = U* twp;d.at<float>(dim - 1, 0) = s;}}else{cv::Mat diag_ = cv::Mat::diag(d);cv::Mat twp = diag_*V.t(); //np.dot(np.diag(d), V.T)cv::Mat res = U* twp; // UT.rowRange(0, dim).colRange(0, dim) = -U.t()* twp;}cv::Mat var_ = varAxis0(src_demean);float val = cv::sum(var_).val[0];cv::Mat res;cv::multiply(d,S,res);float scale =  1.0/val*cv::sum(res).val[0];T.rowRange(0, dim).colRange(0, dim) = - T.rowRange(0, dim).colRange(0, dim).t();cv::Mat  temp1 = T.rowRange(0, dim).colRange(0, dim); // T[:dim, :dim]cv::Mat  temp2 = src_mean.t(); //src_mean.Tcv::Mat  temp3 = temp1*temp2; // np.dot(T[:dim, :dim], src_mean.T)cv::Mat temp4 = scale*temp3;T.rowRange(0, dim).colRange(dim, dim+1)=  -(temp4 - dst_mean.t()) ;T.rowRange(0, dim).colRange(0, dim) *= scale;return T;}}
#endif //FACE_DEMO_FACEPREPROCESS_H

2.2 main.cpp

#include<opencv2/opencv.hpp>
#include "FaceProprocess.h"//标准的关键点。
float v1[5][2] = {{30.2946f, 51.6963f},{65.5318f, 51.5014f},{48.0252f, 71.7366f},{33.5493f, 92.3655f},{62.7299f, 92.2041f}};//检测出的人脸框坐标和关键点
// orgimg.shape:  (640, 640, 3)
// x1:243.000000,y1:140.000000,x2:447.000000,y2:394.000000
// point_0_x:307.000000
// point_0_y:252.000000
// point_1_x:390.000000
// point_1_y:241.000000
// point_2_x:359.000000
// point_2_y:305.000000
// point_3_x:332.000000
// point_3_y:340.000000
// point_4_x:395.000000
// point_4_y:332.000000
//#define originWidth 640
//#define wantWidth   112#define standardWidth 96
#define box_x1 243.00
#define box_y1 140.00
#define box_x2 447.00
#define box_y2 394.00
#define faceWidth   (box_x2 - box_x1)
#define faceHeight  (box_y2 - box_y1)
float point[10] = {307.00, 252.00, 390.00, 241.00, 359.00, 305.00, 332.00, 340.00, 395.00, 332.00};// float v2[5][2] ={
//     {307.00, 252.00},
//     {390.00, 241.00},
//     {359.00, 305.00},
//     {332.00, 340.00},
//     {395.00, 332.00}};float v2[5][2] ={{0.00, 0.00},{0.00, 0.00},{0.00, 0.00},{0.00, 0.00},{0.00, 0.00}};int main(void)
{printf("faceWidth:%d\n", faceWidth);printf("faceHeight:%d\n", faceHeight);cv::Mat src(5,2,CV_32FC1, v1);memcpy(src.data, v1, 2 * 5 * sizeof(float));for (int j = 0; j<5; j = j + 1){v2[j][0] = (point[2*j]     - box_x1)*(standardWidth/faceWidth);v2[j][1] = (point[2*j + 1] - box_y1)*(standardWidth/faceWidth);printf("v2[%d][0]:%f\n", j, v2[j][0]);printf("v2[%d][1]:%f\n", j, v2[j][1]);}cv::Mat dst(5,2,CV_32FC1, v2);memcpy(dst.data, v2, 2 * 5 * sizeof(float));cv::Mat m = FacePreprocess::similarTransform(dst ,src);cv::Mat map_matrix;cv::Rect map_matrix_r = Rect(0, 0, 3, 2); cv::Mat (m, map_matrix_r).copyTo(map_matrix);cv::Mat croppedImageAligned;//第四个参数是图像的输出尺寸。cv::Mat srcImage = imread("./ldh.jpeg");cv::Mat croppedImage = srcImage(cv::Rect(box_x1, box_y1, faceWidth, faceHeight));// Rect(x,y,width,height)warpAffine(croppedImage, croppedImageAligned, map_matrix, { (int)faceWidth, (int)faceHeight}, CV_INTER_CUBIC | CV_WARP_FILL_OUTLIERS, BORDER_CONSTANT, cvScalarAll(0));cv::imwrite("./result.jpg", croppedImageAligned);return 1;
}

2.3 makefile

CC      = gcc
CPP     = g++
AR      = ar
RM      = rm -f#Define the resource compiler.
RC = windres## debug flag
DBG_ENABLE := 1OS = $(shell uname)## source file path
SRC_PATH  := ./src/
SRC_PATH_EXT :=
DEMO :=./demo/main.cpp## target file name
TARGET     := facealign
DEMO_TARGET := run## get all source files
SRCS := $(foreach spath, $(SRC_PATH), $(wildcard $(spath)*.c) $(wildcard $(spath)*.cpp))## all .o based on all .c/.cpp
OBJS = $(SRCS:.c=.o)
OBJS := $(OBJS:.cpp=.o) ## macro define
DEFS := __LINUX__ OS_LINUX _FILE_OFFSET_BITS=64#if freeimage is static-linked use this !
#DEFS += FREEIMAGE_LIB#LIBS   += -lopencv_calib3d  -lopencv_features2d -lopencv_flann  -l
#LIBS   += -l -lopencv_ml -lopencv_objdetect  -lopencv_legacy -lopencv_gpu
#LIBS   += -l   -lopencv_superres -lopencv_contrib -lopencv_nonfree
#LIBS   += -l  -l -lopencv_ts  -lopencv_stitching -lopencv_core## need libs, add at here
LIBS := opencv_core opencv_video opencv_highgui opencv_imgproc opencv_photo opencv_videostab opencv_highgui opencv_imgproc opencv_imgcodecs boost_system boost_thread DEMO_LIBS = $(LIBS)
DEMO_LIBS += facealign## used headers  file path
INCLUDE_PATH := ./include  ./src  /usr/include/#$(warning $(INCLUDE_PATH))## used include librarys file path
LIBRARY_PATH := ./  ./libs /usr/lib/x86_64-linux-gnu/    ## debug for debug info, when use gdb to debug
ifeq (1, ${DBG_ENABLE})
CFLAGS += -D_DEBUG -g -DDEBUG=1
else
CFLAGS += -O2 -DNDEBUG
endif#for ENCYPT flagsifeq ($(OS), Linux)
LIBS += dl rt
CFLAGS += -fPIC
TARGET_EXT := .so
LIBRARY_PATH +=
LDFLAGS += -Wl,--rpath=./libs
endif#CFLAGS += -msse4.2 -march=core2 -pipe $(foreach m, $(DEFS), -D$(m))
#CFLAGS += -march=armv8.2-a -pipe $(foreach m, $(DEFS), -D$(m)) CFLAGS += -pipe $(foreach m, $(DEFS), -D$(m)) ## get all include path
CFLAGS  += $(foreach dir, $(INCLUDE_PATH), -I$(dir))  CXXFLAGS += $(CFLAGS) -std=c++11## get all library path
LDFLAGS += -lpthread $(foreach lib, $(LIBRARY_PATH), -L$(lib))
DEMO_LDFLAGS := $(LDFLAGS)
## get all librarys
LDFLAGS += $(foreach lib, $(LIBS), -l$(lib))DEMO_LDFLAGS += $(foreach lib, $(DEMO_LIBS), -l$(lib))RCFLAGS ?= -DNDEBUGdefault: all%.o: %.c$(CC) $(CFLAGS) -g -c $< -o $@%.o: %.cpp$(CPP) $(CXXFLAGS) -g -c $< -o $@all: $(OBJS) $(RESOURCE)#$(CPP) $(CXXFLAGS) -o $(TARGET) $(OBJS) $(RESOURCE) $(LDFLAGS)$(CPP) $(CXXFLAGS) -g -shared -o lib$(TARGET)$(TARGET_EXT) $(OBJS) $(RESOURCE) $(LDFLAGS)mv libfacealign.so ./libs$(CPP) $(CXXFLAGS) -g -o $(DEMO_TARGET) $(DEMO) $(DEMO_LDFLAGS)clean:  $(RM) $(OBJS) $(DEMO_TARGET) $(TARGET).* $(RESOURCE)

3 对齐效果

参考文献:

采用mtcnn输出的特征点做人脸对齐C++代码 - 代码先锋网

similarity transform matrix in c++ is different from python · Issue #481 · deepinsight/insightface · GitHub

根据人脸关键点做人脸对齐face alignment----C++实现相关推荐

  1. paddle2.0高层API实现人脸关键点检测(人脸关键点检测综述_自定义网络_paddleHub_趣味ps)

    paddle2.0高层API实现人脸关键点检测(人脸关键点检测综述_自定义网络_paddleHub_趣味ps) 本文包含了: - 人脸关键点检测综述 - 人脸关键点检测数据集介绍以及数据处理实现 - ...

  2. 人工智能AI系列 - 人脸识别套件列表,包括人脸检测,人脸识别,人脸关键点,人脸比对,人脸搜索等等。

    人脸识别套件列表 打造最好的java开源人脸识别套件,包括人脸检测,人脸识别,人脸关键点,人脸比对,人脸搜索等等. 人脸检测SDK 人脸检测SDK 链接 人脸检测 (含5个人脸关键点) SDK 链接 ...

  3. 【dlib库】进行人脸检测+人脸关键点检测+人脸对齐

    原图像: 1. 人脸检测 import cv2 import dlib import matplotlib.pyplot as plt # 获取图片 my_img = cv2.imread('my_i ...

  4. 基于人脸关键点修复人脸,腾讯等提出优于SOTA的LaFIn生成网络

    作者 | Yang Yang.Xiaojie Guo.Jiayi Ma.Lin Ma.Haibin Ling 译者 | 刘畅 编辑 | Jane 出品 | AI科技大本营(ID:rgznai100) ...

  5. caffe 人脸关键点检测_全套 | 人脸检测 人脸关键点检测 人脸卡通化

    点击上方"AI算法与图像处理",选择加"星标"或"置顶" 重磅干货,第一时间送达 来源:CVPy 人脸检测历险记 可能跟我一样,人脸检测是很 ...

  6. 识别人脸关键点给人脸加眼镜特效

    作者:busyboxs 本项目主要使用的 API 是人脸关键点检测.因为给人脸加眼镜特效其实只需要眼睛相关的关键点即可,所以本项目为了简单,使用的是百度 AI 人脸检测 API 中的 landmark ...

  7. caffe 人脸关键点检测_人脸关键点对齐

    摘要: 从传统方法到深度学习方法,对人脸关键点定位/人脸对齐的发展进行梳理,对该领域中经典的方法,最新成果进行汇总,并给出相应的paper原文,项目主页及代码链接.重点介绍深度学习的几种最新方法. 1 ...

  8. 关键点提取:face_recognition、疲劳检测、人脸校准、人脸数据库

    日萌社 人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新) 人脸识别功能实现的原理介绍与算法介绍 人脸识别:人脸数据集 A ...

  9. Opencv与dlib联合进行人脸关键点检测与识别

    前言 依赖库:opencv 2.4.9 /dlib 19.0/libfacedetection 本篇不记录如何配置,重点在实现上.使用libfacedetection实现人脸区域检测,联合dlib标记 ...

  10. 【技术综述】人脸关键点检测的数据集与核心算法

    人脸关键点检测是诸如人脸识别.表情分析.三维人脸重建等其它人脸相关任务的基础.近些年来,深度学习方法已被成功应用到了人脸的关键点检测,本章将介绍深度学习方法在人脸关键点检测方向的研究.包括人脸关键点任 ...

最新文章

  1. Java 循环队列原理与用法详解
  2. 的原型是什么_学习服装原型是什么?
  3. execl中设置的格式无法实现
  4. 首批国家应用数学中心:广东独占2家
  5. 规划System Center 2012 R2 Operations manager
  6. 总谐波失真80_如何将总谐波失真降至 10% 以下
  7. 苹果CEO库克薪酬达员工1500倍;曝英特尔将开放x86内核授权;TensorFlow技术主管皮特・沃登离职|极客头条
  8. win7安装Python所需资源
  9. python牛顿法寻找极值_牛顿法求极值及其Python实现
  10. 计算机怎样辅助英语听力教学,浅议多媒体计算机辅助大学英语教学的原则 大学英语听力怎么提高...
  11. 泡泡龙游戏开发系列教程(三)
  12. 1050ti比1050强多少 gtx1050和gtx1050ti差距大吗
  13. 【Physiol Plant】转录因子PpybZIP43通过激活PpySPS3表达和与PpySTOP1互作从而促进梨果实蔗糖合成
  14. Mac 如何强制关机?
  15. SSRS 2008 冻结首行
  16. matlab 2048小游戏
  17. Go是Google的语言,而不是我们的语言
  18. Spring Boot+JOOQ(五)进阶查询操作
  19. CyberLink PowerDVD Ultra v19.0.2005.62极致中文破解版
  20. Cesium淹没分析(干货)

热门文章

  1. XML第十讲:XML中Schema深入详解、元素、属性、关系
  2. 第三讲:验证码点击刷新
  3. 微信小程序自定义下拉刷新
  4. IDEA terminal 输入mvn命令,提示mvn不是内部命令
  5. 【操作系统】进程通信
  6. 【报告分享】2021年自驾游数据报告-马蜂窝旅游(附下载)
  7. matlab出现边频带,边频信号的形成原因及分析
  8. 你真应该再多了解些Handler机制
  9. VS 2013编译xvid
  10. vmware如何安装spoonwep2