深度学习AI美颜系列---美图秀秀AI美图之跨次元相机特效算法解析
最近在做类似美图秀秀AI美图里的跨次元相机特效算法,美图跨次元相机特效举例如下:
原图 美图秀秀跨次元相机效果
Fig. 1美图秀秀跨次元相机特效举例
跨次元相机特效是美图秀秀在2017年开发的一个全新的关于自拍的玩法,能够让自己的照片变成手绘美女,做到“照片一秒转手绘”,效果举例如上图所示。最初上线6种风格特效,分别为“天使之恋、十里桃花、童话萌主、樱之少女、人鱼眼泪、暗夜女爵”。
美图秀秀跨次元相机特效是一个深度学习和传统算法相结合的算法组合,并非单一的深度学习算法或者传统算法可以实现的。
这里本人将其划分为两个分析过程:表面分析、内在技术分析;
1,表面分析
①跨次元相机到目前为止,经历了快两年的时间,这么长的更新时间,目前来看,依旧火爆,而且市面上依旧没有其他类似效果的竞争对手;
②到目前为止,处理单张照片依旧耗时较长,一般在2-3s左右;
③这项功能对照片上传大小有较强要求,需要用户上传图像大小不能小于某一尺寸,同时,需要正脸半身照片,五官无遮挡;
上述三点可以看出美图该算法复杂度较高,不易优化,或者无法实时处理,更无法应用到相机界面,同时,无法较好的处理小脸非半身照片case;
2,内在技术分析
从Fig.1的效果对比来看,本人对其总结如下几点:
①人像照片做了背景替换,使用到了人像分割技术;
②人像区域中,仅仅头发区域进行了头发丝特效处理和头发区域特效处理,该过程比较复杂,据官方声明,使用到了机器学习或者DL技术判断头发纹理走势,在纹理走势下绘制发丝效果,目前具体技术尚不可知;
③人像美妆,在图中可以看到,眉毛、眼影、瞳孔和唇彩等都发生了变化,因此,使用了人像美妆技术;
④人像美颜,在图中对比可以发现,效果图中眼睛变大,人脸变小,五官立体感增强,因此,该算法使用了大眼瘦脸、立体五官等脸部微调技术;
⑤人像整体画面的亮度对比度发生了明显的变化,因此,个人猜测,该算法具有自动亮度对比度调节功能;
⑥原图和效果图中,人像表面增加了特有的贴纸效果,因此,该算法使用了静态贴纸技术;
⑦头发丝绘制算法,美图跨次元中的头发丝绘制效果,可谓时转手绘的点睛之笔;
基于上述猜测,本人对应实现该算法,效果举例如下:
原图 本人跨次元相机算法效果
Fig.2 本人算法效果
在本人算法中没有使用静态贴纸,这个可以随意添加,整体上实现了类似的效果,但是头发丝绘制部分还没有美图秀秀的梦幻,没有它更接近手绘风格;
整体而言,这个特效算法允许用户自定义背景,前景贴纸,头发丝绘制颜色以及面部妆容和人脸变形等内容,但由于算法的复杂度,仅仅适合服务器端运行,可以实现对应微信小程序或H5调用,目前本人算法耗时在1S以下,略优于美图秀秀。
关于算法的具体实现,本文不做详细展示,所用到的算法及代码链接如下:
①人脸自动美型 人脸变形
②人像染发
③人像美颜之磨皮美白 磨皮美白2
④人像抠图
⑤人像美妆 妆容迁移
⑥颜色滤镜
⑦头发柔顺
关于头发柔顺方面,本人博客中之前并未介绍过,这里给出一个参考链接,该链接来自大佬Imageshop: https://www.cnblogs.com/Imageshop/p/10797177.html
使用的时LIC线积分算法来处理头发区域的,线积分的示意图如下:
Fig.3 LIC算法示意图
代码如下:
/// make white noise as the LIC input texture ///
void MakeWhiteNoise(int Width, int Height, unsigned char* pNoise)
{srand(100000);for (int j = 0; j < Height; j++)for (int X = 0; X < Width; X++){int r = rand();r = ((r & 0xff) + ((r & 0xff00) >> 8)) & 0xff;pNoise[j * Width + X] = (unsigned char)r;}
}
//LIC
void FastFlowImagingLIC_Appr(int Width, int Height, float* pVectr, unsigned char* pNoise, unsigned char* pImage, float krnlen)2 {3 float Step = 0.333333f; // 每次前进0.33333像素的流线距离 4 int LoopAmount = int(krnlen / Step); // 流线是左右对称的5 if (LoopAmount <= 0) LoopAmount = 1;6 int Weight = LoopAmount * 2;7 for (int Y = 0; Y < Height; Y++)8 {9 unsigned char *LinePD = pImage + Y * Width;
10 float *LinePV = pVectr + Y * Width * 2;
11 for (int X = 0; X < Width; X++, LinePV += 2)
12 {
13 float PosX_P = X + 0.5f, PosY_P = Y + 0.5f, PosX_N = X + 0.5f, PosY_N = Y + 0.5f;
14 float VectorX = LinePV[0] * 0.333333f, VectorY = LinePV[1] * 0.333333f;
15 int Sum = 0;
16 for (int Z = 0; Z < LoopAmount; Z++)
17 {
18 PosX_P += VectorX; PosY_P += VectorY; // X和Y都是归一化的,所以*0.333333f后流线距离也就是0.25了
19 PosX_N -= VectorX; PosY_N -= VectorY;
20 int Index_P = IM_ClampI(PosY_P, 0, Height - 1) * Width + IM_ClampI(PosX_P, 0, Width - 1);
21 int Index_N = IM_ClampI(PosY_N, 0, Height - 1) * Width + IM_ClampI(PosX_N, 0, Width - 1);
22 Sum += pNoise[Index_P] + pNoise[Index_N];
23 }
24 LinePD[X] = (unsigned char)(Sum / Weight);
25 }
26 }
27 }
在Imageshop的链接中有详细的讲解,对应效果如图所示:
Fig.4 线积分特效效果举例
上述就是整个算法过程的分析,在实际开发中,这个特效综合了十余种复杂的算法技术,囊括了美颜美妆以及图像分割等等内容,算法知识上需要大家对各个方面都有全面的认识,介于商业信息问题,本文仅作技术上的分析,不做详细代码展示,掌握了算法之后,相信大家代码不是问题!
这里感谢Imageshop大佬的分享!