Python 基于Dlib和OpenCV实现人脸融合算法+代码

该代码实现了一个基于Dlib和OpenCV的人脸融合工具FaceMerger。主要功能包括:1) 使用Dlib检测68个人脸特征点;2) 通过三角剖分和仿射变换将源人脸特征点映射到目标人脸;3) 采用泊松融合(seamlessClone)实现自然过渡。核心步骤为:提取特征点→计算凸包→三角剖分→逐三角形变形→泊松融合。最终输出将源人脸特征区域无缝融合到目标人脸上的结果。该算法适用于需要保持目标人脸整体结构同时融合源人脸特征的场景,如人脸编辑、特效制作等应用。

python 复制代码
import cv2
import numpy as np
import dlib

class FaceMerger:
    def __init__(self, predictor_path="shape_predictor_68_face_landmarks.dat"):
        self.detector = dlib.get_frontal_face_detector()
        self.predictor = dlib.shape_predictor(predictor_path)

    def get_landmarks(self, image):
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        faces = self.detector(gray, 1)
        if len(faces) == 0:
            raise ValueError("No face detected")
        
        shape = self.predictor(gray, faces[0])
        landmarks = np.array([(p.x, p.y) for p in shape.parts()])
        return landmarks

    def apply_affine_transform(self, 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(self, img1, img2, tri1, tri2):
        rect1 = cv2.boundingRect(np.float32([tri1]))
        rect2 = cv2.boundingRect(np.float32([tri2]))

        tri1_rect = [(p[0] - rect1[0], p[1] - rect1[1]) for p in tri1]
        tri2_rect = [(p[0] - rect2[0], p[1] - rect2[1]) for p in tri2]

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

        img1_rect = img1[rect1[1]:rect1[1] + rect1[3],
                         rect1[0]:rect1[0] + rect1[2]]
        
        size = (rect2[2], rect2[3])
        warped_rect = self.apply_affine_transform(img1_rect, tri1_rect, tri2_rect, size)
        
        img2_rect = img2[rect2[1]:rect2[1] + rect2[3],
                         rect2[0]:rect2[0] + rect2[2]]
        
        img2_rect = img2_rect * (1 - mask) + warped_rect * mask
        img2[rect2[1]:rect2[1] + rect2[3],
             rect2[0]:rect2[0] + rect2[2]] = img2_rect

    def seamless_clone(self, src, dst, mask, center):
        """泊松融合"""
        output = cv2.seamlessClone(src, dst, mask, center, cv2.NORMAL_CLONE)
        return output

    def merge_faces(self, img1, img2):
        landmarks1 = self.get_landmarks(img1)
        landmarks2 = self.get_landmarks(img2)

        # 凸包点索引(68个特征点的凸包)
        hull_indices = cv2.convexHull(landmarks2, returnPoints=False).flatten()
        hull2 = landmarks2[hull_indices]
        hull1 = landmarks1[hull_indices]

        # 三角剖分
        rect = (0, 0, img2.shape[1], img2.shape[0])
        subdiv = cv2.Subdiv2D(rect)
        for point in hull2:
            subdiv.insert((int(point[0]), int(point[1])))
        triangles = subdiv.getTriangleList()
        triangles = np.array(triangles, dtype=np.int32)

        # 创建掩码和图像副本
        mask = np.zeros(img2.shape, dtype=img2.dtype)
        img1_warped = np.copy(img2)

        # 对每个三角形进行变形
        for t in triangles:
            pt1 = (t[0], t[1])
            pt2 = (t[2], t[3])
            pt3 = (t[4], t[5])

            idx1 = np.where((hull2 == pt1).all(axis=1))[0][0]
            idx2 = np.where((hull2 == pt2).all(axis=1))[0][0]
            idx3 = np.where((hull2 == pt3).all(axis=1))[0][0]

            tri2 = [hull2[idx1], hull2[idx2], hull2[idx3]]
            tri1 = [hull1[idx1], hull1[idx2], hull1[idx3]]

            self.warp_triangle(img1, img1_warped, tri1, tri2)
            cv2.fillConvexPoly(mask, np.int32(tri2), (255, 255, 255))

        # 泊松融合
        center = (int(np.mean(hull2[:, 0])), int(np.mean(hull2[:, 1])))
        output = self.seamless_clone(img1_warped, img2, mask, center)
        return output

if __name__ == "__main__":
    merger = FaceMerger("shape_predictor_68_face_landmarks.dat")
    
    # 读取图片
    img1 = cv2.imread("6.jpg")  # 源人脸
    img2 = cv2.imread("5.jpg")  # 目标人脸
    
    # 调整图像尺寸一致(可选)
    img1 = cv2.resize(img1, (500, 500))
    img2 = cv2.resize(img2, (500, 500))
    
    # 执行融合
    result = merger.merge_faces(img1, img2)
    
    # 显示结果
    cv2.imshow("Source Face", img1)
    cv2.imshow("Target Face", img2)
    cv2.imshow("Merged Face", result)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    # 保存结果
    cv2.imwrite("merged_result.jpg", result)
相关推荐
1941s2 小时前
Google Agent Development Kit (ADK) 指南 第六章:记忆与状态管理
人工智能·python·agent·adk·google agent
no_work2 小时前
万能图像处理小助手1.1_傅里叶变化_椒盐噪声_直方图均衡等图片批量处理
图像处理·人工智能·python
Book思议-2 小时前
【数据结构实战】双向链表:在指定位置插入数据
c语言·数据结构·算法·链表
lightqjx2 小时前
【算法】前缀和
c++·算法·leetcode·前缀和
窝子面2 小时前
LeetCode练题三:链表
算法·leetcode·链表
扶摇接北海1762 小时前
洛谷:P1104 生日
算法
2401_884662102 小时前
CSDN年度技术趋势预测文章大纲
python
叶子2024222 小时前
在压力面前保持本色
python
旖-旎2 小时前
二分查找(寻找旋转排序数组中的最小值)(7)
c++·算法·二分查找·力扣