图像变形背后的想法很简单。给定两个图像我们想通过将图像和混合来创建中间图像。图像的混合由参数控制的是在0和1之间()。当为0时,变形看起来像,而当为1 时,变形看起来。天真的,您可以在每个像素上使用以下方程式混合图像

但是,使用上面的方程式将希拉里·克林顿国务卿和特德·克鲁兹参议员的图像设置为0.5,会产生以下可怕结果。

产生的图像令人不安,但同时也会给您尖叫。恳求您在融合图像之前以某种方式对齐眼睛和嘴巴。当您尝试在不先调整思路的情况下将两种不同的政治意识形态融合在一起时,就会得到类似的令人不安的结果,但我离题了。

因此,要将图像变形为图像,我们需要首先在两个图像之间建立像素对应。换句话说,对于图像中的每个像素,我们需要找到它在图像中的对应像素。假设我们神奇地找到了这些对应关系,我们可以分两步混合图像。首先,我们需要计算变形图像中像素的位置。由下式给出

(1) 

其次,我们需要使用以下公式找到像素的强度

(2) 

而已。我们完了。现在,我们去投票给特朗普。开玩笑!就像特朗普一样,我省略了一些重要的细节。为图像I中的每个像素找到图像J中的对应点与在美国和墨西哥之间建立10英尺的墙一样困难。可以做到,但是它很昂贵,并不是真正必要的。

但是很容易找到一些点对应关系。为了使两个不同的对象(如猫的脸和人的脸)变形,我们可以单击两个图像上的几个点以建立对应关系,并为其余像素插值结果。接下来,我们将详细了解“脸部变形”的完成方式,但是相同的技术可以应用于任何两个对象。

脸部变形:逐步

可以使用以下步骤变形两个面。为了简单起见,我们将假定图像的大小相同,但这不是必需的。

1.使用面部特征检测找到点对应

让我们从获取相应点开始。首先,我们可以通过检测面部特征点来自动(或手动)获得很多。我使用dlib来检测68个对应点。接下来,我又增加了四个点(一个在右侧耳朵上,一个在脖子上,另外两个在肩膀上)。最后,我还添加了图像的角点和这些角点之间的中间点作为对应点。不用说,可以在头和脖子周围添加更多点以获得更好的结果,或者删除手动单击的点以获得稍微差一点(但是全自动的)的结果。

2. Delaunay三角剖分

从上一步开始,我们有两组80个点-每个图像一组。我们可以计算两组中对应点的平均值,并获得一组80个点。在这组平均点上,我们执行Delaunay三角剖分。Delaunay三角剖分的结果是由80点数组中的点的索引表示的三角形列表。在这种特殊情况下,三角剖分产生了149个三角形,将80个点连接在一起。三角剖分存储为三列数组。三角剖分的前几行如下所示。

三角剖分
38 40 37
35 30 29
38 37 20
18 37 36
33 32 30

它显示点38、40和37形成一个三角形,依此类推。三角剖分显示在下面的两个图像中。

请注意,两个图像中的三角形捕获了近似相似的区域。我们从点对应开始,现在由于三角剖分,我们有了三角形(或区域)对应。

3.扭曲图像和Alpha混合

为了更好地理解下面的描述,请在此处订阅我们的时事通讯以下载代码和图像。

现在,我们可以智能地融合两个图像。如前所述,混合量将由参数控制。使用以下步骤创建变形。

  1. 在变形图像中找到特征点的位置:在变形图像中,我们可以使用等式(1)找到所有80个点的位置。
  2. 计算仿射变换:因此我们在图像1中有一组80点,在图像2中有另一组80点,在变形图像中有第三组80点。我们也知道在这些点上定义的三角剖分。在图像1中选择一个三角形,在变形图像中选择一个相应的三角形,并计算仿射变换,该仿射变换将图像1中的三角形的三个角映射到变形图像中相应的三角形的三个角。在OpenCV中,可以使用getAffineTransform完成此操作。为每对149个三角形计算仿射变换。最后,重复图像2和变形图像的过程。
  3. 变形三角形:对于图像1中的每个三角形,使用在上一步中计算出的仿射变换将三角形内的所有像素变换为变形图像。对图像1中的所有三角形重复此操作以获得图像1的变形版本。类似地,获得图像2的变形版本。在OpenCV中,这可以通过使用warpAffine函数来实现。但是,warpAffine会获取图像,而不是三角形。诀窍是计算三角形的边界框,使用warpAffine扭曲边界框内的所有像素,然后遮盖三角形外部的像素。使用fillConvexPoly创建三角形蒙版。使用warpAffine时,请确保使用blendMode BORDER_REFLECT_101。与克林顿国务卿掩盖她的电子邮件相比,它掩盖了接缝。
  4. Alpha混合变形图像:在上一步中,我们获得了图像1和图像2的变形版本。可以使用公式(2)将这两个图像进行Alpha混合,这是您最终的变形图像。在代码中,我提供了变形三角形和alpha混合,将它们合并在一个步骤中。

脸部变形结果

应用上述技术的结果如下所示。中间的图像是左右图像的50%混合。此页面顶部的视频显示了具有不同alpha值的动画。动画是一种廉价的技巧,可以将变形中的许多缺陷隐藏起来。特德·克鲁兹(Ted Cruz)参议员会喜欢的。

大多数面部特征都很好地对齐了。脸部以外的图像部分排列得不太好,因为在该区域中对应的点较少。可以手动添加其他点来修复错位并获得更好的结果。

总结:

point 68

point 80

delaunay 149

图1三角映射

图2三角映射

比例Alpha混合

Delaunay

原文:https://www.learnopencv.com/face-morph-using-opencv-cpp-python/

--

face morhper的更多相关文章

随机推荐

  1. 基于NFS的PV动态供给(StorageClass)

    一.简介 PersistentVolume(PV)是指由集群管理员配置提供的某存储系统上的段存储空间,它是对底层共享存储的抽象,将共享存储作为种可由用户申请使的资源,实现了“存储消费”机制.通过存储插 ...

  2. 使用ansible部署CDH 5.15.1大数据集群

    使用ansible离线部署CDH 5.15.1大数据集群 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在此之前,我之前分享过使用shell自定义脚本部署大数据集群,不管是部署CD ...

  3. orm字段类型使用

    IntegerField:整数类型,映射到数据库中会变成11位的int类型 num是整型字典  object中的5是第五行还是id是5? 整型字符串型都可以传到整数字段 FloatField:浮点数类 ...

  4. k8s安装之prometheus.yaml

    这个系列的东东满多的.要另开系列说明. 这里为了内容连续完成,先贴一个吧,其它configmap,exporter就不展示. 为了保持统一,将prometheus也放到二级目录了. - '--web. ...

  5. Python 过滤a文件中每一行内容,保存到b文件中

    #coding=utf-8print 1#初始化文件crash_log.log with open('e:/1/crash_log.log','w')as f: f.close() def fw(se ...

  6. Dubbo基础入门

    Dubbo概述 Dubbo的背景 随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进. 单一应用架构 ...

  7. 2-html标题、段落、换行与常用的字符实体

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  8. 解决 spring boot 线程中使用@Autowired注入Bean的方法,报java.lang.NullPointerException异常

    问题描述 在开发中,因某些业务逻辑执行时间太长,我们常使用线程来实现.常规服务实现类中,使用 @Autowired 来注入Bean,来调用其中的方法.但如果在线程类中使用@Autowired注入的Be ...

  9. java.util.Properties 读取配置文件中的参数

    用法 getProperty方法的返回值是String类型. java.util.Properties 读取配置文件中的参数 //读取配置文件 FileInputStream inStream = n ...

  10. Oracle row_number() over() 分析函数--取出最新数据

    语法格式:row_number() over(partition by 分组列 order by 排序列 desc) 一个很简单的例子 1,先做好准备 create table test1( id v ...