OpenCV之换脸技术:一场面部识别的奇妙之旅
在这个数字化与智能化并进的时代,图像处理技术日益成为连接现实与虚拟世界的桥梁。其中,换脸技术作为一项颇受欢迎且富有挑战性的应用,不仅让人惊叹于技术的魔力,更在娱乐、影视制作等领域展现了无限可能。今天,我们就来探索如何使用OpenCV这一强大的计算机视觉库,实现基础的换脸效果。
一、前言
OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习软件库,它提供了丰富的图像处理和视频分析功能。通过OpenCV,我们可以轻松地进行面部检测、特征点匹配、图像变换等操作,为实现换脸技术打下坚实基础。
二、技术原理
换脸技术的核心在于将源图像中的人脸区域精确地映射到目标图像上,同时保持面部特征的自然和协调。这通常涉及以下几个关键步骤:
- 面部检测:利用预训练的面部检测模型(如Haar特征分类器或深度学习方法)在图像中定位人脸区域。
- 特征点匹配:通过面部特征点检测算法(如Dlib的68点或5点特征检测)找到源图像和目标图像中对应的关键点。
- 图像变换:使用仿射变换、透视变换或更复杂的非线性变换(如Delaunay三角剖分)将源人脸变形以匹配目标人脸的形状。
- 图像融合:将变形后的源人脸与目标图像的背景进行无缝融合,处理边缘,使其看起来自然。
三、实现步骤
下面是一个基于OpenCV的简单换脸示例代码框架,注意,这里假设你已经安装了OpenCV和Dlib库(用于特征点检测)。
import cv2
import dlib
import numpy as np # 定义面部特征点的区域索引
JAW_POINTS = list(range(0, 17)) # 下巴
RIGHT_BROW_POINTS = list(range(17, 22)) # 右眉毛
LEFT_BROW_POINTS = list(range(22, 27)) # 左眉毛
NOSE_POINTS = list(range(27, 35)) # 鼻子
RIGHT_EYE_POINTS = list(range(36, 42)) # 右眼
LEFT_EYE_POINTS = list(range(42, 48)) # 左眼
MOUTH_POINTS = list(range(48, 61)) # 嘴巴
FACE_POINTS = list(range(17, 68)) # 整个面部(不包括下巴,但包括其他所有) # 关键点集,用于生成面部掩模
POINTS = [LEFT_BROW_POINTS + RIGHT_EYE_POINTS + LEFT_EYE_POINTS + RIGHT_BROW_POINTS + NOSE_POINTS + MOUTH_POINTS]
POINTStuple = tuple(POINTS) def getFaceMask(im, keypoints): """根据关键点生成面部掩模""" # 创建一个与输入图像大小相同的零矩阵 im = np.zeros(im.shape[:2], dtype=np.float64) for p in POINTS: # 对关键点集进行凸包计算 points = cv2.convexHull(keypoints[p]) # 填充凸包区域 cv2.fillConvexPoly(im, points, color=1) # 将单通道图像转换为三通道图像,以适应OpenCV的显示要求 im = np.array([im, im, im]).transpose((1, 2, 0)) # 对掩模进行高斯模糊处理,以减少边缘的锯齿状 im = cv2.GaussianBlur(im, ksize=(25, 25), sigmaX=0) return im def getM(points1, points2): """计算从points1到points2的仿射变换矩阵""" # 将点转换为浮点数类型 points1 = points1.astype(np.float64) points2 = points2.astype(np.float64) # 计算均值,用于归一化 c1 = np.mean(points1, axis=0) c2 = np.mean(points2, axis=0) # 归一化 points1 -= c1 points2 -= c2 # 计算标准差 s1 = np.std(points1) s2 = np.std(points2) # 归一化 points1 /= s1 points2 /= s2 # 使用奇异值分解计算仿射变换矩阵 U, S, Vt = np.linalg.svd(points1.T * points2) R = (U * Vt).T # 返回完整的仿射变换矩阵 return np.hstack(((s2 / s1) * R, c2.T - (s2 / s1) * R * c1.T)) def getKeypoints(im): """检测图像中的面部关键点""" # 检测面部 rects = detector(im, 1) # 获取面部关键点 shape = predictor(im, rects[0]) # 将关键点转换为numpy矩阵 s = np.matrix([[p.x, p.y] for p in shape.parts()]) return s def normalColor(a, b): """调整b图的颜色值,使其与a图相似""" # 对a和b进行高斯模糊处理,以减少噪声 aGauss = cv2.GaussianBlur(a, ksize=(111, 111), sigmaX=0) bGauss = cv2.GaussianBlur(b, ksize=(111, 111), sigmaX=0) # 计算颜色调整权值 weight = aGauss / bGauss # 处理无穷大值 where_are_inf = np.isinf(weight) weight[where_are_inf] = 0 # 返回调整后的b图 return b * weight # 读取换脸所需的图片
a = cv2.imread("pyy1.jpg") # 换脸A图片
b = cv2.imread("hg.png") # 换脸B图片 # 初始化面部检测器和关键点预测器
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat") # 获取A图片和B图片的面部关键点
aKeyPoints = getKeypoints(a)
bKeyPoints = getKeypoints(b) # 复制B图片,以便后续处理不破坏原图
bOriginal = b.copy() # 获取A图片和B图片的面部掩模
aMask = getFaceMask(a, aKeyPoints)
cv2.imshow("aMask", aMask) # 显示A图片的面部掩模
cv2.waitKey() bMask = getFaceMask(b, bKeyPoints) # 获取B图片的面部掩模
cv2.imshow("bMask", bMask) # 显示B图片的面部掩模
cv2.waitKey() # 计算从B图片面部到A图片面部的仿射变换矩阵
M = getM(aKeyPoints[POINTStuple], bKeyPoints[POINTStuple]) # 使用仿射变换矩阵将B图片的面部掩模变换到A图片上
bMaskWarp = cv2.warpAffine(bMask, M, dsize=a.shape[:2][::-1], borderMode=cv2.BORDER_TRANSPARENT, flags=cv2.WARP_INVERSE_MAP)
cv2.imshow("bMaskWarp", bMaskWarp) # 显示变换后的B图片面部掩模
cv2.waitKey() # 获取面部区域的最大掩模(A和B的掩模叠加)
mask = np.max([aMask, bMaskWarp], axis=0)
cv2.imshow("mask", mask) # 显示最大掩模
cv2.waitKey() # 使用仿射变换矩阵将B图片变换到A图片上
bWrap = cv2.warpAffine(b, M, dsize=a.shape[:2][::-1], borderMode=cv2.BORDER_TRANSPARENT, flags=cv2.WARP_INVERSE_MAP)
cv2.imshow("bWrap", bWrap) # 显示变换后的B图片
cv2.waitKey() # 调整B图片的颜色,使其与A图片相似
bcolor = normalColor(a, bWrap)
cv2.imshow("bcolor", bcolor) # 显示调整颜色后的B图片
cv2.waitKey() # 换脸:在掩模区域使用B图片的颜色,其他区域使用A图片
out = a * (1.0 - mask) + bcolor * mask # 显示原始图片和换脸结果
cv2.imshow("a", a) # 显示A图片
cv2.imshow("b", bOriginal) # 显示原始B图片
cv2.imshow("out", out / 255) # 显示换脸结果(注意:这里除以255是为了将像素值归一化到0-1之间,便于显示)
cv2.waitKey()
cv2.destroyAllWindows() # 关闭所有窗口
代码效果:

结语
通过上述步骤,我们利用OpenCV和Dlib实现了一个基础的换脸效果。虽然这只是冰山一角,但它为我们打开了一个充满无限想象的空间。随着技术的不断进步,未来的换脸技术将更加智能化、高效化,为我们的生活带来更多乐趣和可能。如果你对图像处理感兴趣,不妨亲自动手尝试一下,探索更多未知的领域吧!
相关文章:
OpenCV之换脸技术:一场面部识别的奇妙之旅
在这个数字化与智能化并进的时代,图像处理技术日益成为连接现实与虚拟世界的桥梁。其中,换脸技术作为一项颇受欢迎且富有挑战性的应用,不仅让人惊叹于技术的魔力,更在娱乐、影视制作等领域展现了无限可能。今天,我们就…...
Linux学习笔记9 文件系统的基础
一、查看文件组织结构 Linux中一切都是文件。 Linux和Win的文件系统不是一个结构,Linux存在的根目录是所有目录的起点。 所有的存储空间和设备共享一个根目录,不同的磁盘块和分区挂载在其下,成为某个子目录的子目录,甚至设备也挂…...
Android OpenGL粒子特效
在本篇,我们将开启一个新的项目,探索粒子的世界。粒子是一种基本的图形元素,它们通常被表示为一组点。通过巧妙地组合一些基础的物理效果,我们能够创造出许多令人惊叹的视觉效果。想象一下,我们可以模拟一个水滴从喷泉…...
5 -《本地部署开源大模型》在Ubuntu 22.04系统下ChatGLM3-6B高效微调实战
在Ubuntu 22.04系统下ChatGLM3-6B高效微调实战 无论是在单机单卡(一台机器上只有一块GPU)还是单机多卡(一台机器上有多块GPU)的硬件配置上启动ChatGLM3-6B模型,其前置环境配置和项目文件是相同的。如果大家对配置过程还…...
dpkg:错误:另外一个进程已经为dpkg前端锁加锁
一、 问题描述 在新装ubuntu系统时,我们常常会遇见dpkg的错误,dpkg:错误:另外一个进程已经为dpkg前端锁加锁,如下图。 二、问题解决 方法一 先执行sudo rm /var/lib/dpkg/lock-frontend然后再继续安装软件包,如果出现问题dpkg:…...
基于SSM服装定制系统的设计
管理员账户功能包括:系统首页,个人中心,用户管理,服装类型管理,服装信息管理,服装定制管理,留言反馈,系统管理 前台账号功能包括:系统首页,个人中心…...
RK3588开发笔记-usb3.0 xhci-hcd控制器挂死问题解决
目录 前言 一、问题现象 二、问题分析 三、问题排查 总结 前言 在使用 RK3588 芯片进行开发的过程中,我遇到了 USB 3.0 xHCI-HCD 控制器外接5G通讯模块偶尔挂死的问题。这个问题导致 USB 设备失去响应,且不能恢复,需要重启整个系统才能恢复使用,针对该问题进行大量测试以…...
深入解析TCP/IP协议:网络通信的基石
1. 引言 TCP/IP 协议是现代计算机网络的核心,它为互联网上的设备提供了通信的基础。在网络通信中,TCP/IP 协议栈是无处不在的,无论是个人设备的浏览器请求,还是大型分布式系统的内部通信,都依赖于它的稳定、高效与可靠…...
基于微信小程序的汽车预约维修系统(lw+演示+源码+运行)
基于微信小程序的汽车预约维修系统 摘要 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了基于微信小程序的汽车预约维修系统的开发全过程。通过分析基于微信小程序的汽车预约维修系统管理的不足,创建了…...
wifi、热点密码破解 - python
乐子脚本,有点小慢,试过多线程,系统 wifi 连接太慢了,需要时间确认,多线程的话系统根本反应不过来。 也就可以试试破解别人的热点,一般都是 123456 这样的傻鸟口令 # coding:utf-8 import pywifi from pyw…...
bean的实例化2024年10月17日
跟不上为基础 1.你的java学习路线 2. 3.课程 注解的装配 contoller调用service用的是注解装配...
告别ELK,APO提供基于ClickHouse开箱即用的高效日志方案——APO 0.6.0发布
ELK一直是日志领域的主流产品,但是ElasticSearch的成本很高,查询效果随着数据量的增加越来越慢。业界已经有很多公司,比如滴滴、B站、Uber、Cloudflare都已经使用ClickHose作为ElasticSearch的替代品,都取得了不错的效果ÿ…...
Excel使用技巧:定位Ctrl+G +公式+原位填充 Ctrl+Enter快速填充数据(处理合并单元格)
Excel的正确用法: Excel是个数据库,不要随意合并单元格。 数据输入的时候一定要按照行列输入,中间不要留空,不然就没有关联。 定位CtrlG 公式原位填充 CtrlEnter快速填充数据 如果把合并的单元格 取消合并,只有第一…...
JAVA学习-练习试用Java实现“成绩归类”
问题: 编写程序,输入一批学生的成绩,遇0或负数则输入结束,要求统计并输出优秀(大于85)、通过(60~84)和不及格(小于60)的学生人数。 示例 &#x…...
【Hive】7-拉链表的设计与实现
拉链表的设计与实现 数据同步问题 背景 例如:MySQL中有一张用户表: tb_user,每个用户注册完成以后,就会在用户表中新增该用户的信息,记录该用户的id、手机号码、用户名、性别、地址等信息。 每天都会有用户注册,产生…...
Maxwell 底层原理 详解
Maxwell 是一个 MySQL 数据库的增量数据捕获(CDC, Change Data Capture)工具,它通过读取 MySQL 的 binlog(Binary Log)来捕获数据变化,并将这些变化实时地发送到如 Kafka、Kinesis、RabbitMQ 或其他输出端。…...
使用短效IP池的优势是什么?
短效IP池作为代理IP服务中一种独特的资源管理方式,其应用已经在数据采集、市场分析和网络安全等多个领域中展示出强大的功能。尽管“短效”听起来似乎意味着某种限制,然而在某些特定的应用场景下,短效IP池却提供了无可比拟的优势。本文将详细…...
zynq烧写程序到flash后不运行
🏆本文收录于《全栈Bug调优(实战版)》专栏,主要记录项目实战过程中所遇到的Bug或因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&am…...
JMeter如何设置HTTP代理服务器?
1、 2、添加线程组 3、设置HTTP代理服务器,目标控制器选择“测试计划>线程组” 过滤掉不需要的信息 4、设置电脑手动代理 5、点击启动,在浏览器操作就可以了...
React面试题笔记(一)
一、react基础面试题 1.react中keys的作用是什么? key是是用于追踪哪些列表被修改,被添加或者被移除的辅助标识。 在开发过程中,我们需要保证某个元素的 key 在其同级元素中具有唯一性。在 React Diff 算法中 React 会借助元素的 Key 值来判断该元素是…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
【 java 虚拟机知识 第一篇 】
目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...
Bean 作用域有哪些?如何答出技术深度?
导语: Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,…...
ubuntu系统文件误删(/lib/x86_64-linux-gnu/libc.so.6)修复方案 [成功解决]
报错信息:libc.so.6: cannot open shared object file: No such file or directory: #ls, ln, sudo...命令都不能用 error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory重启后报错信息&…...
