原文:人像美妆---妆容迁移算法研究(Makeup transfer)

对于人像美妆算法,现在的美妆相机、玩美彩妆之类的app已经做的比较成熟了,但是具体算法,基本网络上是杳无可查,今天本人介绍一种自动的人像美妆算法----(Makeup Transfer)妆容迁移

妆容迁移相关的论文不多,有如下几篇:

1.Example-Based cosmetic transfer

2.Makeup Transfer using Multi-example

3.A new digtial face makeup method

4.An automatic framework for example vased virtual makeup

本人主要介绍第一篇《Example-Based cosmetic transfer》,论文效果图如下:

注意:A和A*是两张输入,B是原始图像,B*是根据A*迁移过来的妆容效果图;

本文的算法流程如下:

1,Face warp

若要讲A*的妆容迁移到B上,文中有几个条件:

①背景单一;

②肤色相近;

这两个条件也是为了最后的效果更加自然;

首先,Face warp的过程需要有人脸特征点,因此,这一步之前需要进行人脸检测和点位对齐,拿到A*和B的特征点;

然后,根据变形算法讲A*和B的特征点对齐,从而将A*变形到与B一致;

变形算法有以下几种(个人总结):

①最小二乘MLS变形算法:Image Deformation Using Moving Least Squares.

详细介绍参考博客:http://blog.csdn.net/hjimce/article/details/46550001

②基于线的变形算法:As-Rigid-As-Possible Shape Manipulation.

详细介绍参考博客:http://blog.csdn.net/hjimce/article/details/45766321

③三角网格仿射变换

给出这一步的效果图如下:

左边是原图B(为避免 侵权,眼睛做了处理),中间是妆容图A*,右边是Face warp之后的效果图(我这里采用的是三角网格变形);

2,Cosmetic Map计算

文中介绍的重点也就是这一步,计算Cosmetic Map,即CP,其实算法很简单,公式如下:

Cp = ap / ap*

ap:妆容图像A*对应的原图A

ap*:妆容图像A*

就这么一个简单的公式,就可以化腐朽为神奇。

文中所给CP效果图如下:

3,Makeup transfer

得到了CP之后,我们就可以来进行妆容迁移了,具体算法如下:

4,Others

实际上论文中还介绍一些其他内容,这里我没有写出,因为我的重点是妆容迁移,所以就主要提取了这块内容。

论文中实际上还进行了Freckle remove雀斑去除,眉毛眼睛纹理细节提取等等,如下所示:

这些内容,我这里不关心,实际上,就是为了让最后的效果更加自然更加逼真;

以上整个过程就是这篇论文的核心算法;

现在,好东东才刚刚开始:

本人对这篇论文提出一下几个问题,实际上也是应用中的缺陷:

①,论文要求三个输入(A, A*, B),一个输出B*

这一点,实际应用中就有很大限制,一般而言,我们能拿到A*,也就是好看的妆容效果图,然后想对自己的照片B进行化妆,这个逻辑中是没有未化妆的原图A的。

②,论文中要求肤色相近,背景单一

这一点,普适性太低,很难应用;

③,按照论文的逻辑,嘴巴区域是闭合的,无法适应于各种大笑等开口的情况,或者是效果太差;

介于以上三点,本人对算法进行了改进:

①,根据A*,对A进行估计,估算得到A,这样就只要求用户输入一张好看的效果图,即可对自己的自拍照等进行妆容迁移了;

②,根据人脸特征点,获取A*中的肤色特征,构建精准的人脸Mask,去除背景,这样就避免了背景的影响,同时,进行肤色转换,将A*中的肤色转换到B*中去,从而避免肤色差异过大造成的影响;

③获取A*中的唇色特征,对B进行唇色转换,即将A*的肤色和唇色迁移到B*中去,从而使用于各种大笑等开口场景;

根据上述三点,本人改进算法,得到如下的结果:

原图B

三个目标妆容B*

上述三个妆容B*分别对应的效果图如下:

在给一组测试图:

以上效果本人做了化妆程度自适应,所以没有出现很饱满的艳妆,这样是为了看起来更自然一点。

注意:本人使用的测试图来自美颜相机和互联网,若有侵权敬请告知。

本人提供简单的代码调用如下:

  1. private void pictureBox4_Click(object sender, EventArgs e)
  2. {
  3. if (pictureBox1.Image != null)
  4. {
  5. Graphics g = Graphics.FromImage(curBitmap);
  6. int[] eyePoints = {
  7. 173, 370, 177, 441, 191, 509, 212, 577, 236, 640,
  8. 267, 698, 303, 748, 347, 793, 399, 826, 465, 837,
  9. 526, 825, 575, 792, 611, 748, 643, 699, 671, 643,
  10. 695, 578, 714, 507, 727, 435, 728, 364, 214, 316,
  11. 245, 284, 285, 273, 328, 274, 370, 281, 402, 308,
  12. 363, 309, 325, 304, 287, 302, 251, 307, 513, 307,
  13. 544, 282, 583, 275, 623, 274, 660, 284, 688, 313,
  14. 654, 306, 620, 302, 585, 304, 549, 309, 269, 390,
  15. 282, 373, 300, 364, 323, 361, 347, 366, 365, 380,
  16. 378, 401, 360, 406, 342, 410, 321, 412, 300, 408,
  17. 283, 401, 533, 399, 544, 378, 562, 365, 585, 359,
  18. 607, 362, 625, 371, 638, 386, 624, 398, 608, 406,
  19. 588, 410, 567, 408, 550, 404, 424, 394, 424, 453,
  20. 417, 512, 386, 542, 398, 580, 446, 588, 480, 588,
  21. 528, 576, 536, 539, 506, 511, 494, 452, 490, 393,
  22. 363, 653, 394, 643, 429, 637, 462, 642, 495, 636,
  23. 527, 643, 557, 654, 535, 687, 506, 713, 461, 726,
  24. 415, 715, 384, 688, 373, 656, 417, 657, 462, 661,
  25. 504, 657, 546, 657, 505, 676, 460, 686, 414, 676,
  26. 322, 389, 586, 387, 457, 392, 461, 502, 463, 554,
  27. 463, 588 };
  28.  
  29. eyePoints[2 * 50 + 1] -= 2;
  30. eyePoints[2 * 49 + 1] -= 3;
  31. eyePoints[2 * 48 + 1] -= 4;
  32. eyePoints[2 * 47 + 1] -= 3;
  33. eyePoints[2 * 46 + 1] -= 2;
  34.  
  35. eyePoints[2 * 52 + 1] -= 1;
  36. eyePoints[2 * 61 + 1] -= 2;
  37. eyePoints[2 * 60 + 1] -= 3;
  38. eyePoints[2 * 59 + 1] -= 2;
  39. eyePoints[2 * 58 + 1] -= 1;
  40. for (int i = 0; i < 101; i++)
  41. {
  42. g.DrawRectangle(new Pen(Color.Red, 1), new Rectangle(eyePoints[2 * i] - 1, eyePoints[2 * i + 1] - 1, 2, 2));
  43. }
  44. g.Dispose();
  45. DateTime start = DateTime.Now;
  46. curBitmap = ip.SoftSkin(srcBitmap, new Bitmap(startPath + "\\MakeUp\\MAP.png"), null, skinRatio, 30);
  47.  
  48. curBitmap = ip.MKMakeupTransfer(curBitmap, new Bitmap(Application.StartupPath + "\\M3.JPG"), curFacePoints, eyePoints);
  49. DateTime end = DateTime.Now;
  50. label1.Text = "TC: " + (end - start).ToString();
  51. pictureBox1.Image = curBitmap;
  52. }
  53. }
  1.  [DllImport("TestDemo_C.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.None, ExactSpelling = true)]
  2.         private static extern int IN_Pic_MakeupTransfer(byte* srcData, int width, int height, int stride, int[] srcFacePointsAll, byte* maskData, int mWidth, int mHeight, int mStride, int[] mKeyPointsAll);
  3.         public Bitmap MKMakeupTransfer(Bitmap src, Bitmap mask, int[] srcFacePointsAll, int[] mskFacePointsAll)
  4.         {
  5.             Bitmap a = new Bitmap(src);
  6.             int w = a.Width;
  7.             int h = a.Height;
  8.             BitmapData srcData = a.LockBits(new Rectangle(0, 0, a.Width, a.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
  9.             BitmapData mskData = mask.LockBits(new Rectangle(0, 0, mask.Width, mask.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
  10.             IN_Pic_MakeupTransfer((byte*)srcData.Scan0, w, h, srcData.Stride, srcFacePointsAll,(byte*)mskData.Scan0, mask.Width, mask.Height, mskData.Stride,  mskFacePointsAll);
  11.             a.UnlockBits(srcData);
  12.             mask.UnlockBits(mskData);
  13.             return a;
  14.         }

最后,给一个测试DEMO:点击打开链接

如果问题,请联系QQ:1358009172

人像美妆---妆容迁移算法研究(Makeup transfer)的更多相关文章

  1. 美图美妆由Try Try接手运营

    美图又把一个拖累营收的业务转让出去了. 美图的电商业务——美图美妆应用在向用户发布终止运营的公告后,宣布把业务交给了寺库旗下公司 Try Try 运营.Try Try 接手了美图美妆的所有管理运营权, ...

  2. MugLife静态照片变3D动画算法研究

    原文:MugLife静态照片变3D动画算法研究 MugLife app是一款可以将静态照片变成3D动画的手机应用,如下效果图所示: 大家可以看到,这个静态图具有了类3D的动画特效,是不是很好玩? 这种 ...

  3. 照片美妆---基于Haar特征的Adaboost级联人脸检测分类器

    原文:照片美妆---基于Haar特征的Adaboost级联人脸检测分类器 本文转载自张雨石http://blog.csdn.net/stdcoutzyx/article/details/3484223 ...

  4. 《A Survey on Transfer Learning》迁移学习研究综述 翻译

    迁移学习研究综述 Sinno Jialin Pan and Qiang Yang,Fellow, IEEE 摘要:   在许多机器学习和数据挖掘算法中,一个重要的假设就是目前的训练数据和将来的训练数据 ...

  5. python opencv 实现Reinhard颜色迁移算法

    Reinhard颜色迁移算法的过程很简单,流程如下,细节部分见原文,题目为color transfer between images: 将参考图片和目标图片转换到LAB空间下 得到参考图片和目标图片的 ...

  6. July-程序员面试、算法研究、编程艺术、红黑树、数据挖掘5大经典原创系列集锦与总结

    程序员面试.算法研究.编程艺术.红黑树.数据挖掘5大经典原创系列集锦与总结 http://blog.csdn.net/v_july_v/article/details/6543438

  7. Akamai在内容分发网络中的算法研究(翻译总结)

    作者 | 钱坤 钱坤,腾讯后台开发工程师,从事领域为流媒体CDN相关,参与腾讯TVideo平台开发维护. 原文是<Algorithmic Nuggets in Content Delivery& ...

  8. 经典算法研究系列:二、Dijkstra 算法初探

    July   二零一一年一月 本文主要参考:算法导论 第二版.维基百科. 一.Dijkstra 算法的介绍 Dijkstra 算法,又叫迪科斯彻算法(Dijkstra),算法解决的是有向图中单个源点到 ...

  9. 静态频繁子图挖掘算法用于动态网络——gSpan算法研究

    摘要 随着信息技术的不断发展,人类可以很容易地收集和储存大量的数据,然而,如何在海量的数据中提取对用户有用的信息逐渐地成为巨大挑战.为了应对这种挑战,数据挖掘技术应运而生,成为了最近一段时期数据科学的 ...

随机推荐

  1. linux网络编程实现投票功能

    投票系统 1.说明: 写了一个投票系统.过程是先配置好server.在写一个网上投票功能,要实现网上投票功能. 事实上功能实现还是非常easy的,麻烦一点的在于过程比較繁杂,要做的东西还是挺多的! 2 ...

  2. [Angular] Dynamic components with ComponentFactoryResolver

    To create a component dynamicly. 1. Add a container with ref: @Component({ selector: 'app-root', tem ...

  3. Erlang 日期和时间处理、时间戳转换

    http://www.csdn 123.com/html/blogs/20131113/95993.htm 获取当前时间 erlang:now()得到的是从1970年1月1日零时起,到现在经过的时间, ...

  4. 设计模式<面向对象的常用七大设计原则>

    面向对象设计的目标之一在于支持可维护性复用,一方面需要实现设计方案或者源码的重用,另一方面要确保系统能够易于扩展和修改,具有较好的灵活性. 常用的设计原则有七个原则: 1.单一职责原则(single ...

  5. javaScript显示实时时间输出

    实时时间输出 <script> function getDateTime(){ var a = new Date(); var year = a.getFullYear(); var mo ...

  6. hello.c内核模块编译 -- linux内核

    Linux开发模块,在本机上看调试信息的方法走通了.当前版本号2.6.32-32-generic uname –r 能够查询 这里取module_param()作为样例. 该宏被定义在include/ ...

  7. URLDecoder和URLEncoder的使用总结

    其实,这两个类的使用并不复杂,URLDecoder和URLEncoder它的作用主要是用于普通字符串和application/x-www-form-rulencoded MIME字符串之间的转换,一般 ...

  8. android之照相、相冊裁剪功能的实现过程

    今天无聊做了一些照相.相冊裁剪功能,希望能够帮到大家! 不多说了,贴代码实际一点: 首先是XML: <ImageButton android:id="@+id/imageButton1 ...

  9. DELPHI高性能大容量SOCKET并发(四):粘包、分包、解包

    粘包 使用TCP长连接就会引入粘包的问题,粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾.粘包可能由发送方造成,也可能由接收方造成.TCP为提 ...

  10. 【Leetcode】Linked List Cycle II

    Given a linked list, return the node where the cycle begins. If there is no cycle, return null. Foll ...