当前位置: 首页 > news >正文

《计算机视觉》—— 换脸

  • 效果如下:
    在这里插入图片描述
  • 完整代码:
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.lryc.cn/news/463259.html

相关文章:

  • 【JavaEE初阶】深入透析文件-IO关于文件内容的操作(四种文件流)
  • 复习:react 中的 refs,怎么使用,有哪些使用场景
  • Python OpenCV精讲系列 - 目标检测与识别深入理解(二十)
  • golang中的上下文
  • Navigation2 算法流程
  • OpenAI swarm+ Ollama快速构建本地多智能体服务 - 1. 服务构建教程
  • HTB:Wifinetic[WriteUP]
  • 专业学习|马尔可夫链(概念、变体以及例题)
  • RK3576 安卓SDK编译环境搭建
  • Renesas R7FA8D1BH (Cortex®-M85) 上光电编码器测速功能
  • 软件测试学习笔记丨Linux三剑客-sed
  • Vue脚手架学习 vue脚手架配置代理、插槽、Vuex使用、路由、ElementUi插件库的使用
  • 使用yml文件安装环境时,如何添加conda和pip的镜像源
  • c语言经典100例
  • 百易云资产管理运营系统 ufile.api.php SQL注入漏洞复现
  • 【分布式微服务云原生】《Redis RedLock 算法全解析:应对时钟漂移与网络分区挑战》
  • OceanBase 的写盘与传统数据库有什么不同?
  • 用Java爬虫API,轻松获取taobao商品SKU信息
  • OpenHarmony 入门——ArkUI 自定义组件内同步的装饰器@State小结(二)
  • 【Linux驱动开发】嵌入式Linux驱动开发基本步骤,字符设备开发入门,点亮LED
  • 搬砖14、Python网络编程入门
  • Transformer: Attention is All you need
  • C++:排序算法
  • 期货日内稳赢策略:双15交易法详解
  • 2024年10月第2个交易周收盘总结:怎样卖出!
  • mysql 不支持utf8mb4_0900_ai_ci
  • 第10篇:防火墙与入侵检测系统
  • Jmeter监控服务器性能
  • 通过前端UI界面创建VUE项目
  • Python网络爬虫:分析淘宝商品热度与销量[进阶深度优化]