人像美妆---妆容迁移算法研究(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*分别对应的效果图如下:

在给一组测试图:

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

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

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

      private void pictureBox4_Click(object sender, EventArgs e)
      {
          if (pictureBox1.Image != null)
          {
              Graphics g = Graphics.FromImage(curBitmap);
              int[] eyePoints = {
                                 173, 370, 177, 441, 191, 509, 212, 577, 236, 640,
                                 267, 698, 303, 748, 347, 793, 399, 826, 465, 837,
                                 526, 825, 575, 792, 611, 748, 643, 699, 671, 643,
                                 695, 578, 714, 507, 727, 435, 728, 364, 214, 316,
                                 245, 284, 285, 273, 328, 274, 370, 281, 402, 308,
                                 363, 309, 325, 304, 287, 302, 251, 307, 513, 307,
                                 544, 282, 583, 275, 623, 274, 660, 284, 688, 313,
                                 654, 306, 620, 302, 585, 304, 549, 309, 269, 390,
                                 282, 373, 300, 364, 323, 361, 347, 366, 365, 380,
                                 378, 401, 360, 406, 342, 410, 321, 412, 300, 408,
                                 283, 401, 533, 399, 544, 378, 562, 365, 585, 359,
                                 607, 362, 625, 371, 638, 386, 624, 398, 608, 406,
                                 588, 410, 567, 408, 550, 404, 424, 394, 424, 453,
                                 417, 512, 386, 542, 398, 580, 446, 588, 480, 588,
                                 528, 576, 536, 539, 506, 511, 494, 452, 490, 393,
                                 363, 653, 394, 643, 429, 637, 462, 642, 495, 636,
                                 527, 643, 557, 654, 535, 687, 506, 713, 461, 726,
                                 415, 715, 384, 688, 373, 656, 417, 657, 462, 661,
                                 504, 657, 546, 657, 505, 676, 460, 686, 414, 676,
                                 322, 389, 586, 387, 457, 392, 461, 502, 463, 554,
                                 463, 588 };

              eyePoints[2 * 50 + 1] -= 2;
              eyePoints[2 * 49 + 1] -= 3;
              eyePoints[2 * 48 + 1] -= 4;
              eyePoints[2 * 47 + 1] -= 3;
              eyePoints[2 * 46 + 1] -= 2;

              eyePoints[2 * 52 + 1] -= 1;
              eyePoints[2 * 61 + 1] -= 2;
              eyePoints[2 * 60 + 1] -= 3;
              eyePoints[2 * 59 + 1] -= 2;
              eyePoints[2 * 58 + 1] -= 1;
              for (int i = 0; i < 101; i++)
              {
                  g.DrawRectangle(new Pen(Color.Red, 1), new Rectangle(eyePoints[2 * i] - 1, eyePoints[2 * i + 1] - 1, 2, 2));
              }
              g.Dispose();
              DateTime start = DateTime.Now;
              curBitmap = ip.SoftSkin(srcBitmap, new Bitmap(startPath + "\\MakeUp\\MAP.png"), null, skinRatio, 30);

              curBitmap = ip.MKMakeupTransfer(curBitmap, new Bitmap(Application.StartupPath + "\\M3.JPG"), curFacePoints, eyePoints);
              DateTime end = DateTime.Now;
                  label1.Text = "TC: " + (end - start).ToString();
              pictureBox1.Image = curBitmap;
          }
      }
 [DllImport("TestDemo_C.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.None, ExactSpelling = true)]
        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);
        public Bitmap MKMakeupTransfer(Bitmap src, Bitmap mask, int[] srcFacePointsAll, int[] mskFacePointsAll)
        {
            Bitmap a = new Bitmap(src);
            int w = a.Width;
            int h = a.Height;
            BitmapData srcData = a.LockBits(new Rectangle(0, 0, a.Width, a.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            BitmapData mskData = mask.LockBits(new Rectangle(0, 0, mask.Width, mask.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            IN_Pic_MakeupTransfer((byte*)srcData.Scan0, w, h, srcData.Stride, srcFacePointsAll,(byte*)mskData.Scan0, mask.Width, mask.Height, mskData.Stride,  mskFacePointsAll);
            a.UnlockBits(srcData);
            mask.UnlockBits(mskData);
            return a;
        }

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

如果问题,请联系QQ:1358009172

时间: 2025-01-02 06:09:27

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

玩具化的AR试妆,能否玩出美妆行业的市场大未来?

据媒体报道,今年七夕,意大利奢侈品牌宝格丽适时推出了Divas'Dream中国区粉红限量款项链,虽然是特别限量款,但这次宝格丽还采取了一个很亲民的营销策略:和美图旗下的美妆相机联合推出该款项链的AR(增强现实技术)特效.这也是美图首次联手奢侈品牌推出AR珠宝首饰. 但对于美妆相机来说,这只是一次小小的跨界试水.此刻这款对于很多用户都颇为陌生的App,截止2016年年底,累计用户超过1.2亿,月活跃用户数超2000万,其中87%以上为女性用户(以80后.90后为主),标准的美妆行业流量池,而它用来

通用高校排课算法研究----3.基于时间片优先级排课算法

通用高校排课算法研究----3.基于时间片优先级排课算法 3   基于时间片优先级排课算法描述与分析 排课问题实质上是时间.教师.班级.教室.课程这五维关系的冲突问题,要合理的解决这个问题首先要了解排课中的一些基本原则以及排课的一些基本要求. 3.1排课中的基本原则 在课程的编排中应遵循一定的规则, 只有按照基本规则来进行课程的编排才能够减少冲突的发生, 这些基本规则主要有以下几条: 1) 同一班级的学生在同一时间(某些特定的选修课时间除外) 不能安排两门课程 2) 同一教师在同一时间不能安排两

亚洲美容与化妆品产业大会:Focussend驱动美妆行业营销创新

9月1日,为期两天的首届"亚洲美容与化妆品产业大会2015"在上海万豪虹桥大酒店举行.此次大会,不仅有欧莱雅.联合利华.珀莱雅及LG健康生活等知名企业60余位专家分享化妆品领域的研究思路及经验,更有覆盖原料.营销.包装.检测等四个领域的17家科技企业现场参展,共同为处在变革时期的中国化妆品业寻找新的机遇点.Focussend作为大会独家冠名邮件服务商应邀参加此次大会. 那么在互联网快速发展的今天,美妆行业的如何营销方式变革创新?除了需要了解用户,为其提供更多优质的产品外,该如何更好地吸

吉米小屋美妆××× 开拓创新理念创造事业巅峰

如今,越来越多的人开始注重美妆的性比价,他们往往会选择质美价廉的化妆品.化妆品的消费市场不断扩大,市场上的火热,让许多投资商开始选择×××化妆品品牌.而吉米小屋作为化妆品行业的佼佼者,凭借着其企业实力和产品的高质量,深受投资商的喜爱.在如此迅速发展的×××店的背后,是吉米小屋对×××商的扶持和培养,是吉米小屋健全的×××体系,是吉米小屋始终坚持和合作者实现共赢的方针. 吉米小屋何以能保证每一家店都轻松盈利无惧竞争?这不光是企业的先见之明和抢占先机,更因为它善于掌控细节,用无可挑剔的美妆品质.无可

美图美妆由Try Try接手运营

美图又把一个拖累营收的业务转让出去了.美图的电商业务--美图美妆应用在向用户发布终止运营的公告后,宣布把业务交给了寺库旗下公司 Try Try 运营.Try Try 接手了美图美妆的所有管理运营权,包括品牌推广.商品采购.销售.发货.客服等,美图则会继续用旗下的产品为美图美妆导流,并可以获得保底收益和分成收益.除了运营美图美妆业务,寺库创始人兼 CEO 李日学还说会把美图的 AI 测肤功能融入寺库的业务.寺库是一家主营奢侈品电商业务的公司,于 2017 年 9 月在美国纳斯达克上市,截止 201

韩国SNP入驻晒丫社区,品牌携手共同打造美妆新时代

近日,消费者购买美妆品的第一参考平台小红书被曝被各大安卓平台下架,微博也受到牵连,这是近年来社区整改和改型最严肃的一个阶段,这是否意味着对新型平台有着极大的利好和帮助呢?晒丫社区作为国内美妆平台的一匹黑马,直骋美妆领域,意在打造一个真正体验用户需求,反应真实使用体验的社区,受到了很多知名品牌的支持与鼓励.韩国美妆品牌SNP便是晒丫社区的支持者之一,其尤为看重晒丫社区的红人种草.推荐.时尚活动联名等形式,已于近日入驻晒丫社区,品牌携手共同打造美妆新时代.SNP品牌专注护肤 2008年10月SNP皮

基本算法研究1-冒泡排序算法测试

基本算法研究1-冒泡排序算法测试 1.经典冒泡排序法基本原理 先看一个动态图,感觉比较形象: 冒泡排序(Bubble Sort)是一种简单的排序算法.默认是从小到大排序,即把最大的数据排在最后,相当于每次把最大数据像气泡一样浮到水面一样.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换. 基本步骤: 1.比较相邻的元素.如果第一个比第二个大,就交换他们两个.        2.对每一对相邻元素作同样的工作,从开始第一对

HTML5游戏开发-扫雷及其算法研究

吕蒙曰:士隔三月[1],当刮目相看.所以,在下在这三月中发奋图强,花了约莫8节信息课的时间研究扫雷.呜呼,由于在下才能尚且不足,所以也就只能勉强打过中级难度的吧.不过,一边玩的同时,我还一边对扫雷这个游戏的制做方法构思了一下.所以说,本文中的算法完全是凭借自己对扫雷游戏规则的总结而自行研发出来的,倘若和MS的扫雷玩法有些出入,还望各位看官见谅. [1]出自<孙权劝学>,原文为"士别三日",由于在下这三个月来都不曾发表博客,所以引申到"士隔三月",各位看官

Supervised Descent Method Face Alignment 代码下载 和 算法研究 之一

1 主要内容: Supervised Descent Method and its Applications to Face Alignment算法研究. 2代码彩蛋:我问了好久,xxiong好心人发给我的,希望能对你们学习有帮助: 低调下载: http://humansensing.cs.cmu.edu/xxiong/mexintraface1.3.1%28release%29.zip. 注意杜绝一切商业用途,如果需要商业用途,请联系作者本人!! 3本文分为几个部分: (1)解决什么问题 (2