Python换脸——如何让马老师打篮球

news2024/10/6 8:38:20

文章目录

    • 数据准备
    • 提取特征
    • 三角剖分
    • 仿射变换
    • 无缝克隆

简单的换脸只需要四步

  1. 提取脸部特征点
  2. 三角剖分
  3. 仿射变换
  4. 无缝克隆

数据准备

想完成这个,opencv足以胜任,首先第一步,自然是打开准备换脸的图像

import matplotlib.pyplot as plt
import cv2 as cv
im1 = cv.imread("swap_face1.jpg")
im2 = cv.imread("swap_face2.jpg")

ax = plt.subplot(1,2,1)
ax.imshow(im1)
plt.axis('off')
ax = plt.subplot(1,2,2)
ax.imshow(im2)
plt.axis('off')
plt.show()

效果如下,由于opencvmatplotlib默认的通道顺序不同,所以不必为颜色感到惊惶,而且接下来的换脸操作,也基本不涉及到颜色的问题。

在这里插入图片描述
最终效果如下

在这里插入图片描述

提取特征

接下来就开始提取脸部特征点,这里需要用到dlib库,同时还得从这dlib.net下载68点的人脸模型。

import dlib
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
gray = cv.cvtColor(im1, cv.COLOR_RGB2GRAY)
# 此为识别出的人脸方框
rect = detector(gray, 1)[0]
# 此为人脸的特征点列表
landmarks = [[p.x, p.y] for p in predictor(im1,rect).parts()]

font = cv.FONT_HERSHEY_SIMPLEX
imTest = im1*1
for i, pt in enumerate(landmarks):
    # 利用cv.circle给每个特征点画一个圈,共68个
    cv.circle(imTest, pt, 3, color=(0, 255, 0))
    # 利用cv.putText输出1-68
    cv.putText(imTest, str(i+1), pt, font, 0.5, (0, 0, 255), 1,cv.LINE_AA)

cv.imshow("ma", imTest)
cv.waitKey(0)

这样一来,就把马老师的脸部特征选出来了

在这里插入图片描述

上面画个图只是为了掩饰特征点的选择逻辑,下面对两张图片均进行特征点提取操作

gray = cv.cvtColor(im1, cv.COLOR_RGB2GRAY)
rect = detector(gray, 1)[0]
pts1 = [[p.x, p.y] for p in predictor(im1,rect).parts()]

gray = cv.cvtColor(im2, cv.COLOR_RGB2GRAY)
rect = detector(gray, 1)[0]
pts2 = [[p.x, p.y] for p in predictor(im2,rect).parts()]

三角剖分

所谓换脸,就是在脸部的区域,将一个人的五官换成另一个人的五官,现在我们已经找到了人脸的特征点,接下来要做的,就是把相应五官的位置摘选出来,然后将这个区域的人脸进行替换。

第一步,是根据特征点来寻找脸部的凸包,通俗地说,就是把边界点按照顺序连接成一个多边形,这个很简单

import numpy as np
ind1 = cv.convexHull(np.array(pts1), returnPoints=False)
ind2 = cv.convexHull(np.array(pts2), returnPoints=False)
ptsSlct1 = [pts1[i] for i in ind1.reshape(-1)]
ptsSlct2 = [pts2[i] for i in ind2.reshape(-1)]

然后把这个凸包内部分割成许多个三角形,从而让各个区域可以更加完美地一一对应,常见方法是德劳内三角剖分,首先要用到opencv中的Subdiv2D进行初始化。

def outsideRect(x, y, rect):
    flag = x < rect[0] or x > rect[2]
    return flag or y < rect[1] or y > rect[3]

def triOutRect(tri, rect):
    flag = False
    for i in range(3):
        flag |= outsideRect(tri[i*2], tri[i*2+1], rect)
    return flag

def findTri(img, points):
    rect = (0, 0, img.shape[1], img.shape[0])
    subs = cv.Subdiv2D(rect)
    for point in points:
        subs.insert(tuple(point))
    tris = []
    for tri in subs.getTriangleList():
        if triOutRect(tri, rect):
            continue
        inds = []
        for i in range(0, len(points)):
            t = np.array(tri).reshape(3,2)
            flags = np.abs(t-points[i]) < 1.0
            flags = flags[:,0] & flags[:,1]
            inds.extend([i for f in flags if f])
        if len(inds) == 3:
            tris.append(tuple(inds))
    return tris

然后调用

tris1 = findTri(im1, ptsSlct1)
tris2 = findTri(im2, ptsSlct2)

仿射变换

有了三角形还不够,接下来需要完成两个剖分区域的一一对应,即需要进行仿射变换

POLY_FILL_COLOR = (1.0, 1.0, 1.0)

# src是源图像
def affineTransform(src, triSrc, triDst, size):
    warp_mat = cv2.getAffineTransform(np.float32(triSrc), np.float32(triDst))
    dst = cv2.warpAffine(src, warp_mat, size, None, flags=cv2.INTER_LINEAR,
                         borderMode=cv2.BORDER_REFLECT_101)
    return dst


def morphRegion(tri_1, tri_2, im1, im2):
    x1, y1, w1, h1 = cv2.boundingRect(np.float32([tri_1]))
    x2, y2, w2, h2 = cv2.boundingRect(np.float32([tri_2]))
    offset1 = [((x - x1), (y - y1)) for x,y in tri_1]
    offset2 = [((x - x2), (y - y2)) for x,y in tri_1]
    mask = np.zeros((h2, w2, 3))
    cv2.fillConvexPoly(mask, np.int32(offset2), (1.0, 1.0, 1.0))
    im1_within_bounds = im1[y1:y1 + h1, x1:x1 + w1]
    size_bounds_tri_2 = (w2, h2)
    transformed_area = affineTransform(im1_within_bounds, offset1, offset2,size_bounds_tri_2)
    transformed_tri = transformed_area * mask
    x2e, y2e = x2+w2, y2+h2
    im2[y2:y2e, x2:x2e] *= (1.0, 1.0, 1.0) - mask
    im2[y2:y2e, x2:x2e] = im2[y2:y2e, x2:x2e] + transformed_tri
    return im2


def affineTrans(tris, ind1, ind2, im1, im2):
    im2_with_face1 = np.copy(im2)
    for tri in tris:
        tris1 = [ind1[pt] for pt in tri]
        tris2 = [ind2[pt] for pt in tri]
        morphRegion(tris1, tris2, im1, im2_with_face1)
    return im2_with_face1

无缝克隆

这一步主要用到opencv提供的无缝克隆函数,即seamlessClone

POLY_FILL_COLOR = (255, 255, 255)

def getMask(hull, img):
    hulls = [(pt[0], pt[1]) for pt in hull]
    mask = np.zeros(img.shape, dtype=img.dtype)
    cv.fillConvexPoly(mask, np.int32(hulls), POLY_FILL_COLOR)
    rect = cv.boundingRect(np.float32([hull]))
    center = (rect[0] + int(rect[2] / 2),
                                 rect[1] + int(rect[3] / 2))
    return mask, center

def mergeMask(hull, faceImg, img):
    mask, center = getMask(hull, img)
    return cv.seamlessClone(np.uint8(faceImg), img, mask, center, cv.NORMAL_CLONE)

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

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

相关文章

回溯算法-leetcode78 子集(java)

子集 leetcode78 子集题目描述 子集问题的解题思路代码框架子集解题代码 动态规划专题 leetcode78 子集 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode.cn/problems/subsets 题目描述 给你一个整数数组 nums &#xff0c;数组中的元…

IS220PPDAH1B 336A5026ADP14 GE Speedtronic MKVIe 燃气轮机控制

IS220PPDAH1B 336A5026ADP14 GE Speedtronic MKVIe 燃气轮机控制 IS220PPDAH1B 336A5026ADP14 GE Speedtronic MKVIe 燃气轮机控制 电机控制二次回路功能说明&#xff1a;电气柜、现场操作箱上的停止按钮能在任何状态下让电机停止运行&#xff1b;控制地点选择开关可以选择“本…

在?聊聊浏览器事件循环机制

目录 前言 同步/异步编程模型 同步 异步 JS异步模型 调用栈 任务队列 宏任务队列 微任务队列 微任务API 事件循环 队列优先级 混合队列 事件循环实现 总结 参考文章 Event-Loop可视化工具 前言 JS是单线程语言&#xff0c;在某个时间段只能执行一段代码。这…

tailwindcss 多上下文与独立分包

tailwindcss 多上下文与独立分包 你看过动漫《百兽王》吗&#xff1f;《百兽王》的主人公是五个飞行员&#xff0c;他们分别驾驶黑、红、青、黄、绿五头机器狮&#xff0c;它们平时可以单独进行作战&#xff0c;遇到强敌时&#xff0c;也能进行五狮合体&#xff0c;成为巨大机…

论文写作全攻略

【基于Citespace和vosviewer文献计量学相关论文 】 文献计量学是指用数学和统计学的方法&#xff0c;定量地分析一切知识载体的交叉科学。它是集数学、统计学、文献学为一体&#xff0c;注重量化的综合性知识体系。特别是&#xff0c;信息可视化技术手段和方法的运用&#xff0…

uniapp写出文本域,右下角并限制字数200

<view class"textarea_box"><textarea class"textarea" placeholder"请填写10字以上的问题描述&#xff0c;以便我们更好的帮助您解决问题&#xff0c;提高产品质量。" placeholder-style"font-size:28rpx" maxlength"2…

图片怎么压缩到200K以内?来试试这几种压缩方法

怎么把图片压缩到200K以内呢&#xff1f;在日常生活中&#xff0c;不管是工作还是出门游玩&#xff0c;都会使用图片&#xff0c;当这些图片的内存太大时&#xff0c;保存和发送会成为一种难题&#xff0c;有的网站甚至无法上传超过一定内存的照片&#xff0c;那么我们怎么给照…

组态王与FX5u之间EtherNet/IP无线以太网通信

在实际系统中&#xff0c;同一个车间里分布多台PLC&#xff0c;通过上位机集中控制。通常所有设备距离在几十米到上百米不等。在有通讯需求的时候&#xff0c;如果布线的话&#xff0c;工程量较大耽误工期&#xff0c;这种情况下比较适合采用无线通信方式。 本方案以组态王和2…

磨刀不误砍柴工,五款让你事半功倍的软件

有句老话这样讲&#xff0c;工欲善其事&#xff0c;必先利其器&#xff0c;好的工具可以让你工作起来事半功倍。 网页收藏夹——Pocket Pocket是一款用于保存和阅读网页的工具。它可以让你把你感兴趣的网页保存到你的账户中&#xff0c;并提供多种功能和选项来优化你的阅读体…

PHP初中英语在线考试系统的设计与实现-计算机毕设 附源码87564

PHP初中英语在线考试系统的设计与实现 摘 要 本文研究的初中英语在线考试系统主要功能模块包括&#xff1a;学生用户管理、考试信息、成绩分析、通知公告管理&#xff0c;采取面对对象的开发模式进行软件的开发和硬体的架设&#xff0c;能很好的满足实际使用的需求&#xff0c;…

【深度学习】4-2 误差反向传播法 - 简单层的实现(层的介绍)

下面把构建神经网络的“层”实现为一个类。这里所说的“层”是神经网络中功能的单位。 下面先从一些简单的层开始介绍 乘法层的实现 层的实现中有两个共通的方法(接口)forward()和backward()。 forward() 对应正向传播 backward() 对应反向传播 现在来实现乘法层。看下面代…

SpringBoot 如何使用 Servlet 容器

SpringBoot 如何使用 Servlet 容器 SpringBoot 是一个非常流行的 Java 开发框架&#xff0c;它提供了一个简单而强大的方式来创建基于 Servlet 容器的 Web 应用程序。本文将介绍 SpringBoot 中如何使用 Servlet 容器。 Servlet 容器简介 Servlet 容器是指能够运行 Servlet 和…

一文带你认识FPGA LCMXO2-7000HC-4FG484C 带你深入了解其原理及特点

莱迪思深力科 LCMXO2-7000HC-4FG484C MachXO2系列 可编程逻辑器件 (PLD) 由六个超低功耗、即时启动、非易失性 PLD 组成&#xff0c;可提供 256 至 6864 个查找表 (LUT) 的密度。MachXO2 系列 PLD 提供多种特性&#xff0c;例如嵌入式块 RAM (EBR)、分布式 RAM 和用户闪存 (UFM…

linux端口数量上限65535原因;linux服务端最大连接数量可以超过65535

概述 关于端口数量&#xff0c;大家都知道最多是65535个端口。 这个来源于标识端口号的变量是16位的&#xff0c;那么就是65536个&#xff0c;去掉0这个特殊端口&#xff0c;剩下65535个&#xff0c;所以理论上最大可用数量是65535。 但是实际中还有一些特殊端口已经定义好用…

sourceTree代码回滚

记一次惊心动魄的代码回滚记录&#xff01; 背景&#xff1a; 因为test分支进行Jenkins代码构建的时候发现文件引入的两个已安装的依赖没有找到&#xff0c;构建报错 可是我明明已经安装成功&#xff0c;并且package.json中也有了版本记录&#xff0c;可就是构建失败&#xf…

面试官:“同学,你做的这几个项目都不错。但怎么问QPS你就胡说呢?”

作者&#xff1a;小傅哥 博客&#xff1a;https://bugstack.cn 沉淀、分享、成长&#xff0c;让自己和他人都能有所收获&#xff01;&#x1f604; 这位同学&#xff0c;你比上一位面试者好多了&#xff0c;你的简历中做的几个项目都不错。既有业务项目&#xff0c;也有技术项目…

电子签名软件有哪些?10大电子签名平台盘点

目录 一、电子签名软件有哪些 1.e签宝&#xff1a;国内签名领域老大哥 2.上上签&#xff1a;开创SaaS电子签极简模式 3.法大大&#xff1a;数智化签约管理平台 4.数字认证&#xff1a;中国电子认证第一股 5.契约锁&#xff1a;主攻中大型客户无缝集成各类系统 6.安心签&…

持有NPDP产品经理证书可以加薪吗?

NPDP(New Product Development Professional)是指产品经理国际资格认证&#xff0c;由美国产品开发与管理协会&#xff08;PDMA&#xff09;所发起的唯一国际公认新产品开发专业认证。NPDP是集理论、方法与实践为一体的全方位知识体系&#xff0c;为公司组织层级进行规划、决策…

破圈丨2023年绿色积分消费返利:云联惠3.0升级版【循环购】商业模式

破圈丨2023年绿色积分消费返利&#xff1a;云联惠3.0升级版【循环购】商业模式 京东供应链商品/自营商品/供应商商品 平台上面产品超过300w款产品&#xff0c;均为京东供应链货品&#xff0c;由京东统一仓储和配送&#xff0c;从源头上面杜绝假冒伪劣产品的存在&#xff0c;然…