图像处理算法之瘦脸及放大眼睛

 现在很多图像美颜app,处理后不但使人物皮肤变得平滑、白皙,还会稍微瘦下脸、放大眼睛,给人眼前一亮的感觉。这其中涉及人脸检测及特征点提取算法,一般提取68个特征点就足够了,同时也涉及图像局部变形算法。这也是两个研究方向,前者主要是计算机视觉,后者是图像处理。但随着深度学习的大热及在多个领域的成功应用,很多图像处理技术也开始采用深度学习算法实现突破,比如基于深度学习的降噪、超分辨率、非真实感绘制等等技术。深度学习大有在计算机视觉、图像处理一统之态势。言归正传,本文主要还是介绍瘦脸及放大眼睛所用到的图像局部变形算法。主要参考:交互式图像变形算法一文 。看过该文章后,自然了解瘦脸其实用的是图像局部平移变形,放大眼睛,用的是图像局部缩放变形。同时,文章还阐述了图像局部旋转变形的算法原理及思路。
       瘦脸及放大眼睛的前提是需要检测到人脸,并提取特征点。谈到图像变形,最基础的思路是:由变形前坐标,根据变形映射关系,得到变形后坐标。这其中变形映射关系是最关键的,不同的映射关系,将得到不同的变形效果。平移、缩放、旋转,对应的是不同的映射关系,即不同的变换公式。当然实际在计算过程中,用的是逆变换,即由变形后坐标,根据逆变换公式反算变形前坐标,然后插值得到该坐标rgb像素值,将该rgb值作为变形后坐标对应的像素值。这样才能保证变形后的图像是连续、完整的。
       下面简单讲一下图像局部平移变形,该变形稍微复杂一些,公式如下:

                                       

       公式中,由于主要是像素点位置计算,因此涉及一些矢量运算,不过比较简单。其实上面公式就是逆变换公式了,x是变换后的位置,u是原坐标位置。整个计算在以c为圆心,r为半径的圆内进行。因为是交互式图像局部变形,所以c也可以看做鼠标点下时的坐标,而m为鼠标移动一段距离后抬起时的坐标,这样c和m就决定了变形方向。下面是示例代码,公式结合代码一起看,应该很快能弄明白。
void LocalTranslationWarp(Mat &img, int warpX, int warpY, int warpW, int warpH, int directionX, int directionY, double warpCoef)
{
    RestrictBounds(warpX, warpY, warpW, warpH);
 
    Mat imgCopy;
    copyMakeBorder(img, imgCopy, 0, 1, 0, 1, BORDER_REPLICATE);
 
    Point center(warpX + (warpW>>1), warpY + (warpH>>1));
    double radius = (warpW < warpH) ? (warpW >> 1) : (warpH >> 1);
    radius = radius * radius;
 
    // 平移方向矢量/模
    double transVecX = directionX - center.x;
    double transVecY = directionY - center.y;
    double transVecModel = transVecX*transVecX + transVecY*transVecY;
 
    // 水平/垂直增量//映射后位置与原位置
    double dx = 0, dy = 0, posX = 0.0, posY = 0.0, posU = 0.0, posV = 0.0;
    // 点到圆心距离/平移比例
    double distance = 0.0, ratio = 0.0;
    // 插值位置
    int startU = 0, startV = 0;
    double alpha = 0.0, beta = 0.0;
 
    int maxRow = warpY + warpH;
    int maxCol = warpX + warpW;
    uchar* pImg = NULL;
    for (int i = warpY; i < maxRow; i++)
    {
        pImg = img.data + img.step * i;
        for (int j = warpX; j < maxCol; j++)
        {
            posX = j;
            posY = i;
            dx = posX - center.x;
            dy = posY - center.y;
            distance = dx*dx + dy*dy;
            if (distance < radius)
            {
                ratio = (radius - distance) / (radius - distance + transVecModel * warpCoef);
                posU = posX - ratio * ratio * transVecX;
                posV = posY - ratio * ratio * transVecY;
 
                startU = (int)posU;
                startV = (int)posV;
                alpha = posU - startU;
                beta  = posV - startV;
                BilinearInter(imgCopy, startU, startV, alpha, beta, pImg[3*j], pImg[3*j + 1], pImg[3*j + 2]);
            }
        }
    }
}
       可以看到,只有圆形选区内的图像才进行变形。越靠近圆心,变形越大,反之变形越小。对于图像缩放变形及旋转变形,公式比较简单,实现起来也容易一些,本文就不在详细讲解了。应用上面算法,简单的瘦脸效果如下:
    
       
       参考文献:
       http://www.gson.org/thesis/warping-thesis.pdf
       http://www.cnblogs.com/xiaotie/archive/2009/12/08/1619046.html
--------------------- 
作者:grafx 
来源:CSDN 
原文:https://blog.csdn.net/grafx/article/details/70232797 
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自blog.csdn.net/c2a2o2/article/details/83416946