当前位置:   article > 正文

深度学习AI美颜系列---SpecialFace特效滤镜_ai美颜 github

ai美颜 github

SpecialFace滤镜这个名字实际上是本人自己起的,因为这个滤镜是一种比较另类的,人脸美化特效,所以给了这个名字。先看一下效果:

 

下面我们来分析一下这个滤镜效果的算法逻辑:

1,设计一张逼真的模版A,如下图所示:

这张模版中有透明区域和白色区域以及花草区域三个区域组成;

同时,在A中标定出两个人眼眼睛的位置E1和E2。

2,对人物照片原图S进行人脸检测与特征点识别;

这里我们只需要两个眼睛的点位SE1和SE2即可,可以直接使用腾讯或者Face++开源人脸特征点检测。

这里给出一个开源的人脸检测+对齐(68点位)的资源链接:https://github.com/XiuSdk/cnn-facial-landmark

这个开源代码是68个点的,没有眼睛中心点,但是可以根据眼睛轮廓点计算出眼睛中心点。

3,根据人眼特征点位置,将A放置到S的人脸区域,A和S中的人眼位置对齐;

这一步算法是仿射变换,将E1和E2对齐到SE1和SE2上,这样A即对齐到了S中。

仿射变换公式如下:

在OPENCV中有API接口调用:

void cv::warpAffine ( InputArray src, OutputArray dst, InputArray M, Size dsize, int flags = INTER_LINEAR, int borderMode = BORDER_CONSTANT, const Scalar & borderValue = Scalar() )

4,对A的三个区域分别处理:

①A中透明区域显示S中的内容;

②A中花草区域填充到S中对应位置;

③A中的白色区域显示对应S中的人脸区域,并对该区域像素进行右向的平移,平移距离OFFSET的大小,反映了图像中人脸裂开的程度;

以①-③的步骤将A和S进行融合,即得到该滤镜的效果图。

用类似的方法可以做出很多另类的滤镜风格,滤镜的真实度与模版的逼真度相关,所以模版的设计要求比较高。

本算法核心代码如下:

  1. int TriangleProcess(Triangle srcTriangle, unsigned char* srcData, int width ,int height, int stride, Triangle dstTriangle, unsigned char* dstData, int dWidth, int dHeight, int dStride, unsigned char* pFaceLabel, int ratio)
  2. {
  3. unsigned char* tempData = (unsigned char*)malloc(sizeof(unsigned char) * height * stride);
  4. memcpy(tempData, srcData, sizeof(unsigned char) * height * stride);
  5. int i, j, pos, mw, mh, nx, ny, r, g, b, a, k, nk, temp;
  6. float px = 0, py = 0, cx, cy, AR, AG, AB, AA;
  7. int x0, y0, index_x0y0, index_x0y1, index_x1y0, index_x1y1;
  8. float disX, disY, tmp1, tmp2;
  9. TPoint curPoint;
  10. TPoint A =srcTriangle.A;
  11. TPoint B = srcTriangle.B;
  12. TPoint C = srcTriangle.C;
  13. px = MIN2(A.x, MIN2(B.x, C.x));
  14. py = MIN2(A.y, MIN2(B.y, C.y));
  15. mw = (int)(MAX2(A.x,MAX2(B.x, C.x)) - px);
  16. mh = (int)(MAX2(A.y,MAX2(B.y, C.y)) - py);
  17. k = ratio * 255 / 100;
  18. nk = 255 - k;
  19. for(j = 0; j < mh; j++)
  20. {
  21. for(i = 0; i < mw; i++)
  22. {
  23. curPoint.x = CLIP3(i + px, 0, width - 1);
  24. curPoint.y = CLIP3(j + py, 0, height - 1);
  25. if (WARP_JudgePointInTriangleOrNot(curPoint,srcTriangle))
  26. {
  27. if(pFaceLabel[(int)curPoint.x + (int)curPoint.y * width] == 255)
  28. continue;
  29. TriangleTransform(curPoint, srcTriangle,dstTriangle, &cx, &cy);
  30. x0 = (int)CLIP3(floor(cx), 0, dWidth - 2);
  31. y0 = (int)CLIP3(floor(cy), 0, dHeight - 2);
  32. index_x0y0 = (x0 << 2) + y0 * dStride;
  33. index_x1y0 = index_x0y0 + 4;
  34. index_x0y1 = index_x0y0 + dStride;
  35. index_x1y1 = index_x0y1 + 4;
  36. disX = cx - x0;
  37. disY = cy - y0;
  38. tmp1 = dstData[index_x0y0] + disX *(dstData[index_x1y0] - dstData[index_x0y0]);
  39. tmp2 = dstData[index_x0y1] + disX *(dstData[index_x1y1] - dstData[index_x0y1]);
  40. AB = tmp1 + disY * (tmp2 - tmp1);
  41. tmp1 = dstData[index_x0y0 + 1] + disX *(dstData[index_x1y0 + 1] - dstData[index_x0y0 + 1]);
  42. tmp2 = dstData[index_x0y1 + 1] + disX *(dstData[index_x1y1 + 1] - dstData[index_x0y1 + 1]);
  43. AG = tmp1 + disY * (tmp2 - tmp1);
  44. tmp1 = dstData[index_x0y0 + 2] + disX *(dstData[index_x1y0 + 2] - dstData[index_x0y0 + 2]);
  45. tmp2 = dstData[index_x0y1 + 2] + disX *(dstData[index_x1y1 + 2] - dstData[index_x0y1 + 2]);
  46. AR = tmp1 + disY * (tmp2 - tmp1);
  47. tmp1 = dstData[index_x0y0 + 3] + disX *(dstData[index_x1y0 + 3] - dstData[index_x0y0 + 3]);
  48. tmp2 = dstData[index_x0y1 + 3] + disX *(dstData[index_x1y1 + 3] - dstData[index_x0y1 + 3]);
  49. AA = tmp1 + disY * (tmp2 - tmp1);
  50. nx = (int)CLIP3(i + px, 0, width - 1);
  51. ny = (int)CLIP3(j + py, 0, height - 1);
  52. pos = (nx << 2) + ny * stride;
  53. r = (int)AR;
  54. g = (int)AG;
  55. b = (int)AB;
  56. a = (int)AA;
  57. temp = 255 - a;
  58. if(b > 220 && g > 220 && r > 220 && a != 0)
  59. {
  60. srcData[pos + 3] = 0;
  61. }
  62. b = CLIP3((b * a + temp * srcData[pos + 0]) / 255, 0, 255);
  63. g = CLIP3((g * a + temp * srcData[pos + 1]) / 255, 0, 255);
  64. r = CLIP3((r * a + temp * srcData[pos + 2]) / 255, 0, 255);
  65. srcData[pos + 0] = CLIP3((b * k + nk * srcData[pos + 0]) >> 8, 0, 255);
  66. srcData[pos + 1] = CLIP3((g * k + nk * srcData[pos + 1]) >> 8, 0, 255);
  67. srcData[pos + 2] = CLIP3((r * k + nk * srcData[pos + 2]) >> 8, 0, 255);
  68. //srcData[pos + 3] = 255;/
  69. pFaceLabel[(int)curPoint.x + (int)curPoint.y * width] = 255;
  70. }
  71. }
  72. }
  73. free(tempData);
  74. return 0;
  75. }
  76. int f_FaceMesh(unsigned char* srcData, int width ,int height, int stride, unsigned char* maskData, int mWidth, int mHeight, int mStride, int srcFacePointsAll[101 * 2], int mskFacePointsAll[101 * 2 + 8 * 2], int ratio, int method)
  77. {
  78. int ret = 0;
  79. Triangle mskTriangle[191], srcTriangle[191];
  80. GetTriangle(mskFacePointsAll,mskTriangle);
  81. int maxx = 0, maxy = 0, minx = 10000, miny = 10000;
  82. for(int i = 0; i < 101; i++)
  83. {
  84. maxx = maxx > srcFacePointsAll[(i << 1)] ? maxx : srcFacePointsAll[(i << 1)];
  85. maxy = maxy > srcFacePointsAll[(i << 1) + 1] ? maxy : srcFacePointsAll[(i << 1) + 1];
  86. minx = minx < srcFacePointsAll[(i << 1)] ? minx : srcFacePointsAll[(i << 1)];
  87. miny = miny < srcFacePointsAll[(i << 1) + 1] ? miny : srcFacePointsAll[(i << 1) + 1];
  88. }
  89. int tx, ty, roiWidth;
  90. tx = minx;
  91. ty = miny;
  92. roiWidth = MAX2(abs(maxx - minx),abs(maxy - miny));
  93. int roiHeight = roiWidth;
  94. int k = 2;
  95. int px = MAX2(tx - roiWidth / k, 0);
  96. int py = MAX2(ty - roiWidth / k, 0);
  97. roiWidth = CLIP3(tx - px + roiWidth + roiWidth / k, 0, width - 1);
  98. roiHeight = CLIP3(ty - py + roiHeight + roiWidth / k, 0, height - 1);
  99. int rw = MIN2(roiWidth, roiHeight);
  100. roiWidth = roiHeight = rw;
  101. tx = px;
  102. ty = py;
  103. int facePointsAll[202 + 16];
  104. for(int i = 0; i < 202; i++)
  105. {
  106. facePointsAll[i] = srcFacePointsAll[i];
  107. }
  108. facePointsAll[202] = tx;
  109. facePointsAll[203] = ty;
  110. facePointsAll[204] = tx;
  111. facePointsAll[205] = ty + (roiHeight >> 1);
  112. facePointsAll[206] = tx;
  113. facePointsAll[207] = ty + roiHeight;
  114. facePointsAll[208] = tx + (roiWidth >> 1);
  115. facePointsAll[209] = ty + roiHeight;
  116. facePointsAll[210] = tx + roiWidth;
  117. facePointsAll[211] = ty + roiHeight;
  118. facePointsAll[212] = tx + roiWidth;
  119. facePointsAll[213] = ty + (roiHeight >> 1);
  120. facePointsAll[214] = tx + roiWidth;
  121. facePointsAll[215] = ty;
  122. facePointsAll[216] = tx + (roiWidth >> 1);
  123. facePointsAll[217] = ty;
  124. GetTriangle(facePointsAll, srcTriangle);
  125. unsigned char* pFaceLabel = (unsigned char*)malloc(sizeof(unsigned char) * width * height);
  126. memset(pFaceLabel, 0, sizeof(unsigned char) * width * height);
  127. for(int i = 0; i < 191-15; i++)
  128. {
  129. TriangleProcess(srcTriangle[i], srcData, width ,height, stride, mskTriangle[i], maskData, mWidth, mHeight, mStride, pFaceLabel, ratio);
  130. }
  131. free(pFaceLabel);
  132. return ret;
  133. };
  134. //SpecialFace filter api
  135. int f_Test(unsigned char* srcData, int width ,int height, int stride, unsigned char* maskData, int mWidth, int mHeight, int mStride, int srcFacePointsAll[101 * 2], int mskFacePointsAll[101 * 2 + 8 * 2], int ratio)
  136. {
  137. int ret = 0;
  138. unsigned char* pMask = maskData;
  139. for(int j = 0; j < mHeight; j++)
  140. {
  141. for(int i = 0; i < mWidth; i++)
  142. {
  143. if(pMask[3] == 0)
  144. pMask[0] = pMask[1] = pMask[2] = 0;
  145. pMask += 4;
  146. }
  147. }
  148. //Process
  149. unsigned char* tempData = (unsigned char*)malloc(sizeof(unsigned char) * height * stride);
  150. memcpy(tempData, srcData, sizeof(unsigned char) * height * stride);
  151. ret = f_FaceMesh(srcData, width, height, stride, maskData, mWidth, mHeight, mStride, srcFacePointsAll, mskFacePointsAll, ratio, 0);
  152. int nx = 0, ny = 0, pos = 0, dis;
  153. unsigned char* pSrc = srcData;
  154. dis = srcFacePointsAll[2 * 51] - srcFacePointsAll[2 * 45];
  155. for(int j = 0; j < height; j++)
  156. {
  157. for(int i = 0; i < width; i++)
  158. {
  159. if(pSrc[3] == 0)
  160. {
  161. nx = (int)CLIP3(i - dis, 0, width - 1);
  162. ny = (int)CLIP3(j, 0, height - 1);
  163. pos = (nx << 2) + ny * stride;
  164. pSrc[0] = (int)tempData[pos + 0];
  165. pSrc[1] = (int)tempData[pos + 1];
  166. pSrc[2] = (int)tempData[pos + 2];
  167. pSrc[3] = 255;
  168. }
  169. pSrc += 4;
  170. }
  171. }
  172. free(tempData);
  173. return ret;
  174. };

本文算法的DEMO连接:SpecialFace Filter

最后,本人QQ1358009172,微信公众号:SF图像算法

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小桥流水78/article/detail/897939
推荐阅读
相关标签
  

闽ICP备14008679号