《计算机视觉》—— 换脸

  • 效果如下:
    在这里插入图片描述
  • 完整代码:
import cv2
import dlib
import numpy as npJAW_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)     # 填充凸包,数字在0~1之间# 单通道im构成3通道im(3,行,列),改变形状(行、列、3)适应0penCVim = np.array([im, im, im]).transpose((1, 2, 0))im = cv2.GaussianBlur(im, (25, 25), 0)  # 需要根据具体调整return im""" 求出b脸仿射变换到a脸的变换矩阵M,此处用到的算法难以理解,大家可直接跳过 """def getM(points1, points2):points1 = points1.astype(np.float64)    # int8转换为浮点数类型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       # 除标准差,计算出归一化的结果# 奇异值分解,Singular Value DecompositionU, S, Vt = np.linalg.svd(points1.T * points2)R = (U * Vt).T      # 通过U和Vt找到Rreturn np.hstack(((s2 / s1) * R, c2.T - (s2 / s1) * R * c1.T))def getKeyPoints(im):       # 获取关键点rects = detector(im, 1)     # 获取人脸方框位置shape = predictor(im, rects[0])     # 获取关键点s = np.matrix([[p.x, p.y] for p in shape.parts()])return s""" 修改b图的颜色值,与a图相同 """
def normalColor(a, b):ksize = (111, 111)      #非常大的核,去噪等运算时为11就比较大了aGauss = cv2.GaussianBlur(a, ksize, 0)     # 对a进行高斯滤波bGauss = cv2.GaussianBlur(b, ksize, 0)     # 对b进行高斯滤波weight = aGauss / bGauss        # 计算目标图像调整颜色的权重值,存在0除警告,可忽略。where_are_inf = np.isinf(weight)weight[where_are_inf] = 0return b * weighta = cv2.imread("dlrb_3.jpg")    # 换脸A图片
b = cv2.imread("zly.jpg")       # 换脸B图片detector = dlib.get_frontal_face_detector()     # 构造脸部位置检测器
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")   # 获取人脸关键点定位模型aKeyPoints = getKeyPoints(a)        # 获取A图片的68关键点
bKeyPoints = getKeyPoints(b)        # 获取B图片的68关键点bOriginal = b.copy()    # 不对原来的图片b进行破坏和修改aMask = getFaceMask(a, aKeyPoints)      # 获取图片A的人脸掩膜
cv2.imshow('aMask', aMask)
cv2.waitKey()bMask = getFaceMask(b, bKeyPoints)      # 获取图片B的人脸掩膜
cv2.imshow('bMask', bMask)
cv2.waitKey()"""求出b脸仿射变换到a脸的变换矩阵M"""
M = getM(aKeyPoints[POINTStuple], bKeyPoints[POINTStuple])"""将b的脸部(bmask)根据M仿射变换到a上"""
dsize = a.shape[:2][::-1]
# 目标输出与图像a大小一致
# 需要注意,shape是(行、列),warpAffine参数dsize是(列、行)
# 使用a.shape[:2][::-1],获取a的(列、行)# 函数warpAffine(src,M,dsize,dst=None, flags=None, borderMode=None, borderValue=None)
# src:输入图像
# M:运算矩阵,2行3列的,
# dsize:运算后矩阵的大小,也就是输出图片的尺寸
# dst:输出图像
# flags:插值方法的组合,与resize函数中的插值一样,可以查看cv2.resize
# borderMode:边界模式,BORDER_TRANSPARENT表示边界透明
# borderValue:在恒定边框的情况下使用的borderValue值;默认情况下,它是 0
bMaskWarp = cv2.warpAffine(bMask, M, dsize, borderMode=cv2.BORDER_TRANSPARENT, flags=cv2.WARP_INVERSE_MAP)
cv2.imshow("bMaskWarp", bMaskWarp)
cv2.waitKey()"""获取脸部最大值(两个脸模板香加)"""
mask = np.max([aMask, bMaskWarp], axis=0)
cv2.imshow("mask", mask)
cv2.waitKey()""" 使用仿射矩阵M,将b映射到a """
bWrap = cv2.warpAffine(b, M, dsize, borderMode=cv2.BORDER_TRANSPARENT, flags=cv2.WARP_INVERSE_MAP)
cv2.imshow("bWrap", bWrap)
cv2.waitKey()""" 求b图片的仿射到图片a的颜色值,b的颜色值改为a的颜色 """
bcolor = normalColor(a, bWrap)
cv2.imshow("bcolor", bcolor)
cv2.waitKey()""" ===========step8:换脸(mask区域用bcolor,非mask区城用a)============= """
out = a * (1.0 - mask) + bcolor * mask# =========输出原始人脸、换脸结果===============
cv2.imshow("a", a)
cv2.imshow("b", bOriginal)
cv2.imshow("out", out/255)
cv2.waitKey()
cv2.destroyAllWindows()

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

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

相关文章

力扣 中等 82.删除排序链表中的重复元素 II

文章目录 题目介绍题解 题目介绍 题解 只需在83题基础上加一个while循环即可 class Solution {public ListNode deleteDuplicates(ListNode head) {ListNode dummy new ListNode(101, head);ListNode cur dummy;while (cur.next ! null && cur.next.next ! null) {…

qt5.12.12插件机制无法加载插件问题

环境:win11 vs2015 qt5.12.12 问题描述:确保插件代码正确的情况下,无法解析插件接口(即QPluginLoader类的instance(); 返回为空)。 问题现象:1、qt5.12.12的debug下无法解析;2、release下禁…

【Linux】Anaconda下载安装配置Pytorch安装配置(保姆级)

目录 Anaconda下载 Anaconda安装 conda init conda --v Conda 配置 conda 环境创建 conda info --envs conda list Pytorch安装配置 检验安装情况 检验是否可以使用GPU Anaconda下载 可以通过两种途径完成Anaconda安装包的下载 途径一:本地windows下…

运算放大器的带宽

运算放大器(Op-Amp)的带宽是指放大器能够稳定放大信号而不发生增益衰减的最高频率范围。带宽通常定义为放大器增益下降3分贝(dB)时对应的频率,这个点也被称为-3dB点(下图中是蓝色方框圈出的点)。…

读数据工程之道:设计和构建健壮的数据系统13无服务器

1. 无服务器 1.1. 云供应商的一个大趋势是无服务器,允许开发人员和数据工程师无须在后台管理服务器即可运行应用程序 1.1.1. 无服务器快速将价值投入到其正确的用例 1.2. 无服务器真正开始流行是在2014年AWS Lambda全面投入使用…

C++ —— 类和对象

目录 介绍类和对象 一. 类和对象——类的定义 1.访问限定符 2.类域 作用操作符:: 3.对象大小 类的实例化 内存对齐规则 4.this指针 this指针会出现的问题 5.C语言结构体与C类对比 封装的本质 C类的优点 二 .类和对象——关于成员 1.类的默认成员函数 I.构造函数 构…

SpringBoot+Vue+Uniapp智能社区服务小程序系统(源码+lw+部署文档+讲解等)

项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念,提供了一套默认的配置,让开发者可以更专注于业务逻辑而不是配置文件。Spring Boot 通过自动化配置和约…

[k8s理论知识]5.docker基础(四)Dockerfile构建

容器镜像 前面我们已经介绍了容器的rootfs文件系统。在传统的手动制作roofts的过程中,需要执行以下步骤: 下载基础操作系统的用户态文件配置文件系统中的各种目录和文件手动安装依赖、配置环境 这个过程不仅繁琐且容易出错,特别是在需要创…

限制游客在wordpress某分类下阅读文章的数量

在WordPress中实现某个分类下的内容限制游客只能阅读前5篇文章,注册用户可以阅读更多文章的功能,可以通过以下步骤来完成: 1. 安装和激活插件 首先,你可以使用一个插件来简化这个过程。一个常用的插件是 “MemberPress” 或 “R…

三菱FX3U-4AD模块怎样读出模拟量数据的?

关于使用FX3U-4AD读出模拟量数据时,所需的最低限度的程序,就此进行说明。读出模拟量数据的步骤如下所示: 1、确认单元号 从左侧的特殊功能单元/模块开始,依次分配单元号0~7。连接在FX3UC-32MT-LT(-2)可编程控制器上时&#xff0c…

LeetCode 3191.使二进制数组全部等于 1 的最少操作次数 I:模拟(说是最小操作次数,其实不重复翻转就是了)

【LetMeFly】3191.使二进制数组全部等于 1 的最少操作次数 I:模拟(说是最小操作次数,其实不重复翻转就是了) 力扣题目链接:https://leetcode.cn/problems/minimum-operations-to-make-binary-array-elements-equal-to…

ubuntu24.0离线安装Ollama和纯cpu版本以及对接Spring AI

文章目录 一.官网下载 0.3.13版本二.将文件包上传至ubuntu服务器三.下载安装脚本四.剔除GPU相关下载ROCM等,纯CPU运行脚本五.ollama常用命令六. 远程测试 七.对接spring AI 一.官网下载 0.3.13版本 ollama离线安装包下载地址 二.将文件包上传至ubuntu服务器 三.下…

【openwrt-21.02】openwrt中NPT(network prefix translation)实现举例

参考链接 [OpenWrt Wiki] NAT examples IPv4 NPT 启用 IPv4 到 IPv4 网络前缀转换 cat << "EOF" > /etc/nftables.d/npt.sh LAN_PFX="192.168.1.0/24" WAN_PFX="192.168.2.0/24" . /lib/functions/network.sh network_flush_cache …

电感电容谐振原理及Matlab仿真

一、电感电容谐振原理概述 电感电容谐振&#xff08;LC谐振&#xff09;是一种电路现象&#xff0c;它发生在电感器&#xff08;L&#xff09;和电容器&#xff08;C&#xff09;通过适当的方式连接时&#xff0c;电路中电流和电压之间形成共振。在这种共振状态下&#xff0c;…

计算机组成原理与系统结构——外部存储器

笔记内容及图片整理自XJTUSE “计算机组成原理与系统结构” 课程ppt&#xff0c;仅供学习交流使用&#xff0c;谢谢。 磁盘 磁盘是一个由非磁性材料构成的圆形盘片&#xff08;称为基片&#xff09;&#xff0c;上面涂抹可磁化材料。传统的基片一直是铝制或铝合金的&#xff0…

基于SpringBoot+Vue+Uniapp汽车保养系统小程序的设计与实现

详细视频演示 请联系我获取更详细的演示视频 项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而…

linux下使用VSCODE 调试python

文章目录 一、环境准备安装VS Code&#xff1a;安装Python&#xff1a; 二、环境测试创建Python文件&#xff1a;编写测试代码运行 Linux下使用VS Code调试Python 在Linux环境中进行Python开发时&#xff0c;一个高效、直观的调试工具是必不可少的。Visual Studio Code&#xf…

2024.10月18日- Vue2组件开发(3)

Vue组件开发 一、 ref属性 如果在vue里&#xff0c;想要获取DOM对象&#xff0c;并且不想使用JS的原生语法&#xff0c;那么就可以使用ref属性。ref属性的用法&#xff1a; 1&#xff09;在HTML元素的开始标记中&#xff0c;或者在Vue子组件中的开始标记中定义&#xff0c;相…

第 5 章:vuex

1. 理解 vuex vuex 是什么&#xff1a; 概念&#xff1a;专门在 Vue 中实现集中式状态&#xff08;数据&#xff09;管理的一个 Vue 插件&#xff0c;对 vue 应用中多个组件的共享状态进行集中式的管理&#xff08;读/写&#xff09;&#xff0c;也是一种组件间通信的方式&am…

ant design vue TimePicker时间选择器不点击确认也可以设置值

文章目录 前言一、背景二、操作步骤1.复现前的准备工作&#xff08;1&#xff09;vue版本和ant design vue 版本&#xff08;2&#xff09;任意ant design vue TimePicker的demo 2.解决问题&#xff08;1&#xff09;使用change时间&#xff08;无效&#xff09;&#xff08;2&…