凯发真人娱乐

人脸姿态校正算法 附完整c 示例代码 -凯发真人娱乐

2023-10-19,

在一些特殊情况下,经常需要依据图像中的人脸,对图片进行倾斜矫正。

例如拍照角度幅度过大之类的情况,而进行人工矫正确实很叫人头大。

那是不是可以有一种,可以根据人脸的信息对图片进行角度的修复呢?

答案肯定是确认的。

再次例如,想要通过人脸的特征对人物的表情和情绪进行精准判断,

那么这个时候如果能确保人脸没有发现严重倾斜,无疑对准确率判断有一定的帮助。

那么假如一张图片只有一个人脸,其实很好判断,通过眼睛的位置的坐标,根据两眼的直线角度,

就可以计算出修正的角度。

然后旋转图片到对应角度即可。

但是如果,一张图片存在多张人脸的时候该怎么办?

有两种方法:

1.找到最大的那个人脸,以它为基准

2.找到频次最高的人脸角度,以频次为基准

当然在大多数情况,方法1是比较合理的。

这两个种情况就留给各位看官去实现了。

本人仅仅考虑一张人脸的情况,演示如何实现该功能。

倾斜角度计算的代码如下:

    float diffeyex = right_eye_x - left_eye_x;
float diffeyey = right_eye_y - left_eye_y; float fangle;
float m_pi = 3.1415926535897932384626433832795f;
if (fabs(diffeyex) < 0.0000001f)
fangle = .f;
else
fangle = atanf(diffeyey / diffeyex) * 180.0f / m_pi;

如果看不明白,需要好好补一下高中数学基础。

为了节约时间,直接复用《自动红眼移除算法 附c 完整代码》的代码。

增加函数如下:

void rotatebilinear(unsigned char *sourcedata, int width, int height, int channels, int rowbytes,
unsigned char *destinationdata, int newwidth, int newheight, float angle, bool keepsize = true,
int fillcolorr = , int fillcolorg = , int fillcolorb = ) {
if (sourcedata == null || destinationdata == null) return; float oldxradius = (float) (width - ) / ;
float oldyradius = (float) (height - ) / ; float newxradius = (float) (newwidth - ) / ;
float newyradius = (float) (newheight - ) / ; double mpi = 3.14159265358979323846;
double anglerad = -angle * mpi / 180.0;
float anglecos = (float) cos(anglerad);
float anglesin = (float) sin(anglerad); int srcstride = rowbytes;
int dstoffset = newwidth * channels - ((channels == ) ? newwidth : newwidth * channels); unsigned char fillr = fillcolorr;
unsigned char fillg = fillcolorg;
unsigned char fillb = fillcolorb; unsigned char *src = (unsigned char *) sourcedata;
unsigned char *dst = (unsigned char *) destinationdata; int ymax = height - ;
int xmax = width - ;
if (channels == ) {
float cy = -newyradius;
for (int y = ; y < newheight; y ) {
float tx = anglesin * cy oldxradius;
float ty = anglecos * cy oldyradius; float cx = -newxradius;
for (int x = ; x < newwidth; x , dst ) {
float ox = tx anglecos * cx;
float oy = ty - anglesin * cx; int ox1 = (int) ox;
int oy1 = (int) oy; if ((ox1 < ) || (oy1 < ) || (ox1 >= width) || (oy1 >= height)) {
*dst = fillg;
} else {
int ox2 = (ox1 == xmax) ? ox1 : ox1 ;
int oy2 = (oy1 == ymax) ? oy1 : oy1 ;
float dx1 = ;
if ((dx1 = ox - (float) ox1) < )
dx1 = ;
float dx2 = 1.0f - dx1;
float dy1 = ;
if ((dy1 = oy - (float) oy1) < )
dy1 = ;
float dy2 = 1.0f - dy1; unsigned char *p1 = src oy1 * srcstride;
unsigned char *p2 = src oy2 * srcstride; *dst = (unsigned char) (dy2 * (dx2 * p1[ox1] dx1 * p1[ox2])
dy1 * (dx2 * p2[ox1] dx1 * p2[ox2]));
}
cx ;
}
cy ;
dst = dstoffset;
}
} else if (channels == ) {
float cy = -newyradius;
for (int y = ; y < newheight; y ) {
float tx = anglesin * cy oldxradius;
float ty = anglecos * cy oldyradius; float cx = -newxradius;
for (int x = ; x < newwidth; x , dst = channels) {
float ox = tx anglecos * cx;
float oy = ty - anglesin * cx; int ox1 = (int) ox;
int oy1 = (int) oy; if ((ox1 < ) || (oy1 < ) || (ox1 >= width) || (oy1 >= height)) {
dst[] = fillr;
dst[] = fillg;
dst[] = fillb;
} else {
int ox2 = (ox1 == xmax) ? ox1 : ox1 ;
int oy2 = (oy1 == ymax) ? oy1 : oy1 ; float dx1 = ;
if ((dx1 = ox - (float) ox1) < )
dx1 = ;
float dx2 = 1.0f - dx1;
float dy1 = ;
if ((dy1 = oy - (float) oy1) < )
dy1 = ;
float dy2 = 1.0f - dy1; unsigned char *p1 = src oy1 * srcstride;
unsigned char *p2 = p1;
p1 = ox1 * channels;
p2 = ox2 * channels; unsigned char *p3 = src oy2 * srcstride;
unsigned char *p4 = p3;
p3 = ox1 * channels;
p4 = ox2 * channels; dst[] = (unsigned char) (
dy2 * (dx2 * p1[] dx1 * p2[])
dy1 * (dx2 * p3[] dx1 * p4[])); dst[] = (unsigned char) (
dy2 * (dx2 * p1[] dx1 * p2[])
dy1 * (dx2 * p3[] dx1 * p4[])); dst[] = (unsigned char) (
dy2 * (dx2 * p1[] dx1 * p2[])
dy1 * (dx2 * p3[] dx1 * p4[]));
}
cx ;
}
cy ;
dst = dstoffset;
}
} else if (channels == ) {
float cy = -newyradius;
for (int y = ; y < newheight; y ) {
float tx = anglesin * cy oldxradius;
float ty = anglecos * cy oldyradius; float cx = -newxradius;
for (int x = ; x < newwidth; x , dst = channels) {
float ox = tx anglecos * cx;
float oy = ty - anglesin * cx; int ox1 = (int) ox;
int oy1 = (int) oy; if ((ox1 < ) || (oy1 < ) || (ox1 >= width) || (oy1 >= height)) {
dst[] = fillr;
dst[] = fillg;
dst[] = fillb;
dst[] = ;
} else {
int ox2 = (ox1 == xmax) ? ox1 : ox1 ;
int oy2 = (oy1 == ymax) ? oy1 : oy1 ; float dx1 = ;
if ((dx1 = ox - (float) ox1) < )
dx1 = ;
float dx2 = 1.0f - dx1;
float dy1 = ;
if ((dy1 = oy - (float) oy1) < )
dy1 = ;
float dy2 = 1.0f - dy1; unsigned char *p1 = src oy1 * srcstride;
unsigned char *p2 = p1;
p1 = ox1 * channels;
p2 = ox2 * channels; unsigned char *p3 = src oy2 * srcstride;
unsigned char *p4 = p3;
p3 = ox1 * channels;
p4 = ox2 * channels; dst[] = (unsigned char) (
dy2 * (dx2 * p1[] dx1 * p2[])
dy1 * (dx2 * p3[] dx1 * p4[])); dst[] = (unsigned char) (
dy2 * (dx2 * p1[] dx1 * p2[])
dy1 * (dx2 * p3[] dx1 * p4[])); dst[] = (unsigned char) (
dy2 * (dx2 * p1[] dx1 * p2[])
dy1 * (dx2 * p3[] dx1 * p4[]));
dst[] = ;
}
cx ;
}
cy ;
dst = dstoffset;
}
}
} void facialposecorrection(unsigned char *inputimage, int width, int height, int channels, int left_eye_x, int left_eye_y,
int right_eye_x, int right_eye_y) {
float diffeyex = right_eye_x - left_eye_x;
float diffeyey = right_eye_y - left_eye_y; float fangle;
float m_pi = 3.1415926535897932384626433832795f;
if (fabs(diffeyex) < 0.0000001f)
fangle = .f;
else
fangle = atanf(diffeyey / diffeyex) * 180.0f / m_pi;
size_t numberofpixels = width * height * channels * sizeof(unsigned char);
unsigned char *outputimage = (unsigned char *) malloc(numberofpixels);
if (outputimage != nullptr) {
rotatebilinear(inputimage, width, height, channels, width * channels, outputimage, width, height, fangle);
memcpy(inputimage, outputimage, numberofpixels);
free(outputimage);
}
}

上效果图片。

原图:

红眼修复 倾斜矫正:

项目地址:

https://github.com/cpuimage/mtcnn

命令行参数:

mtcnn 模型文件路径 图片路径

例如: mtcnn ../models ../sample.jpg

用cmake即可进行编译代码,详情见cmakelists.txt。

若有其他相关问题或者需求也可以邮件联系俺探讨。

邮箱地址是: 
gaozhihan@vip.qq.com

人脸姿态校正算法 附完整c 示例代码的相关教程结束。

网站地图