首页 > 其他分享 >变脸大师:基于OpenCV与Dlib的人脸换脸技术实现

变脸大师:基于OpenCV与Dlib的人脸换脸技术实现

时间:2024-09-20 09:54:57浏览次数:12  
标签:r2 cv2 OpenCV 人脸 np img2 换脸 Dlib rect

目录

简介 

重新简介

思路解析

1. 加载人脸检测器和特征点预测模型

2. 读取两张人脸图片

3. 获取人脸的特征点

4. 使用Delaunay三角剖分

5. 仿射变换三角形

6. 三角形变形并复制

7. 脸部轮廓掩模

8. 无缝克隆换脸

9. 缩放图像

10. 显示换脸结果

整体代码

效果展示

准备换脸的图

准备接收换脸的图

结果


a4697c94656a4a51a5c786ef7d6e04d1.jpeg

 

 

简介 

        能让你秒变吴彦祖(或者你的女神,随你挑)的神奇换脸程序!呀哈哈哈哈(博主本人已疯),熬夜秃头(夸张一下)换来的。

        想象一下,早上醒来,对着镜子一照,哎呀妈呀,这不是我一直梦寐以求的那张脸吗?别急着去整容医院,先试试我的换脸神器吧!只需简单几步,你就能在朋友圈里上演一场“大变活人”的好戏,保证让你的朋友们惊掉下巴,直呼内行!

        当然啦,开发这玩意儿可不是闹着玩的。我经历了无数次的代码调试、算法优化,还有那些让人头疼的bug大战。但每当看到换脸效果越来越自然,我就像看到了自己的孩子慢慢长大一样,心里那叫一个美滋滋啊!

        好啦,废话不多说,接下来就让我带你走进这个换脸世界的奇妙之旅吧!记得系好安全带,因为接下来的内容可能会让你的脑洞大开,笑到肚子疼哦!

 

呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃呃

写得出来上面的话我真的是个正常人吗

 

重新简介

        在现代的图像处理技术中,人脸识别和图像变形已经不再是遥不可及的技术。通过一些简单的算法和工具,我们可以实现很多有趣的效果,比如今天要介绍的“人脸置换”。在这篇文章中,我将向大家展示如何使用OpenCV和Dlib库实现一个有趣的换脸程序,代码不仅能识别人脸,还能通过仿射变换,将一张脸的特征平滑地融合到另一张脸上。that`s ez


f07b903419ed41648d573ff4e2127578.jpeg

思路解析

        实现了两个图像之间的“换脸”功能,使用了Dlib库的人脸检测器、特征点预测器,以及OpenCV的图像处理函数。具体的实现思路如下:

1. 加载人脸检测器和特征点预测模型

 
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('./model/shape_predictor_68_face_landmarks.dat')

 

        首先,代码加载了Dlib的正面人脸检测器detector,以及68个特征点预测模型predictor,后者会用来提取人脸的关键特征点。

2. 读取两张人脸图片

 
img1 = cv2.imread("./imgs/006.jpg")
img2 = cv2.imread("./imgs/008.jpg")

 

        接着,使用OpenCV的imread函数读取两张图像。img1是要移植脸部特征的图片,img2是脸部特征的目标图片。

3. 获取人脸的特征点

 
def get_landmarks(image):
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    faces = detector(gray)
    if len(faces) == 0:
        return None
    landmarks = predictor(gray, faces[0])
    return np.array([[p.x, p.y] for p in landmarks.parts()])

 

        这个函数将图像转换为灰度图后,通过detector检测人脸区域。如果检测到人脸,则使用predictor提取人脸的68个特征点,返回一个包含这些特征点坐标的NumPy数组。每个特征点对应面部的特定位置,如眼睛、鼻子、嘴巴等。

4. 使用Delaunay三角剖分

 
def get_triangles(landmarks):
    rect = cv2.boundingRect(np.array([landmarks]))
    subdiv = cv2.Subdiv2D(rect)
    subdiv.insert(landmarks.tolist())
    triangles = subdiv.getTriangleList()
    triangles = np.array(triangles, dtype=np.int32)
    ...

 

        该函数通过Delaunay三角剖分算法,将人脸特征点分割为多个三角形。Delaunay三角剖分可以确保生成的三角形不会产生过小的角度,这样更利于仿射变换。

5. 仿射变换三角形

 
def apply_affine_transform(src, src_tri, dst_tri, size):
    warp_mat = cv2.getAffineTransform(np.float32(src_tri), np.float32(dst_tri))
    dst = cv2.warpAffine(src, warp_mat, (size[0], size[1]), None, flags=cv2.INTER_LINEAR,
                         borderMode=cv2.BORDER_REFLECT_101)
    return dst

 

        这个函数实现了将一个三角形从源图像变换到目标图像。通过仿射变换,将src_tri中的三角形变换为dst_tri中的相应三角形,返回变换后的图像。

6. 三角形变形并复制

 
def warp_triangle(img1, img2, t1, t2):
    r1 = cv2.boundingRect(np.array([t1]))
    r2 = cv2.boundingRect(np.array([t2]))
    ...

 

  warp_triangle函数使用仿射变换将每个三角形从img1中的位置变形到img2_new_face中的对应位置。这是将源人脸区域贴到目标人脸的核心步骤。

7. 脸部轮廓掩模

 
hull2 = cv2.convexHull(np.array(landmarks2))
mask = np.zeros_like(img2[:, :, 0])
cv2.fillConvexPoly(mask, np.int32(hull2), 255)

 

        在仿射变换之后,通过convexHull构建目标人脸区域的凸包,即覆盖整个脸部的轮廓,并生成一个掩模mask用于后续的无缝克隆。

8. 无缝克隆换脸

 
seamless_img = cv2.seamlessClone(np.uint8(img2_new_face), img2, mask, center, cv2.NORMAL_CLONE)

 

  seamlessClone函数将换脸后的区域与目标图像进行无缝融合。这个函数会避免图像边界产生不自然的效果,从而使换脸看起来更加逼真。

9. 缩放图像

 
scale_factor = 0.9
dim = (int(seamless_img.shape[1] * scale_factor), int(seamless_img.shape[0] * scale_factor))
resized_img = cv2.resize(seamless_img, dim, interpolation=cv2.INTER_AREA)

 

        为了适应显示器大小(你们自己调调,分辨率高的图片就调小一点,分辨率低的就拉满吧),这里设置了一个缩放因子scale_factor(0.9),将最终生成的图像缩小到原来的90%。

10. 显示换脸结果

 
cv2.imshow("Face Swap", resized_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

 

        最后,使用imshow显示处理后的换脸结果,并等待用户按下任意键后关闭窗口。


ae9fd562949b4c1296bfe546ebc1ba32.jpeg

整体代码

import cv2
import numpy as np
import dlib

# 加载人脸检测器和特征点预测模型
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('./model/shape_predictor_68_face_landmarks.dat')

# 读取两张人脸图片
img1 = cv2.imread("./imgs/006.jpg")
img2 = cv2.imread("./imgs/002.jpg")

# 获取人脸的特征点
def get_landmarks(image):
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    faces = detector(gray)
    if len(faces) == 0:
        return None
    landmarks = predictor(gray, faces[0])
    return np.array([[p.x, p.y] for p in landmarks.parts()])

# 使用Delaunay三角剖分
def get_triangles(landmarks):
    rect = cv2.boundingRect(np.array([landmarks]))
    subdiv = cv2.Subdiv2D(rect)
    subdiv.insert(landmarks.tolist())
    triangles = subdiv.getTriangleList()
    triangles = np.array(triangles, dtype=np.int32)

    indexes = []
    for t in triangles:
        pts = []
        for i in range(3):
            for j, p in enumerate(landmarks):
                if (t[i * 2], t[i * 2 + 1]) == (p[0], p[1]):
                    pts.append(j)
        if len(pts) == 3:
            indexes.append(pts)
    return indexes

# 仿射变换三角形
def apply_affine_transform(src, src_tri, dst_tri, size):
    warp_mat = cv2.getAffineTransform(np.float32(src_tri), np.float32(dst_tri))
    dst = cv2.warpAffine(src, warp_mat, (size[0], size[1]), None, flags=cv2.INTER_LINEAR,
                         borderMode=cv2.BORDER_REFLECT_101)
    return dst

# 变形并复制
def warp_triangle(img1, img2, t1, t2):
    r1 = cv2.boundingRect(np.array([t1]))
    r2 = cv2.boundingRect(np.array([t2]))

    t1_rect = []
    t2_rect = []
    t2_rect_int = []

    for i in range(3):
        t1_rect.append(((t1[i][0] - r1[0]), (t1[i][1] - r1[1])))
        t2_rect.append(((t2[i][0] - r2[0]), (t2[i][1] - r2[1])))
        t2_rect_int.append(((t2[i][0] - r2[0]), (t2[i][1] - r2[1])))

    img1_rect = img1[r1[1]:r1[1] + r1[3], r1[0]:r1[0] + r1[2]]

    size = (r2[2], r2[3])
    img2_rect = apply_affine_transform(img1_rect, t1_rect, t2_rect, size)

    mask = np.zeros((r2[3], r2[2], 3), dtype=np.float32)
    cv2.fillConvexPoly(mask, np.int32(t2_rect_int), (1.0, 1.0, 1.0), 16, 0)

    img2_rect = img2_rect * mask
    img2[r2[1]:r2[1] + r2[3], r2[0]:r2[0] + r2[2]] = img2[r2[1]:r2[1] + r2[3], r2[0]:r2[0] + r2[2]] * (
                (1.0, 1.0, 1.0) - mask)
    img2[r2[1]:r2[1] + r2[3], r2[0]:r2[0] + r2[2]] = img2[r2[1]:r2[1] + r2[3], r2[0]:r2[0] + r2[2]] + img2_rect

# 主程序
landmarks1 = get_landmarks(img1)
landmarks2 = get_landmarks(img2)

if landmarks1 is None or landmarks2 is None:
    print("未能检测到人脸")
    exit()

triangles = get_triangles(landmarks1)

# 复制人脸区域
img2_new_face = np.zeros_like(img2)

for tri in triangles:
    t1 = [landmarks1[tri[0]], landmarks1[tri[1]], landmarks1[tri[2]]]
    t2 = [landmarks2[tri[0]], landmarks2[tri[1]], landmarks2[tri[2]]]

    warp_triangle(img1, img2_new_face, t1, t2)

# 构建脸部轮廓掩模
hull2 = cv2.convexHull(np.array(landmarks2))
mask = np.zeros_like(img2[:, :, 0])
cv2.fillConvexPoly(mask, np.int32(hull2), 255)

# 将换脸后的区域融合
r = cv2.boundingRect(np.int32(hull2))  # 使用 np.int32 类型
center = ((r[0] + int(r[2] / 2), r[1] + int(r[3] / 2)))

seamless_img = cv2.seamlessClone(np.uint8(img2_new_face), img2, mask, center, cv2.NORMAL_CLONE)

# 缩放因子
scale_factor = 0.3

# 计算新尺寸
width = int(seamless_img.shape[1] * scale_factor)
height = int(seamless_img.shape[0] * scale_factor)
dim = (width, height)

# 缩放图像
resized_img = cv2.resize(seamless_img, dim, interpolation=cv2.INTER_AREA)

# 显示换脸效果
cv2.imshow("Face Swap", resized_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

 


效果展示

准备换脸的图

2fa0e1f86bd5466e82cedad5dfc21574.png

准备接收换脸的图

3b1d8f42a33249b2ada923300e39bd6a.png

 

结果

daae93c68bc94e1eac32815920e2dde4.png

 

我正如彭于晏一样的帅气(*^▽^*)

a6635f1defde40d1afc0cd7113ff9fd8.jpeg

 

 

 

 

 

标签:r2,cv2,OpenCV,人脸,np,img2,换脸,Dlib,rect
From: https://blog.csdn.net/DDDDWJDDDD/article/details/142369782

相关文章

  • OpenCv(一)
    计算机视觉和机器视觉的区别计算机视觉(ComputerVision)和机器视觉(MachineVision)是两个密切相关但又有区别的领域。两者在应用、技术和目标上都有所不同。**计算机视觉:**主要是研究如何使计算机能够理解和处理图像和视频数据。其目标是从视觉数据中提取有用的信息,实现图像......
  • OpenCV(cv::Sobel())
    目录1.函数定义2.工作原理2.1Sobel核2.2计算过程(1)x方向的Sobel卷积计算(2)y方向的Sobel卷积计算(3)合并x和y方向的梯度2.3示例3.示例4.使用场景总结cv::Sobel()是OpenCV中用于计算图像的梯度(边缘)的常用函数之一。它实现了Sobel滤波器,这是一种常见......
  • OpenCV(cv::magnitude())
    目录1.函数定义2.使用场景3.示例4.注意事项cv::magnitude()是OpenCV中用于计算向量的大小(模)的函数。它可以处理二维向量的模,也可以用于计算图像中每个像素点的梯度大小,通常在处理图像梯度或傅里叶变换时使用。1.函数定义voidcv::magnitude(InputArrayx,......
  • 护目镜佩戴检测系统 Opencv
    护目镜佩戴检测系统利用摄像头和图像识别技术,护目镜佩戴检测系统实时监测工人的护目镜佩戴情况,护目镜佩戴检测系统通过拍摄工人的面部图像,并使用算法分析图像中的眼睛和护目镜位置,判断是否正确佩戴护目镜。护目镜佩戴检测系统能够实时监测工人的护目镜佩戴情况,护目镜佩戴检测系统及......
  • OpenCV_图像旋转超详细讲解
    图像转置transpose(src, dst);transpose()可以实现像素下标的x和y轴坐标进行对调:dst(i,j)=src(j,i),接口形式transpose(InputArraysrc,//输入图像OutputArraydst,//输出)图像翻转flip(src,dst,1);flip()函数可以实现对图像的水平翻转、垂直翻转和双向......
  • OpenCV Python 深度指南
    OpenCV(OpenSourceComputerVisionLibrary)是一个开源的计算机视觉库,它包含了大量的图像处理和机器视觉算法。OpenCV支持多种编程语言,包括C++和Python,其中Python接口因其易用性和灵活性而受到广泛欢迎。本指南将覆盖以下几个方面:OpenCV简介OpenCV安装与配置图像基础视频......
  • Python OpenCV精讲系列 - 高级图像处理技术(七)
    ......
  • 周也带你进阶OpenCV (1)--采样、直方图即均衡化、掩膜
    文章目录OpenCV高阶操作一、上、下采样1.上采样2.下采样3.恢复原图二、直方图1.plt.hist()绘图2.cv2.calcHist()绘图三、mask掩膜1.原图2.创建黑白图像3.掩膜4.绘制曲线图四、直方图均衡化1.直方图均衡化2.自适应直方图均衡化(局部直方图处理)总结......
  • OpenCV(cv::bilateralFilter())
    目录1.函数定义2.双边滤波的工作原理3.应用场景4.示例5.与其他滤波器的比较6.性能优化7.注意事项结论cv::bilateralFilter()是OpenCV中用于图像平滑处理。与传统的线性滤波器(如高斯滤波器)不同,它同时考虑空间邻近性和像素值相似性,从而保留边缘的细节。1.函数定义vo......
  • opencv-python学习笔记10-图像形态学处理
    目录一、基本概念: (1)结构元素(StructuringElement):(2)膨胀(Dilation):(3)腐蚀(Erosion):(4)开运算(Opening)(5)闭运算(Closing)(6)形态学梯度(MorphologicalGradient)(7)顶帽(Top-hat)和黑帽(Black-hat)转换(8)应用领域 二、膨胀:(1)基本概念:(2)原理:(3)方法:(4)OpenCV中的膨胀函数:(5)代码示例:(6)应用领域:(7......