利用CImg实现人脸融合

article/2025/9/4 18:49:48

实验目的

输入两张人脸图像,根据Image Morphing的方法完成中间 11 帧的差值,得到一张人脸渐变的动图。

实验原理

Cross-Dissolve 交叉融合,对两张图片每个像素点按一定的比例进行混合,
公式:Imagehalfway = (1-t) * Image1 + t * image2
但这种方法只适合图像对齐的情况,对于没有对齐的情况,可以采用局部变形的思想,先根据特征点划分出局部图像,然后对局部图像求出平均图像,在平均图像上使用交叉融合,需要的像素值可以使用原图像的双线性插值,最后把局部图像拼接成整体图像。

实验步骤

  • 首先,对图片进行特征点标记,可以使用dlib库对人脸实现自动标记,但是需要用到opencv库,这里进行手动标记,并把标记的点存入文件中,方便下次使用。
    对应代码实现在getDetectionPoints函数中。
    在这里插入图片描述在这里插入图片描述
    除了手动检测的这几个点,还给每张图片加入了8个点,分别是4个角点和每条片的中点。

  • 进行Delaunay三角剖分:如果点集V的一个三角剖分T只包含Delaunay边,那么
    该三角剖分称为Delaunay三角剖分。Delaunay边是指:假设E中的一条边e(两个端点为a,b),e若满足下列条件,则称之为Delaunay边:存在一个圆经过a,b两点,圆内(注意是圆内,圆上最多三点共圆)不含点集V中任何其他的点,这一特性又称空圆特性。最优化:在散点集可能形成的三角剖分中,Delaunay三角剖分所形成的三角形的最小角最大。从这个意义上讲,Delaunay三角网是“最接近于规则化的”三角网。

Delaunay剖分是一种三角剖分的标准,实现它有多种算法。目前常用的一种算法是Bowyer-Watson算法,主要步骤如下:

  1. 构造一个超级三角形,包含所有散点,放入三角形链表。
  2. 将点集中的散点依次插入,在三角形链表中找出其外接圆包含插入点的三角形(称为该点的影响三角形),删除影响三角形的公共边,将插入点同影响三角形的全部顶点连接起来,从而完成一个点在Delaunay三角形链表中的插入。
  3. 根据优化准则对局部新形成的三角形进行优化。将形成的三角形放入Delaunay三角形链表。
  4. 循环执行上述第2步,直到所有散点插入完毕。

对应代码实现在getDelaunayTriangles 函数中。

	// --- step 3 : get Delaunay triangles --- vector<triangle*> triangles_A, triangles_B;getDelaunayTriangles(triangles_A, points_A);// get couterpart delaunay triangles of B from Afor (int i = 0; i < triangles_A.size(); i++) {triangles_B.push_back(new triangle(*points_B.at(triangles_A[i]->index[0]),*points_B.at(triangles_A[i]->index[1]),*points_B.at(triangles_A[i]->index[2]),triangles_A[i]->index[0],triangles_A[i]->index[1],triangles_A[i]->index[2]));}drawTriangles(triangles_A, img_A);drawTriangles(triangles_B, img_B);

在获得了A的三角剖分后,根据对应特征点获得B的三角剖分,效果如下:
在这里插入图片描述在这里插入图片描述

  • 将每个Delaunay三角形对映射到同一个三角形区域

在上一步我们获得了A和B的三角剖分,下一步,就是求出过渡三角形,这里的方法是用两张图片的比例进行加权。

// transition between source A and B
triangle* morph::getTransitionTriangle(const triangle* A, const triangle* B, double rate) {int ax = (int)(rate*(A->a.x) + (1 - rate)*(B->a.x));int ay = (int)(rate*(A->a.y) + (1 - rate)*(B->a.y));int bx = (int)(rate*(A->b.x) + (1 - rate)*(B->b.x));int by = (int)(rate*(A->b.y) + (1 - rate)*(B->b.y));int cx = (int)(rate*(A->c.x) + (1 - rate)*(B->c.x));int cy = (int)(rate*(A->c.y) + (1 - rate)*(B->c.y));return new triangle(point(ax, ay), point(bx, by), point(cx, cy));
}
  • 对每个映射三角形区域进行morphing

首先求过渡三角形到两张图的变换矩阵,TA=B,那么T=B*inv(A),利用变化矩阵算出过渡点,可以直接调用CImg的矩阵除法T=B/A。这里需要使用两个三角形的顶点坐标构造矩阵A和B。需要注意的是,CImg里的坐标是以左上角为原点,向右为x,向下为y。
在这里插入图片描述

CImg<float> morph::getTransTriangle2Triangle(const triangle* src, const triangle* dst) {// transform src to dst// !!! CImg 下标是先y后x !!!CImg<float> m1(3, 3);m1(0, 0) = src->a.x;m1(1, 0) = src->b.x;m1(2, 0) = src->c.x;m1(0, 1) = src->a.y;m1(1, 1) = src->b.y;m1(2, 1) = src->c.y;m1(0, 2) = m1(1, 2) = m1(2, 2) = 1;CImg<float> m2(3, 3);m2(0, 0) = dst->a.x;m2(1, 0) = dst->b.x;m2(2, 0) = dst->c.x;m2(0, 1) = dst->a.y;m2(1, 1) = dst->b.y;m2(2, 1) = dst->c.y;m2(0, 2) = m2(1, 2) = m2(2, 2) = 1;return m2 / m1;
}

然后计算过度图像每一帧的像素值,采用反向映射的方法,用过渡图像的点坐标求出原来两幅图对应点坐标,然后采用双线性插值的方法求出原图像对应点的像素值,然后根据交叉融合公式得到过渡图像素值。

	cimg_forXY(result, x, y) {if (trans_tri->isInTriangle(point(x, y))) {float tx_a = x * H1(0, 0) + y * H1(1, 0) + H1(2, 0);float ty_a = x * H1(0, 1) + y * H1(1, 1) + H1(2, 1);float pixel_a[3] = { 0 };cimg_forC(img_A, c) {pixel_a[c] = img_A.linear_atXY(tx_a, ty_a, 0, c);}float tx_b = x * H2(0, 0) + y * H2(1, 0) + H2(2, 0);float ty_b = x * H2(0, 1) + y * H2(1, 1) + H2(2, 1);float pixel_b[3] = { 0 };cimg_forC(img_B, c) {pixel_b[c] = img_B.linear_atXY(tx_b, ty_b, 0, c);}// morphcimg_forC(result, c) {result(x, y, 0, c) = rate * pixel_a[c] + (1 - rate)*pixel_b[c];}}}

这里使用了CImg的linear_atXY函数。还用到了isInTriangle判断一个点是否在三角形内,采用的是向量点积的方法,如果P在三角形ABC内部,则满足以下三个条件:P,A在BC的同侧、P,B在AC的同侧、PC在AB的同侧。某一个不满足则表示P不在三角形内部。

int cross3(const point &a, const point &b, const point &p) {return (b.x - a.x)*(p.y - a.y) - (b.y - a.y)*(p.x - a.x);
}bool triangle::isInTriangle(const point& p) {if (cross3(a, b, p) >= 0 && cross3(b, c, p) >= 0 && cross3(c, a, p) >= 0)return true;else if (cross3(a, b, p) <= 0 && cross3(b, c, p) <= 0 && cross3(c, a, p) <= 0)return true;elsereturn false;
}

实验结果

在这里插入图片描述

完整代码

Github

参考博客

http://www.demodashi.com/demo/13644.html
http://www.yanglajiao.com/article/qq_31578409/70049516
https://blog.kinpzz.com/2017/04/25/face-morphing/


http://chatgpt.dhexx.cn/article/LsJ9spNJ.shtml

相关文章

《Real-Time Rendering 4th Edition》全文翻译 - 第4章 变换(下)4.5 ~ 4.7

第四章终于结束了……接下来会休息一段时间&#xff0c;祝各位五一劳动节快乐&#xff01; …… 想了想还是不休息了&#xff0c;继续继续&#xff01;&#xff01; 实时渲染&#xff08;第四版&#xff09;Real-Time Rendering (Fourth Edition) 第4章 变换 Chapter 4 Tran…

osgEarth的Rex引擎原理分析(九十五)地形变形(Terrain morphing)

目标&#xff1a;&#xff08;十二&#xff09;中的问题14 morphing翻译为渐变&#xff08;或混合&#xff09;比较合适。 先看两张图&#xff0c;左图是使用了Image morphing&#xff0c;右图没有使用。morph的作用是使视域边界处的瓦片颜色和高程均匀变化。Image morphing控…

Image Warping-Morphing 实现人脸渐变

这学期选修了计算机视觉与模式识别这门课&#xff0c;刚上几周&#xff0c;感觉挺有趣的。 课程上到Image Warping & Morphing的时候老师介绍了一样挺好玩的东西&#xff0c;我用它来做人脸渐变。 先看看效果图&#xff1a; 。。。。。。。。。。。。。。。。。。。。。。…

android按钮详解,android-morphing-button

从一种形状变成另一种形状。 你可以轻易的继承MorphingButton来添加自己的行为(behaviour)&#xff0c;下面是一个继承自MorphingButton的ofLinearProgressButton。 示例代码// sample demonstrate how to morph button to green circle with icon MorphingButton btnMorph (M…

基于StyleGAN的Face-Morphing

本文详细介绍了生成对抗网络&#xff08;GAN&#xff09;的知识&#xff0c;并用其变换人脸&#xff0c;并探寻如何利用StyleGAN生成不同属性&#xff08;如年龄、微笑等&#xff09;的人脸。 概述 直到最近&#xff0c;我才开始探索深度学习的全部内容&#xff0c;并在计算机…

人脸融合技术,用 Python - OpenCV 来帮你实现

提了好几天的人脸融合技术&#xff0c;今天终于被提上日程&#xff0c;该技术是基于之前介绍的技术基础上延伸得到的&#xff0c;如果之前没有了解过这两篇文章&#xff0c;建议提前看下&#xff0c; 实现人脸识别、人脸68个特征点提取&#xff0c;或许这个 Python 库能帮到你&…

FaceMorphing

大学时候上《计算机视觉与模式识别》课程的时候&#xff0c;一个人脸morphing作业的源代码&#xff0c;运行环境为VS2015。 项目源代码下载链接 效果图如下&#xff1a;

实时渲染(RealTimeRendering-4thEdition)笔记——4变换(下)

变换&#xff08;下&#xff09; 顶点混合&#xff08;vertex blender&#xff09;渐变&#xff08;Morphing&#xff09;Geometry Cache Playback投影&#xff08;Projections&#xff09;透视投影 顶点混合&#xff08;vertex blender&#xff09; 现在我们想象要完成一个手…

基于图像的虚拟换装:Morphing architectures for pose-based image generation of people in clothing

项目的重点是变形操作的特征化与实现&#xff0c;解决卷积神经网络中的信息失准问题。我们将所研究的方法应用到一个换衣服的任务中&#xff0c;将其建模为一个条件图像生成问题。尽管对抗性方法在生成性任务中很流行&#xff0c;但我们将此项目的范围限制为监督方法&#xff0…

Traffic morphing阅读笔记

文章目录 前言1 变形1.1 符号表示及算法讲解1.1.1 符号1.1.2 凸优化求解1.1.3 降低开销1.1.4大样本空间分治1.1.5实验中的注意事项短会话源分布变化多样数据包分片 2 实验评估2.1 加密IP语音识别白盒变形黑盒变形2.1.1 与原始分类器对抗二元分类器三元分类器 2.1.2 不可区分性评…

云波社区 l Mecha Morphing(变形机甲)游戏介绍

Mecha Morphing&#xff08;变形机甲&#xff09;由YGG领投的一个创新型GameFi项目即将开始打金&#xff01; 简单介绍一下&#xff0c;该游戏由Call of duty核心团队研发&#xff0c;画风完美阐释暴力美学。在MechaMorphing元宇宙中&#xff0c;玩家可以通过参与PVE, PVP, 土地…

Real-Time Rendering——4.5 Morphing 变形

Imagine that one model is displayed at time t0 and we wish it to change into another model by time t1. For all times between t0 and t1, a continuous “mixed” model is obtained, using some kind of interpolation. An example of morphing is shown in Figure 4.…

《数字图像处理》dlib人脸检测获取关键点,delaunay三角划分,实现人脸的几何变换warpping,接着实现两幅人脸图像之间的渐变合成morphing

这学期在上《数字图像处理》这门课程&#xff0c;老师布置了几个大作业&#xff0c;自己和同学一起讨论完成后&#xff0c;感觉还挺有意思的&#xff0c;就想着把这个作业整理一下 &#xff1a; 目录 1.实验任务和要求 2.实验原理 3.实验代码 3.1利用人脸特征点检测工具dli…

OpenCV:图像变形(Image Morphing)

融合/形变技术 Image Morphing的原理是十分简单的。有两幅图像 I 和 J ,我们希望通过融合图像 I 和 J 来创建一幅新的图像 M. 图像 I 和 J 的融合过程是由参数 alpha 来控制&#xff0c;参数 alpha 介于0和1之间。当alpha 0&#xff0c;新的图像 M看起来更接近 I;当alpha 1&…

计算机动画作业:图像morphing

本学期选了计算机动画课程&#xff0c;第一次作业是图像morphing&#xff0c; 本来打算选择基于四边网格的morphing&#xff0c; 但因为要用到曲面插值&#xff0c;感觉比较麻烦&#xff0c;因此使用基于三角网格的face morphing。 一、总体方案 1、检测人脸特征点&#xff0…

Morphing

<script src"http://widgets.amung.us/classic.js" type"text/javascript"></script> <script type"text/javascript"> </script> Morphing 这篇文章给大家介绍一下morphing&#xff0c;它是一种变型动画&#xff0c;…

深度学习中的GPU与CUDA

对应视频教程&#xff1a;https://www.bilibili.com/video/BV1S5411X7FY/ 文章目录 1. 显卡&#xff08;GPU&#xff09;与驱动2. 显卡与CUDA3. 如何查看自己的显卡 1. 显卡&#xff08;GPU&#xff09;与驱动 显卡&#xff0c;也称之为 GPU。GPU 的全称是 Graphics Processin…

CUDA详解

CUDA&#xff08;Compute Unified Device Architecture&#xff0c;统一计算设备架构&#xff09;&#xff0c;是显卡厂商NVIDIA推出的运算平台。 CUDA™是一种由NVIDIA推出的通用并行计算架构&#xff0c;该架构使GPU能够解决复杂的计算问题。 它包含了CUDA指令集架构&#xf…

CUDA入门

1. 引言 CUDA为a platform and programming model for CUDA-enabled GPUs。该平台通过GPU来进行计算。CUDA为GPU编程和管理 提供C/C语言扩展和API。 CUDA编程中&#xff0c;会同时使用CPU和GPU进行计算&#xff1a; CPU system&#xff1a;称为host。GPU system&#xff1a;…

cuda和cudatoolkit

Pytorch 使用不同版本的 cuda 由于课题的原因&#xff0c;笔者主要通过 Pytorch 框架进行深度学习相关的学习和实验。在运行和学习网络上的 Pytorch 应用代码的过程中&#xff0c;不少项目会标注作者在运行和实验时所使用的 Pytorch 和 cuda 版本信息。由于 Pytorch 和 cuda 版…