人脸姿态校正算法 附完整C++示例代码

**本文引用自:http://www.cnblogs.com/cpuimage/p/9011130.html **
在一些特殊情况下,经常需要依据图像中的人脸,对图片进行倾斜矫正。

例如拍照角度幅度过大之类的情况,而进行人工矫正确实很叫人头大。
那是不是可以有一种算法,可以根据人脸的信息对图片进行角度的修复呢?
答案肯定是确认的。

再次例如,想要通过人脸的特征对人物的表情和情绪进行精准判断,
那么这个时候如果能确保人脸没有发现严重倾斜,无疑对准确率判断有一定的帮助。

那么假如一张图片只有一个人脸,其实很好判断,通过眼睛的位置的坐标,根据两眼的直线角度,
就可以计算出修正的角度。
然后旋转图片到对应角度即可。
但是如果,一张图片存在多张人脸的时候该怎么办?
有两种方法:
1.找到最大的那个人脸,以它为基准
2.找到频次最高的人脸角度,以频次为基准
当然在大多数情况,方法1是比较合理的。
这两个种情况就留给各位看官去实现了。
本人仅仅考虑一张人脸的情况,演示如何实现该功能。
倾斜角度计算的代码如下:

float diffEyeX = right_eye_x - left_eye_x;
float diffEyeY = right_eye_y - left_eye_y;

float fAngle;
if (fabs(diffEyeX) < 0.0000001f)
     fAngle = 0.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 = 255, int fillColorG = 255, int fillColorB = 255) {
    if (sourceData == NULL || destinationData == NULL) return;

    float oldXradius = (float) (width - 1) / 2;
    float oldYradius = (float) (height - 1) / 2;

    float newXradius = (float) (newWidth - 1) / 2;
    float newYradius = (float) (newHeight - 1) / 2;

    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 == 1) ? 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 - 1;
    int xmax = width - 1;
    if (Channels == 1) {
float cy = -newYradius;
        for (int y = 0; y < newHeight; y++) {
            float tx = angleSin * cy + oldXradius;
            float ty = angleCos * cy + oldYradius;

            float cx = -newXradius;
            for (int x = 0; x < newWidth; x++, dst++) {
                float ox = tx + angleCos * cx;
                float oy = ty - angleSin * cx;

                int ox1 = (int) ox;
                int oy1 = (int) oy;

                if ((ox1 < 0) || (oy1 < 0) || (ox1 >= width) || (oy1 >= height)) {
                    *dst = fillG;
                } else {
                    int ox2 = (ox1 == xmax) ? ox1 : ox1 + 1;
                    int oy2 = (oy1 == ymax) ? oy1 : oy1 + 1;
                    float dx1 = 0;
                    if ((dx1 = ox - (float) ox1) < 0)
                        dx1 = 0;
                    float dx2 = 1.0f - dx1;
                    float dy1 = 0;
                    if ((dy1 = oy - (float) oy1) < 0)
                        dy1 = 0;
                    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 == 3) {
        float cy = -newYradius;
        for (int y = 0; y < newHeight; y++) {
            float tx = angleSin * cy + oldXradius;
            float ty = angleCos * cy + oldYradius;

            float cx = -newXradius;
            for (int x = 0; 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 < 0) || (oy1 < 0) || (ox1 >= width) || (oy1 >= height)) {
                    dst[0] = fillR;
                    dst[1] = fillG;
                    dst[2] = fillB;
                } else {
                    int ox2 = (ox1 == xmax) ? ox1 : ox1 + 1;
                    int oy2 = (oy1 == ymax) ? oy1 : oy1 + 1;

                    float dx1 = 0;
                    if ((dx1 = ox - (float) ox1) < 0)
                        dx1 = 0;
                    float dx2 = 1.0f - dx1;
                    float dy1 = 0;
                    if ((dy1 = oy - (float) oy1) < 0)
                        dy1 = 0;
                    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[0] = (unsigned char) (
                            dy2 * (dx2 * p1[0] + dx1 * p2[0]) +
                            dy1 * (dx2 * p3[0] + dx1 * p4[0]));

                    dst[1] = (unsigned char) (
                            dy2 * (dx2 * p1[1] + dx1 * p2[1]) +
                            dy1 * (dx2 * p3[1] + dx1 * p4[1]));

                    dst[2] = (unsigned char) (
                            dy2 * (dx2 * p1[2] + dx1 * p2[2]) +
                            dy1 * (dx2 * p3[2] + dx1 * p4[2]));
                }
                cx++;
            }
            cy++;
            dst += dstOffset;
        }
} else if (Channels == 4) {
        float cy = -newYradius;
        for (int y = 0; y < newHeight; y++) {
            float tx = angleSin * cy + oldXradius;
            float ty = angleCos * cy + oldYradius;

            float cx = -newXradius;
            for (int x = 0; 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 < 0) || (oy1 < 0) || (ox1 >= width) || (oy1 >= height)) {
                    dst[0] = fillR;
                    dst[1] = fillG;
                    dst[2] = fillB;
                    dst[3] = 255;
                } else {
                    int ox2 = (ox1 == xmax) ? ox1 : ox1 + 1;
                    int oy2 = (oy1 == ymax) ? oy1 : oy1 + 1;

                    float dx1 = 0;
                    if ((dx1 = ox - (float) ox1) < 0)
                        dx1 = 0;
                    float dx2 = 1.0f - dx1;
                    float dy1 = 0;
                    if ((dy1 = oy - (float) oy1) < 0)
                        dy1 = 0;
                    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[0] = (unsigned char) (
                            dy2 * (dx2 * p1[0] + dx1 * p2[0]) +
                            dy1 * (dx2 * p3[0] + dx1 * p4[0]));

                    dst[1] = (unsigned char) (
                            dy2 * (dx2 * p1[1] + dx1 * p2[1]) +
                            dy1 * (dx2 * p3[1] + dx1 * p4[1]));

                    dst[2] = (unsigned char) (
                            dy2 * (dx2 * p1[2] + dx1 * p2[2]) +
                            dy1 * (dx2 * p3[2] + dx1 * p4[2]));
                    dst[3] = 255;
                }
                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 = 0.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);
    }
}

上效果图片。
原图:

红眼修复+倾斜矫正:
红眼修复+倾斜矫正:

在这里插入图片描述
原文网址
原作者项目github地址

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 人脸融合是指将两张或多张人脸图像进行融合,生成一张合成的人脸图像。Python中的dlib库提供了一些相关的函数和工具,用于实现人脸融合。 首先,需要使用dlib库中的人脸检测器来检测图像中的人脸位置和关键点。可以使用dlib.get_frontal_face_detector()函数来获取一个人脸检测器,然后使用detect()函数来检测人脸。检测到的人脸位置可以用一个矩形框表示,关键点包括眼睛、鼻子、嘴巴等特征点。 接下来,可以使用dlib.shape_predictor()函数来获取一个人脸关键点检测器,该检测器能够检测出人脸关键点的位置。使用predictor()函数来检测人脸关键点,传入图像人脸位置矩形框参数。 之后,可以使用dlib.get_face_chip()函数将人脸图像中提取出来,并进行缩放和归一化处理。然后,根据需要的融合效果,使用图像处理技术,如图像融合、图像混合等,将多张人脸图像进行融合。 需要注意的是,在进行人脸融合时,不同人脸的关键点位置和人脸形状可能有所不同。可以使用dlib.find_corresponding_landmarks()函数来查找两张人脸关键点之间的对应关系,从而更好地进行融合。 最后,将融合后的人脸图像保存到文件或显示在屏幕上。 总之,使用Python的dlib库可以方便地进行人脸融合。通过人脸检测、关键点检测和图像处理等技术,可以实现人脸图像的融合效果。 ### 回答2: 人脸融合是指在一张照片中将两个或多个人的面部特征进行融合,生成一张合成的新图片。而Python和dlib是实现人脸融合的工具和库。 Python是一种高级编程语言,具有易于上手、功能强大的特点。在人脸融合中,Python常用于图像处理、机器学习等方面的编程任务。它拥有丰富的第三方库和工具,提供了大量的函数和类,方便我们进行图像处理和算法实现。 而dlib是一个开源的面部检测和特征提取的库,可以用于人脸融合中的人脸定位、面部标记和特征点提取等任务。它基于C++编写,但同时也提供了Python接口,使得我们可以方便地使用Python来调用dlib的功能。 人脸融合的具体步骤一般包括以下几个阶段: 1. 人脸检测:使用dlib库中的人脸检测器,定位输入图像中的人脸位置。 2. 面部标记:利用dlib的面部标记器,找到人脸上的关键特征点,如眼睛、鼻子、嘴巴等。 3. 形变和对齐:根据两个或多个人的面部特征点,对其进行形变和对齐操作,使得它们的位置和形状更加一致。 4. 纹理合成:将多个人的脸部纹理信息进行合成,生成融合后的新纹理。 5. 图像合成:使用图像处理技术,将融合后的纹理信息与原始图像进行叠加或混合,生成最终的人脸融合图像。 总之,人脸融合是一项基于图像处理和机器学习的技术,通过Python编程和dlib库的使用,我们可以实现对人脸的定位、标记和特征提取,从而进行人脸融合操作。这种技术可以应用于娱乐产业、虚拟现实、安全监控等领域,提供了一种有趣和有用的图像合成方法。 ### 回答3: 人脸融合是一种使用技术将两张以上的人脸进行合成的方法。Python中的dlib库提供了一些强大的人脸识别和图像处理功能,可以用于实现人脸融合。 要实现人脸融合,首先需要使用dlib库进行人脸检测和标定。dlib库中的人脸检测器可以帮助我们找到图像中的人脸,并将其标定为一组关键点,如眼睛、鼻子、嘴巴等。通过这些关键点,可以准确地定位人脸的位置和形状。 接下来,我们可以使用dlib中的形状预测器来对这些关键点进行更精确的标定。形状预测器可以根据已有的训练模型推测出更多的关键点,从而更好地描述人脸的特征。 一旦我们成功检测和标定了人脸,就可以进行人脸融合了。通常的做法是将两张或多张人脸图像进行对齐,以确保它们的位置和尺寸相同。然后,我们可以按照不同的算法进行人脸融合,如权重平均、像素取样等。最终,将融合后的图像输出保存。 在人脸融合过程中,还可以进行一些后期处理,如平滑处理、颜色校正、纹理合成等,以提高合成图像的质量和真实度。 总的来说,通过使用Python中的dlib库,我们可以实现人脸融合。这个过程包括人脸检测和标定、形状预测、图像对齐、融合算法和后期处理等步骤。通过合理地利用dlib库提供的功能,可以实现高质量、真实度较高的人脸融合效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值