OpenCV之换脸技术:一场面部识别的奇妙之旅

在这个数字化与智能化并进的时代,图像处理技术日益成为连接现实与虚拟世界的桥梁。其中,换脸技术作为一项颇受欢迎且富有挑战性的应用,不仅让人惊叹于技术的魔力,更在娱乐、影视制作等领域展现了无限可能。今天,我们就来探索如何使用OpenCV这一强大的计算机视觉库,实现基础的换脸效果。

一、前言

OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习软件库,它提供了丰富的图像处理和视频分析功能。通过OpenCV,我们可以轻松地进行面部检测、特征点匹配、图像变换等操作,为实现换脸技术打下坚实基础。

二、技术原理

换脸技术的核心在于将源图像中的人脸区域精确地映射到目标图像上,同时保持面部特征的自然和协调。这通常涉及以下几个关键步骤:

  1. 面部检测:利用预训练的面部检测模型(如Haar特征分类器或深度学习方法)在图像中定位人脸区域。
  2. 特征点匹配:通过面部特征点检测算法(如Dlib的68点或5点特征检测)找到源图像和目标图像中对应的关键点。
  3. 图像变换:使用仿射变换、透视变换或更复杂的非线性变换(如Delaunay三角剖分)将源人脸变形以匹配目标人脸的形状。
  4. 图像融合:将变形后的源人脸与目标图像的背景进行无缝融合,处理边缘,使其看起来自然。
三、实现步骤

下面是一个基于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实现了一个基础的换脸效果。虽然这只是冰山一角,但它为我们打开了一个充满无限想象的空间。随着技术的不断进步,未来的换脸技术将更加智能化、高效化,为我们的生活带来更多乐趣和可能。如果你对图像处理感兴趣,不妨亲自动手尝试一下,探索更多未知的领域吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/56785.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

arp欺骗及其实验

ARP欺骗(ARP Spoofing)是一种网络攻击技术,攻击者通过伪造ARP(地址解析协议)消息,将其MAC地址与目标IP地址关联,从而实现对网络流量的截获、篡改或重定向。以下是ARP欺骗的详细信息:…

怎么修改编辑PDF的内容,有这4个工具就行了。

PDF 软件在现代的办公或者是学习当中的应用非常广泛,编辑PDF内容对很多人来说也是一件常有的事情。如果有了PDF 编辑软件,查看,编辑,修改,分享也会变得更加方便简单,所以今天要给大家介绍几款这样的工具。 …

python-库

python-库 常用库 仅个人笔记使用,感谢点赞关注 常用库 dill:对象序列化 目前仅专注于 NLP 大模型 机器学习和前后端的技术学习和分享 感谢大家的关注与支持!

vue特效,一片动态星空

vue实现漂亮星空&#xff0c;超级简单 1.创建vue项目&#xff1a; vue create demo 2.注册vuecli : npm i element-ui -S 3.加载依赖 &#xff1a;npm i 4.运行项目 :npm run serve <!DOCTYPE html> <html lang"en"> <head><…

Linux SSH免密登录

生成密钥-默认 出现三个提示步骤,直接回车即可 看到下图的提示的时候,你已经生成密钥成功 ssh-keygen -t rsa 生成密钥-定制化 与默认的步骤一致,唯一不同的是命令,话不多说,上命令 ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa_new-t rsa&#xff1a;指定密钥类型为 RSA。…

FreeRTOS:任务通知

目录 一、简介 二、相关API 1.发送任务通知的API 2.获取任务通知的API 三、使用场景 1.代替消息队列 2.代替二值信号量 3.代替计数信号量 4.代替事件组 一、简介 FreeRTOS的任务通知&#xff08;Task Notifications&#xff09;是一个轻量级、快速的机制&#xff0c;用于…

【ELK】初始阶段

一、logstash学习 安装的时候最好不要有中文的安装路径 使用相对路径 在 Windows PowerShell 中&#xff0c;如果 logstash 可执行文件位于当前目录下&#xff0c;你需要使用相对路径来运行它。尝试输入以下命令&#xff1a; .\logstash -e ‘input { stdin { } } output { s…

详解23种设计模式——第一部分:概述+创建型模式

目录 1. 概述 2. 创建型模式 2.1 简单&#xff08;静态&#xff09;工厂模式 2.1.1 介绍 2.1.2 实现 2.2 工厂模式 2.3 抽象工厂模式 2.4 单例模式 2.4.1 饿汉模式 2.4.2 懒汉模式 2.4.3 线程安全的懒汉式 2.4.4 DCL单例 - 高性能的懒汉式 2.5 建造者模式 2.6 原…

kaptcha依赖maven无法拉取的问题

老依赖了&#xff0c;就是无法拉取&#xff0c;也不知道为什么&#xff0c;就是用maven一直拉去不成功&#xff0c;还以为是魔法的原因&#xff0c;试了好久发现不是&#xff0c;只好在百度寻求帮助了&#xff0c;好在寻找到了这位大佬的文章Maven - 解决无法安装 Kaptcha 依赖…

纯血鸿蒙!

纯血鸿蒙&#xff0c;这是哪个营销大师给起的名字啊&#xff01; 纯血&#xff01;象征着高贵、自信、自主、血性、英雄气概&#xff0c;都融入这纯血鸿蒙了&#xff01; 鸿蒙本就是开天辟地&#xff0c;加上纯血&#xff0c;真是荡气回肠&#xff01; 鸿蒙的推出背景 我们前…

Git安装与配置(2.47.0版本超详细)

一、背景 1.什么是gitt&#xff1f;&#xff08;官网引用&#xff09; Git 是一个快速、可扩展的分布式版本控制系统&#xff0c;它拥有异常丰富的命令集&#xff0c;可以提供高级操作和对内部的完全访问。 参阅 gittutorial[7] 开始使用&#xff0c;然后查看 giteveryday[7] …

ARM嵌入式学习--第四天

汇编与C混合编程 -汇编指令中调用C语言 .global _start _start:mov r0,#5mov r1,#3bl add stop:b stop int add(int a,int b) {int c a b;return c; } 无优化情况&#xff1a;&#xff08;反汇编之后&#xff0c;发现多了很多很多指令&#xff0c;运行之后结果是错误的&a…

MySQL-19.多表设计-一对多-外键

一.多表问题分析 二.添加外键 三.外键约束的问题

SpringCloud无介绍快使用,单机Eureka服务注册中心cloud-eureka-server7001搭建(十)

TOC 问题背景 从零开始学springcloud微服务项目 注意事项&#xff1a; 约定 > 配置 > 编码IDEA版本2021.1这个项目&#xff0c;我分了很多篇章&#xff0c;每篇文章一个操作步骤&#xff0c;目的是显得更简单明了controller调service&#xff0c;service调dao项目源码以及…

单位评职称需要在指定媒体上投稿发表文章看我如何轻松应对

在职场中,晋升与评职称是一项不可或缺的任务,而在这个过程中,完成相关的投稿更是至关重要。作为单位的一名员工,当我得知自己需要在指定的媒体上发表文章以满足职称评审要求时,心中既期待又忐忑。起初,我选择了传统的邮箱投稿方式,然而却没想到,这条路竟让我倍感挫折。 刚开始,…

交叉注意力融合时域、频域特征的FFT + CNN -BiLSTM-CrossAttention轴承故障识别模型

往期精彩内容&#xff1a; Python-凯斯西储大学&#xff08;CWRU&#xff09;轴承数据解读与分类处理 Pytorch-LSTM轴承故障一维信号分类(一)-CSDN博客 Pytorch-CNN轴承故障一维信号分类(二)-CSDN博客 Pytorch-Transformer轴承故障一维信号分类(三)-CSDN博客 三十多个开源…

【Pycharm默认解释器配置文件】怎样删除配置解释器的无效历史记录?

有时候我们希望删除无效的解释器路径&#xff0c;可以找到这个文件&#xff0c;进行删除修改。 C:\Users\你的用户名\AppData\Roaming\JetBrains\PyCharm2022.3\options\jdk.table.xml直接删除解释器名称对应的一整个<jdk version"2">节点即可&#xff01; …

深度学习领域,你心目中 idea 最惊艳的论文是哪篇?

深度学习发展至今&#xff0c;共经历了三次浪潮&#xff0c;20 世纪40年代到60年代深度学习的雏形出现在控制论(cybernetics)中&#xff0c;20 世纪 80 年代 到 90 年代深度学习表现为 联结主义(connectionism)&#xff0c;直到 2006 年&#xff0c;才真正以深度学习之名复兴。…

电气学习知识点

文章目录 NPN和PNP输出 NPN和PNP输出 NPN和PNP&#xff08;两种不同类型的三极管&#xff09;都是集电极输出。&#xff08;集电极开路输出&#xff09; 下图b:基极、c集电极、e发射极 NPN示意图&#xff08;集电极连接负载 — 正方形&#xff09; NPN的电流流向是从集电极…

电子物证的数字化时代:龙信科技引领取证技术革新

文章关键词&#xff1a;电子物证、手机取证、云取证、介质取证、电子数据取证 在信息技术飞速发展的今天&#xff0c;电子物证在司法领域扮演着越来越重要的角色。电子物证是指以存储于介质载体中的电磁记录或光电记录对案件事实起证明作用的电子信息数据及其附属物。与传统物…