美妆实现原理
美妆功能基本实现步骤原理
1、根据人脸检测算法检测出人脸landmark点位信息
2、根据人脸点位将妆容素材进行图片变形来精准匹配人脸需要上妆的位置区域,得到变形后的妆容贴图
3、将变形后的妆容贴图和人脸上妆区域做图层混合得到最终结果
图片变形算法
图片变形算法有多种实现,每种算法都可以用来做美妆变形
778572-20160920112941027-464698588.gif
这里提供仿射变换的变形算法
void AffinetransformMetrix(float x1, float y1, float x2, float y2, float x3, float y3,
float tx1, float ty1, float tx2, float ty2, float tx3, float ty3,
float hMatrix[6])
{
float detA;
detA = tx1 * ty2 + tx2 * ty3 + tx3 * ty1 - tx3 * ty2 - tx1 * ty3 - tx2 * ty1;
float A11, A12, A13, A21, A22, A23, A31, A32, A33;
A11 = ty2 - ty3;
A21 = -(ty1 - ty3);
A31 = ty1 - ty2;
A12 = -(tx2 - tx3);
A22 = tx1 - tx3;
A32 = -(tx1 - tx2);
A13 = tx2 * ty3 - tx3 * ty2;
A23 = -(tx1 * ty3 - tx3 * ty1);
A33 = tx1 * ty2 - tx2 * ty1;
hMatrix[0] = (x1 * A11 + x2 * A21 + x3 * A31) / detA;
hMatrix[1] = (x1 * A12 + x2 * A22 + x3 * A32) / detA;
hMatrix[2] = (x1 * A13 + x2 * A23 + x3 * A33) / detA;
hMatrix[3] = (y1 * A11 + y2 * A21 + y3 * A31) / detA;
hMatrix[4] = (y1 * A12 + y2 * A22 + y3 * A32) / detA;
hMatrix[5] = (y1 * A13 + y2 * A23 + y3 * A33) / detA;
};
// 变形后的位置信息
float cx = (hMatrix[0] * i + hMatrix[1] * j + hMatrix[2]);
float cy = (hMatrix[3] * i + hMatrix[4] * j + hMatrix[5]);
通过仿射变换得到每个像素点变形后的新位置,根据新位置颜色和人脸颜色做混合达到最终效果
眼影效果实现原理
由于仿射变换要求输入3个点,而眼影需要输入4个点,因此以眼睛左右两点连线,将眼睛分为上下两个三角形,分别进行放射变换,如何判断某个点位于直线上方还是下方,这里提供一种方法判断:
bool BelowLine(float inputPoint[4], float x, float y) {
float x1 = inputPoint[0];
float y1 = inputPoint[1];
float x2 = inputPoint[2];
float y2 = inputPoint[3];
float val = ((x2 - x1) * (y - y1) - (x - x1) * (y2 - y1));
return (val > 0.);
}
唇彩实现原理
唇彩实现比较复杂,需要将嘴唇区域根据关键点切分多个三角形,切分的越多,贴合的越准确
针对每个三角形做仿射变换,将嘴唇模版变形到新的位置,然后针对在三角形内部的做颜色混合效果
判断某个点是否位于三角形内部方法,这里采用面积法来判断,如果点在三角形内部,则点和3个顶点组成的3个三角形面积和等于三角形面积
float GetTriangleSquar(float pt0_x, float pt0_y, float pt1_x, float pt1_y, float pt2_x, float pt2_y) {
float AB_x, AB_y, BC_x, BC_y;
AB_x = pt1_x - pt0_x;
AB_y = pt1_y - pt0_y;
BC_x = pt2_x - pt1_x;
BC_y = pt2_y - pt1_y;
return abs((AB_x * BC_y - AB_y * BC_x)) * 0.5;
}
bool JudgePointInTriangleOrNot(float curPoint_x, float curPoint_y, float Ax, float Ay,
float Bx, float By,float Cx,float Cy) {
float ABS_FLOAT_0 = 0.0001;
float SABC, SADB, SBDC, SADC;
SABC = GetTriangleSquar(Ax, Ay, Bx, By, Cx, Cy);
SADB = GetTriangleSquar(Ax, Ay, curPoint_x, curPoint_y, Bx, By);
SBDC = GetTriangleSquar(Bx, By, curPoint_x, curPoint_y, Cx, Cy);
SADC = GetTriangleSquar(Ax, Ay, curPoint_x, curPoint_y, Cx, Cy);
float SumSuqar = SADB + SBDC + SADC;
if ((-ABS_FLOAT_0 < (SABC - SumSuqar)) && ((SABC - SumSuqar) < ABS_FLOAT_0)) {
return true;
} else {
return false;
}
}
嘴唇区域包括内唇牙齿区域不能进行染色,只针对外嘴唇区域到内嘴唇区域做染色
由于内嘴唇关键点较少,在张开嘴巴漏出牙齿时,会有部分牙齿区域也被染色了,部分嘴唇区域没有被染色,这个可以通过增加嘴唇关键点个数来优化,也可以通过贝塞尔曲线拟合方式来实现唇彩效果
瞳孔改变原理
通过landmark中人眼瞳孔中心点和瞳孔范围4个点计算瞳孔的半径信息,将瞳孔素材和人脸瞳孔区域像素进行混合达到换瞳效果
图层混合算法
ps常见的混合算法有18种,具体算法原理如下图所示
image.png
某竞品美妆原理分析
首先查看竞品的美妆模版配置文件格式
{
"faceID":[0],"faceSDKType":2,
"filters":[
{
"2d_sequence_resources":{
"imageCount":1,"imageInterval":0.5,"name":"mask2999_","path":"mask2999/"
},
"blendMode":17,
"filterType":"mask",
"intensity":1.0,
"rect":{
"height":696.0,"width":540.8,"x":368.0,"y":230.4
},
"zPosition":2999
},
{
"2d_sequence_resources":{
"imageCount":1,"imageInterval":0.5,"name":"mask2998_","path":"mask2998/"
},
"blendMode":0,
"filterType":"mask",
"intensity":1.0,
"rect":{
"height":475.2,"width":481.6,"x":400.0,"y":372.8
},
"zPosition":2998
},
{
"2d_sequence_resources":{
"imageCount":1,"imageInterval":0.5,"name":"mask2997_","path":"mask2997/"
},
"blendMode":15,
"filterType":"mask",
"intensity":1.0,
"rect":{
"height":918.4,"width":910.4,"x":163.2,"y":131.2
},
"zPosition":2997
}
],
"standardFaceKeyPoints":"FaceMakeupV2/texcoord.txt",
"standardFaceSize":{"height":1280,"width":1280},
"version":"2.8.0"}
其中2d_sequence_resources目录下的2d资源图片样式是透明图片,可以确定实际做法是通过ps其中一种blend模式和人脸混合
妆容素材最终缩放大小和位置先推测是通过rect属性和standFaceSize来确定,后面推测原理分析用不上
standFaceKeyPoints路径对应标准人脸经过人脸识别后的x,y轴归一化位置,这里120个点应该是106个点+14个扩展点
240
0.302451 0.384169
0.302986 0.409377
0.304336 0.434977
0.306984 0.460683
0.311010 0.486447
......
实现分析
美妆素材再不同人脸上表现需要做相应的形变才能很好的满足美妆效果,图片变形算法有好多种实现方式,有局部缩放算法,最小二乘法,仿射变换https://xhzy.yuque.com/engineer-1/ag1g0d/gqigvd等
但从上述文件中standFaceKeyPoints属性和素材形式可以猜测剪印上通过将人脸划分为一系列不重合的三角形,然后将妆容上对应的三角形映射到当前人脸来实现变形的效果,三角形划分越细,效果越好
image.png
顶点着色器处理:
上诉划分的三角形索引位置和标准脸坐标分别填充到OpenGL的索引缓冲和顶点缓冲
片段着色器处理:
shader输入原始人脸图像和妆容素材纹理,然后根据设置的blendMode和intensity进行PS混合
最终通过渲染管线绘制三角形,最终实现美妆功能
参考链接: