一键AI高清换脸——基于InsightFace、CodeFormer实现高清换脸与验证换脸后效果能否通过人脸比对、人脸识别算法

这篇具有很好参考价值的文章主要介绍了一键AI高清换脸——基于InsightFace、CodeFormer实现高清换脸与验证换脸后效果能否通过人脸比对、人脸识别算法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

1、项目简介

AI换脸是指利用基于深度学习和计算机视觉来替换或合成图像或视频中的人脸。可以将一个人的脸替换为另一个人的脸,或者将一个人的表情合成到另一个人的照片或视频中。算法常常被用在娱乐目上,例如在社交媒体上创建有趣的照片或视频,也有用于电影制作、特效制作、人脸编辑工具和虚拟现实。但也有可能被滥用,用于欺骗、虚假信息传播或隐私侵犯。
随着AI换脸技术的广泛应用,这也引起很多的关注和担忧,因为它可以用于制造虚假的视频内容,可能导致社会和政治问题。AI换脸技术也会引发法律和伦理问题,包括隐私问题和身份验证问题。滥用这些技术可能导致个人的声誉受损,也可能用于欺骗和诈骗。
AI换脸技术不断发展,变得越来越先进的同时,也有研究人员和技术公司努力开发检测和防御AI换脸的方法,以应对滥用和虚假信息传播的问题。
这里结合实现了一些常用的AI换脸技术,从人脸检测到人脸关键点检测,再到AI换脸,然后使用算法进行人脸修复和超分,以便大家更好的了解AI换脸这个智能算法,只能全面的理解才能做到更好的防范。

2.项目效果

一键AI高清换脸——基于InsightFace、CodeFormer实现高清换脸与验证换脸后效果能否通过人脸比对、人脸识别算法,人脸智能算法,人工智能,算法,AI换脸,一键换脸,人脸欺骗,人脸识别,人脸验证
注:这里使用视频是Rerender_A_Video这个项目生成的视频。

3.源码与环境配置

源码地址:https://download.csdn.net/download/matt45m/88395491
模型地址:链接:https://pan.baidu.com/s/1ebvB86bvocOUdTCmAp8C8Q 提取码:3ubq
源码环境配置:

conda create -n swapface python=3.10
activate swapface
cd SwapFaceVerify
pip install -r requirements.txt

一、AI换脸预处理

1.人脸检测

做人脸相关处理工作,首先需要获取图像或者视频中的人脸以及坐标,会用于人脸检测相关的算法,人脸检测算法提供人脸位置的矩形框
。以下是一些常用的人脸检测算法:

  • Viola-Jones算法:Viola-Jones算法是一种经典的人脸检测算法,基于Haar特征和级联分类器。它具有快速的检测速度,通常用于实时应用。
  • 卷积神经网络(CNN):深度学习中的卷积神经网络在人脸检测方面取得了显著的进展。许多现代的人脸检测器,如MTCNN(多任务卷积神经网络)和SSD(单发多框检测器),使用CNN来检测人脸。
  • HOG特征和支持向量机(SVM):HOG(方向梯度直方图)特征通常与SVM分类器结合使用,用于人脸检测。这种方法在处理不同光照和尺度条件下的人脸时表现良好。
  • 深度学习模型:一些基于深度学习的人脸检测器,如YOLO(You Only Look Once)和Faster R-CNN(区域卷积神经网络),已经被广泛应用于目标检测领域,包括人脸检测。
  • 级联分类器:级联分类器是一种组合多个弱分类器的方法,以提高人脸检测的准确性。这种方法被Viola-Jones算法采用,以及其他一些基于AdaBoost的方法。
  • 3D人脸检测:除了2D人脸检测,还存在用于检测和识别3D人脸的算法,这些算法通常使用深度传感器或多视角摄像头。
    通常轮廓点检测也被称为 Face Alignment。本文的AI换脸实现就是建立在68个人脸轮廓点(Landmarks)的基础之上。而 Face Alignment 必须依赖一个人脸检测器,即 Face Detection。也就是说,本文所介绍的换脸或者其他精细化人脸操作的基础是 Face Detection + Face Alignment。但是,这两个技术并不需要我们亲自开发,dlib已经提供了效果不错、使用简便的第三方库。
    一键AI高清换脸——基于InsightFace、CodeFormer实现高清换脸与验证换脸后效果能否通过人脸比对、人脸识别算法,人脸智能算法,人工智能,算法,AI换脸,一键换脸,人脸欺骗,人脸识别,人脸验证

2. 人脸关键特征点

人脸图像中的关键特征点(face-landmark),例如眼睛、鼻子、嘴巴、脸颊等。这些特征点通常用于面部识别、表情分析、面部姿势估计等应用。以下是一些常用的人脸关键点检测算法:
Dlib:Dlib 是一个流行的 C++ 库,提供了高效的人脸关键点检测功能。它使用了一种基于 HOG 特征的级联分类器,并使用回归方法来预测关键点位置。Dlib 还提供了 Python 绑定,因此可以方便地用于 Python 环境。
OpenCV:OpenCV 是一个广泛使用的计算机视觉库,它包含了一些用于人脸关键点检测的功能。OpenCV 的面部关键点检测器通常基于级联分类器和形状模型。
Face++:Face++ 是一个商业化的人脸识别平台,提供了人脸关键点检测服务。它使用深度学习技术,包括卷积神经网络(CNN),来检测和定位面部关键点。
dlib + 预训练模型:除了 Dlib 库本身,还可以使用预训练的深度学习模型,例如基于 TensorFlow 或 PyTorch 的模型,来进行面部关键点检测。这些模型通常在大规模数据集上进行训练,能够更准确地检测面部关键点。
MediaPipe Face Detection:Google 的 MediaPipe 框架提供了一种用于实时面部关键点检测的解决方案。它使用了深度学习模型来检测人脸并估计关键点位置,可用于实时应用和移动设备上的部署。
68-Point Facial Landmarks Model:这是一个常见的面部关键点检测模型,它能够检测到脸部的 68 个关键点,包括眼睛、嘴巴、鼻子、脸颊等部位。这种模型通常使用深度学习方法构建。
一键AI高清换脸——基于InsightFace、CodeFormer实现高清换脸与验证换脸后效果能否通过人脸比对、人脸识别算法,人脸智能算法,人工智能,算法,AI换脸,一键换脸,人脸欺骗,人脸识别,人脸验证

二、InsightFace算法

1、算法简介

InsightFace算法是一种用于人脸分析和识别任务的深度学习模型,它主要侧重于人脸识别和人脸验证。InsightFace是一个用于2D和3D人脸分析的集成Python库。 InsightFace 有效地实现了各种最先进的人脸识别、人脸检测和人脸对齐算法,并针对训练和部署进行了优化。它支持一系列主干架构,包括 IResNet、RetinaNet、MobileFaceNet、InceptionResNet_v2 和 DenseNet。 除了模型之外,它还可以使用 MS1M、VGG2 和 CASIA-WebFace 等面部数据集。InsightFace算法的基本解析:
骨干网络(Backbone Networks):InsightFace使用深度卷积神经网络(CNN)作为骨干网络,用于从输入图像中提取人脸特征。通常情况下,ResNet和MobileNet等网络结构被用作骨干网络,但InsightFace也支持其他网络结构。

ArcFace损失(ArcFace Loss):InsightFace的一个显著特点是在训练过程中使用ArcFace损失函数。ArcFace损失函数旨在增强特征嵌入的区分能力,使其适用于人脸识别任务。它通过在嵌入空间中对类别之间引入边界(margin)来实现,从而更好地区分不同的身份。

有效的训练(Efficient Training):InsightFace以高效的训练过程著称,包括大规模人脸识别和数据增强等技术。这些方法有助于提高模型的性能,特别是在处理大规模数据集时。

预训练模型(Pretrained Models):InsightFace提供了预训练模型,使开发人员能够轻松开始进行人脸识别任务,而无需从头开始训练模型。这些预训练模型经过大规模的人脸数据集训练,可以用于特定应用的微调。

开源(Open Source):InsightFace是一个开源框架,这意味着开发人员可以访问其代码库,并根据自己的需求进行定制。这导致了一个繁荣的研究和开发社区,不断为其发展做出贡献。

各种应用(Various Applications):InsightFace不仅仅可以用于基本的人脸识别,还可以应用于更广泛的任务,如情感分析、年龄估计、性别分类和人脸属性识别等。

2. 算法优势

InsightFace具有许多优势,使其在人脸识别和相关任务中备受欢迎。以下是InsightFace的主要优势总结:

高精度:InsightFace以其强大的深度学习模型和ArcFace损失函数而闻名,这使得其在人脸识别和人脸验证任务中能够实现高精度的识别结果。

高效性:InsightFace采用了有效的训练技巧,包括大规模人脸识别和数据增强,这有助于提高模型的性能并减少训练时间。

预训练模型:InsightFace提供了预训练模型,使开发人员可以快速开始人脸识别项目,无需从头开始训练模型。这提高了开发效率。

灵活性:InsightFace是一个开源框架,开发人员可以根据自己的需求进行自定义。这意味着它可以适应各种人脸分析任务和应用领域。

多用途:除了基本的人脸识别和验证,InsightFace还可以用于其他多种应用,如情感分析、年龄估计、性别分类和人脸属性识别等。

大规模支持:InsightFace具备处理大规模数据集的能力,因此适用于需要大量训练数据的项目,如人脸识别在大型身份数据库中的应用。

社区支持:由于是开源项目,InsightFace有一个积极的社区,不断贡献代码、文档和改进,使其保持活跃和更新。

强调隐私和安全:InsightFace的使用者可以自己加强安全和隐私措施,以确保合规性和数据保护。

3.算法概述

InsightFace提供用于深度识别的训练数据,网络设置和损失设计。 训练数据包括标准化的 MS1M,VGG2 和 CASIA-Webface 数据集,这些数据集已经以 MXNet 二进制格式打包。 网络主干包括 ResNet,MobilefaceNet,MobileNet,InceptionResNet_v2,DenseNet,DPN。 损失函数包括 Softmax,SphereFace,CosineFace,ArcFace 和 Triplet(Euclidean / Angular)Loss。
一键AI高清换脸——基于InsightFace、CodeFormer实现高清换脸与验证换脸后效果能否通过人脸比对、人脸识别算法,人脸智能算法,人工智能,算法,AI换脸,一键换脸,人脸欺骗,人脸识别,人脸验证
InsightFace的方法 ArcFace 最初在 arXiv 技术报告中描述。 通过使用此存储库,可以通过单个模型简单地实现 LFW 99.80%+ 和 Megaface 98%+。

3. 使用InsightFace实现人脸属性分析

import os
import  cv2
import insightface
from sklearn import  preprocessing
import numpy as np
import onnxruntime
from sklearn.metrics.pairwise import cosine_similarity, paired_distances
import gradio as gr

class DisposeFace:
    def __init__(self,face_db,gpu_id=0, threshold=1.24,
                 det_thresh=0.50, det_size=(640, 640)):
        self.gpu_id = gpu_id
        self.threshold = threshold
        self.det_thresh = det_thresh
        self.det_size = det_size
        self.face_db = face_db

        # 初始化模型
        providers = onnxruntime.get_available_providers()
        self.face_model = insightface.app.FaceAnalysis(
            name="buffalo_l", root="checkpoints", allowed_modules=None, providers=providers)
        self.face_model.prepare(ctx_id=self.gpu_id, det_thresh=self.det_thresh, det_size=self.det_size)

        # 人脸库的人脸特征
        self.faces_embedding = list()
        # # 加载人脸库中的人脸
        self.load_db_faces(self.face_db)

    def load_model(self):
        return self.face_model

    def load_db_faces(self,face_db_path):
        if not os.path.exists(face_db_path):
            os.makedirs(face_db_path) #创建人脸数据库

        for root,dirs,files in os.walk(face_db_path):
            for file in files:
                input_image = cv2.imdecode(np.fromfile(os.path.join(root, file), dtype=np.uint8), 1)
                user_name = file.split(".")[0]
                face = self.face_model.get(input_image)[0]
                embedding = np.array(face.embedding).reshape((1, -1))
                embedding = preprocessing.normalize(embedding)
                self.faces_embedding.append({"user_name": user_name,"feature": embedding})

    def detect_face(self,cv_src):
        faces = self.face_model.get(cv_src)
        faces_results = list()

        for face in faces:
            result = dict()

            #获取人脸属性
            result["bbox"] = np.array(face.bbox).astype(np.int32).tolist()
            result["kps"] = np.array(face.kps).astype(np.int32).tolist()
            result["landmark_3d_68"] = np.array(face.landmark_3d_68).astype(np.int32).tolist()
            result["landmark_2d_106"] = np.array(face.landmark_2d_106).astype(np.int32).tolist()
            result["pose"] = np.array(face.pose).astype(np.int32).tolist()
            result["age"] = face.age

            gender = 'man'
            if face.gender == 0:
                gender = 'female'
            result["gender"] = gender

            #人脸识别
            embedding = np.array(face.embedding).reshape((1, -1))
            embedding = preprocessing.normalize(embedding)
            result["embedding"] = embedding
            faces_results.append(result)

        return faces_results
    @staticmethod
    def feature_compare(feature1, feature2, threshold):
        diff = np.subtract(feature1, feature2)
        dist = np.sum(np.square(diff), 1)
        if dist < threshold:
            return True
        else:
            return False

    def face_recognition(self,cv_src):
        faces = self.face_model.get(cv_src)
        face_results = list()

        for face in faces:
            # 开始人脸识别
            embedding = np.array(face.embedding).reshape((1, -1))
            embedding = preprocessing.normalize(embedding)

            user_name = "unknown"
            for com_face in self.faces_embedding:
                result = self.feature_compare(embedding,com_face["feature"],self.threshold)

                if result:
                    user_name = com_face["user_name"]

            face_results.append(user_name)

        return face_results

    def recognition(self,cv_face1,cv_face2):
        faces1 = self.face_model.get(cv_face1)
        faces2 = self.face_model.get(cv_face2)

        if len(faces1) != 1 and len(faces2) != 1:
            return "No face detected or multiple faces detected!"

        embedding1 = np.array(faces1[0].embedding).reshape((1, -1))
        embedding1 = preprocessing.normalize(embedding1)

        embedding2 = np.array(faces2[0].embedding).reshape((1, -1))
        embedding2 = preprocessing.normalize(embedding2)

        return self.feature_compare(embedding1,embedding2,self.threshold)
    def face_similarity(self,cv_face1,cv_face2):
        faces1 = self.face_model.get(cv_face1)
        faces2 = self.face_model.get(cv_face2)

        if len(faces1) != 1 and len(faces2) != 1:
            return "No face detected or multiple faces detected!"

        embedding1 = np.array(faces1[0].embedding).reshape((1, -1))
        embedding1 = preprocessing.normalize(embedding1)

        embedding2 = np.array(faces2[0].embedding).reshape((1, -1))
        embedding2 = preprocessing.normalize(embedding2)

        return cosine_similarity(embedding1,embedding2)

    #注册人脸
    def face_register(self,cv_face,user_name):
        faces = self.face_model.get(cv_face)

        if len(faces) != 1:
            return "No face detected or multiple faces detected!"

        embedding = np.array(faces[0].embedding).reshape((1, -1))
        embedding = preprocessing.normalize(embedding)

        is_exits = False

        for com_face in self.faces_embedding:
            r = self.feature_compare(embedding, com_face["feature"], self.threshold)
            if r:
                is_exits = True
        if is_exits:
            return "The user already exists. You do not need to re-register the user!"

        cv2.imencode('.png', cv_face)[1].tofile(os.path.join(self.face_db, '%s.png' % user_name))
        self.faces_embedding.append({"user_name": user_name,"feature": embedding})

        return "Register face success!"

face_dis = DisposeFace("face_database")

def get_face_feature(image):
    # image = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
    img_3d_point = image.copy()
    img_2d_point = image.copy()

    results = face_dis.detect_face(image)
    for result in results:
        color = list(np.random.choice(range(256), size=3))
        cv2.rectangle(image, (result["bbox"][0], result["bbox"][1]), (result["bbox"][2], result["bbox"][3]),
                      (int(color[0]), int(color[1]), int(color[2])))

        age = 'age:{}'.format(result["age"])
        gender = 'gender:{}'.format(result["gender"])

        cv2.putText(image, age, (result["bbox"][0], result["bbox"][1]), cv2.FONT_HERSHEY_COMPLEX, 0.6, (100, 200, 200), 1)
        cv2.putText(image, gender, (result["bbox"][0], result["bbox"][1] - 20), cv2.FONT_HERSHEY_COMPLEX, 0.6,
                    (100, 200, 200), 1)

        for p in result["kps"]:
            cv2.circle(image, (int(p[0]), int(p[1])), 0, (255, 0, 255), 4)

        for p3 in result["landmark_3d_68"]:
            cv2.circle(img_3d_point, (int(p3[0]), int(p3[1])), 0, (0, 255, 255), 4)

        for p2 in result["landmark_2d_106"]:
            cv2.circle(img_2d_point, (int(p2[0]), int(p2[1])), 0, (255, 255, 0), 4)

    return image,img_2d_point,img_3d_point


input = gr.Image(label="请输入人脸图像")
output_1 = gr.Image(label="年龄与性别")
output_2 = gr.Image(label="2D关键点")
output_3 = gr.Image(label="3D关键点")

demo = gr.Interface(fn=get_face_feature,inputs=input,outputs=[output_1,output_2,output_3])
demo.launch()

显示结果:
一键AI高清换脸——基于InsightFace、CodeFormer实现高清换脸与验证换脸后效果能否通过人脸比对、人脸识别算法,人脸智能算法,人工智能,算法,AI换脸,一键换脸,人脸欺骗,人脸识别,人脸验证
注:人脸是使用Stable Diffusion的模型生成的。

三、InsightFace换脸

输入的人脸可是单张或者多张,然后人脸框的X坐标顺序进行替换人脸:

class InsightFaceSwap():
    def __init__(self,in_model_path:str,code_former_index:int,codeformer_model_path:str,face_analyser):
        self.model_path = in_model_path
        self.codeformer_model_path = codeformer_model_path
        self.code_former_index = code_former_index
        self.item_dir = os.path.abspath(os.path.dirname(__file__))
        self.face_analyser = face_analyser

        # providers = onnxruntime.get_available_providers()
        # self.face_analyser = insightface.app.FaceAnalysis(
        #     name="buffalo_l", root=os.path.join(item_path,"checkpoints"),allowed_modules=None,providers=providers)
        # self.face_analyser.prepare(ctx_id=self.gpu_id, det_thresh=self.det_thresh, det_size=self.det_size)

        model_path = os.path.join(item_path, in_model_path)
        self.face_swapper = insightface.model_zoo.get_model(model_path)

        if code_former_index == 1:
            check_ckpts()
            self.upsampler = set_realesrgan()

            self.device = torch.device("mps" if torch.backends.mps.is_available() else "cuda" if torch.cuda.is_available() else "cpu")

            self.codeformer_net = ARCH_REGISTRY.get("CodeFormer")(dim_embd=512,codebook_size=1024,n_head=8,n_layers=9,
                                                             connect_list=["32", "64", "128", "256"],).to(self.device)
            checkpoint = torch.load(codeformer_model_path)["params_ema"]
            self.codeformer_net.load_state_dict(checkpoint)
            self.codeformer_net.eval()

    def get_many_faces(self,frame:np.ndarray):
        try:
            face = self.face_analyser.get(frame)
            return sorted(face, key=lambda x: x.bbox[0])
        except IndexError:
            return None

    ##target_indexes - 以逗号分隔的目标图像中要交换的面部索引列表(从左到右),从0开始(-1交换目标图像中的所有面部)。
    ##source_indexes - 以逗号分隔的源图像中要使用的面部索引列表(从左到右),从0开始(-1使用源图像中的所有面部)。
    def process(self,face_imgs,src_img,source_indexes,target_indexes):
        target_img = cv2.cvtColor(np.array(src_img), cv2.COLOR_RGB2BGR)
        target_faces = self.get_many_faces(target_img)

        num_target_faces = len(target_faces)
        num_source_images = len(face_imgs)

        ## 要转换的图像中包括人脸
        if target_faces is not None:
            temp_frame = copy.deepcopy(target_img)

            if isinstance(face_imgs, list) and num_source_images == num_target_faces:
                print("Replacing faces in target image from the left to the right by order")
                for i in range(num_target_faces):
                    source_faces = self.get_many_faces(cv2.cvtColor(np.array(face_imgs[i]), cv2.COLOR_RGB2BGR))
                    source_index = i
                    target_index = i

                    if source_faces is None:
                        raise Exception("No source faces found!")

                    temp_frame = self.swap_face(source_faces,target_faces,source_index,target_index,temp_frame)
            elif num_source_images == 1:
                # detect source faces that will be replaced into the target image
                source_faces = self.get_many_faces(cv2.cvtColor(np.array(face_imgs[0]), cv2.COLOR_RGB2BGR))
                num_source_faces = len(source_faces)

                if source_faces is None:
                    raise Exception("No source faces found!")

                if target_indexes == "-1":
                    if num_source_faces == 1:
                        # print("Replacing all faces in target image with the same face from the source image")
                        num_iterations = num_target_faces
                    elif num_source_faces < num_target_faces:
                        # print("There are less faces in the source image than the target image, replacing as many as we can")
                        num_iterations = num_source_faces
                    elif num_target_faces < num_source_faces:
                        # print("There are less faces in the target image than the source image, replacing as many as we can")
                        num_iterations = num_target_faces
                    else:
                        # print("Replacing all faces in the target image with the faces from the source image")
                        num_iterations = num_target_faces

                    for i in range(num_iterations):
                        source_index = 0 if num_source_faces == 1 else i
                        target_index = i

                        temp_frame = self.swap_face(source_faces,target_faces,source_index,target_index,temp_frame)
                else:
                    # print("Replacing specific face(s) in the target image with specific face(s) from the source image")
                    if source_indexes == "-1":
                        source_indexes = ','.join(map(lambda x: str(x), range(num_source_faces)))

                    if target_indexes == "-1":
                        target_indexes = ','.join(map(lambda x: str(x), range(num_target_faces)))

                    source_indexes = source_indexes.split(',')
                    target_indexes = target_indexes.split(',')
                    num_source_faces_to_swap = len(source_indexes)
                    num_target_faces_to_swap = len(target_indexes)

                    if num_source_faces_to_swap > num_source_faces:
                        raise Exception(
                            "Number of source indexes is greater than the number of faces in the source image")

                    if num_target_faces_to_swap > num_target_faces:
                        raise Exception(
                            "Number of target indexes is greater than the number of faces in the target image")

                    if num_source_faces_to_swap > num_target_faces_to_swap:
                        num_iterations = num_source_faces_to_swap
                    else:
                        num_iterations = num_target_faces_to_swap

                    if num_source_faces_to_swap == num_target_faces_to_swap:
                        for index in range(num_iterations):
                            source_index = int(source_indexes[index])
                            target_index = int(target_indexes[index])

                            if source_index > num_source_faces - 1:
                                raise ValueError(
                                    f"Source index {source_index} is higher than the number of faces in the source image")

                            if target_index > num_target_faces - 1:
                                raise ValueError(
                                    f"Target index {target_index} is higher than the number of faces in the target image")

                            temp_frame = self.swap_face(source_faces,target_faces,source_index,target_index,temp_frame)
            else:
                raise Exception("Unsupported face configuration")
            result = temp_frame

        else:
            print("No target faces found!")

        if self.code_former_index == 1:
            cf_result = face_restoration(result,True,
                                            True,1,0.5,
                                            self.upsampler,
                                            self.codeformer_net,
                                            self.device)

            cf_im_result = Image.fromarray(cf_result)
            dis_result = Image.fromarray(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))

        else:
            cf_im_result = Image.fromarray(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
            dis_result = cf_im_result

        return dis_result,cf_im_result

    def process_video(self, face_imgs, input_video_path, output_video_path,source_indexes, target_indexes):
        cap = cv2.VideoCapture(input_video_path)
        frame_width = int(cap.get(3))
        frame_height = int(cap.get(4))

        fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
        out = cv2.VideoWriter(output_video_path, fourcc, 25, (frame_width, frame_height))

        while(True):
            ret,frame = cap.read()
            if ret == True:
                image = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
                result_image = self.process(face_imgs,image,source_indexes,target_indexes)
                img = cv2.cvtColor(np.asarray(result_image), cv2.COLOR_RGB2BGR)
                out.write(img)
            else:
                break

        cap.release()
        out.release()

    def swap_face(self,source_faces,target_faces,source_index,target_index,temp_frame):
        source_face = source_faces[source_index]
        target_face = target_faces[target_index]

        return self.face_swapper.get(temp_frame, target_face, source_face, paste_back=True)

    def process_img(self,face_imgs,src_img,output_path,source_indexes,target_indexes):
        img = self.process(face_imgs,src_img,source_indexes,target_indexes)

        img.save(output_path)

    def codeformer_video(self,input_video_path,output_video_path):
        cap = cv2.VideoCapture(input_video_path)
        frame_width = int(cap.get(3))
        frame_height = int(cap.get(4))

        fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
        out = cv2.VideoWriter(output_video_path, fourcc, 25, (frame_width, frame_height))

        while (True):
            ret, frame = cap.read()
            if ret == True:
                # image = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
                cf_result = face_restoration(frame, True,
                                             True, 1, 0.5,
                                             self.upsampler,
                                             self.codeformer_net,
                                             self.device)
                img = cv2.cvtColor(cf_result, cv2.COLOR_RGB2BGR)
                out.write(img)
            else:
                break

        cap.release()
        out.release()

从换完脸之后效果看,所以输出的换脸效果与正常人脸图片对比会有严重的割裂感,这里由于输入的像素值大小在卷积时默认为128 * 128, 为了改进这个效果,这里可以采用codeFormer进行人脸增强,使其输出的图片正常化。
一键AI高清换脸——基于InsightFace、CodeFormer实现高清换脸与验证换脸后效果能否通过人脸比对、人脸识别算法,人脸智能算法,人工智能,算法,AI换脸,一键换脸,人脸欺骗,人脸识别,人脸验证
一键AI高清换脸——基于InsightFace、CodeFormer实现高清换脸与验证换脸后效果能否通过人脸比对、人脸识别算法,人脸智能算法,人工智能,算法,AI换脸,一键换脸,人脸欺骗,人脸识别,人脸验证
注:人脸是使用Stable Diffusion的模型生成的。

四、CodeFormer人脸修复算法

1.算法概述

CodeFormer是一个基于Transformer的预测网络,它能够有效地对低质量人脸图像进行全局组成和上下文建模,以实现编码预测。即使在输入信息严重缺失的情况下,该网络也能够生成与目标人脸极为接近的自然人脸图像。此外,为了增强对不同类型退化的适应性,还引入了一个可控的特征转换模块,允许在图像保真度和质量之间进行灵活的权衡。
一键AI高清换脸——基于InsightFace、CodeFormer实现高清换脸与验证换脸后效果能否通过人脸比对、人脸识别算法,人脸智能算法,人工智能,算法,AI换脸,一键换脸,人脸欺骗,人脸识别,人脸验证

由于使用了带有丰富先验信息的代码簿和整体网络的全局建模能力,CodeFormer 在图像质量和保真度方面一直优于最先进的技术,展现出卓越的退化鲁棒性。最后,通过广泛的合成和真实世界数据集实验结果,充分验证了算法的有效性。
低清图像(LQ)和潜在高清图像(HQ)之间存在多对多的映射关系,如下图所示。这种多解的映射会在网络学习过程中引发困惑,导致难以获得高质量的输出。特别是在输入信息严重退化的情况下,这种适应性问题会更加显著。其中一个挑战是如何降低这种映射的不确定性。
CodeForme首先引入了VQGAN的离散码本空间,以解决前述的两个问题(1和2)。这个有限且离散的映射空间显著减少了复原任务映射的不稳定性(1)。通过VQGAN的自重建训练,码本先验保留了丰富的高清人脸纹理信息,有助于在复原任务中填充真实的人脸纹理细节(2)。
如下图所示,与连续先验空间(d、e)相比,离散码本空间(f、g)能够生成更高质量的结果,消除了伪影,同时保持了面部轮廓的完整性,并呈现出更加真实和精细的纹理。
一键AI高清换脸——基于InsightFace、CodeFormer实现高清换脸与验证换脸后效果能否通过人脸比对、人脸识别算法,人脸智能算法,人工智能,算法,AI换脸,一键换脸,人脸欺骗,人脸识别,人脸验证

2.源码与环境部署

我这里测试部署的系统win 10, cuda 11.8,cudnn 8.5,GPU是RTX 3060, 8G显存,使用conda创建虚拟环境。

环境安装:

git clone https://github.com/sczhou/CodeFormer
cd CodeFormer
conda create -n codeformer python=3.8 -y
conda activate codeformer

单独安装pytorch,再安装环境:

conda install pytorch2.0.0 torchvision0.15.0 torchaudio==2.0.0 pytorch-cuda=11.8 -c pytorch -c nvidia
pip install -r requirements.txt
python basicsr/setup.py develop
conda install -c conda-forge dlib

测试代码:

import os
import cv2
import torch
from torchvision.transforms.functional import normalize
from PIL import Image
from basicsr.utils import img2tensor, tensor2img
from basicsr.utils.download_util import load_file_from_url
from facelib.utils.face_restoration_helper import FaceRestoreHelper
from facelib.utils.misc import is_gray
from basicsr.archs.rrdbnet_arch import RRDBNet
from basicsr.utils.realesrgan_utils import RealESRGANer
import gradio as gr
from basicsr.utils.registry import ARCH_REGISTRY
import numpy as np
import sys

item_path = os.path.abspath(os.path.dirname(__file__))

cf_path = "./CodeFormer"
cf_dir = os.path.join(item_path, cf_path)
sys.path.append(cf_dir)

def check_ckpts():
    pretrain_model_url = {
        'codeformer': 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/codeformer.pth',
        'detection': 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/detection_Resnet50_Final.pth',
        'parsing': 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/parsing_parsenet.pth',
        'realesrgan': 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/RealESRGAN_x2plus.pth'
    }

    # download weights
    cf_model_path = 'checkpoints/codeformer.pth'
    cf_model_dir = os.path.join(item_path, cf_model_path)

    dr_model_path = 'checkpoints/detection_Resnet50_Final.pth'
    dr_model_dir = os.path.join(item_path, dr_model_path)

    pp_model_path = 'checkpoints/parsing_parsenet.pth'
    pp_model_dir = os.path.join(item_path, pp_model_path)

    re_model_path = 'checkpoints/RealESRGAN_x2plus.pth'
    re_model_dir = os.path.join(item_path, re_model_path)

    if not os.path.exists(cf_model_dir):
        load_file_from_url(url=pretrain_model_url['codeformer'], model_dir=os.path.join(item_path, '/checkpoints'), progress=True, file_name=None)
    if not os.path.exists(dr_model_dir):
        load_file_from_url(url=pretrain_model_url['detection'], model_dir=os.path.join(item_path, '/checkpoints'), progress=True, file_name=None)
    if not os.path.exists(pp_model_dir):
        load_file_from_url(url=pretrain_model_url['parsing'], model_dir=os.path.join(item_path, '/checkpoints'), progress=True, file_name=None)
    if not os.path.exists(re_model_dir):
        load_file_from_url(url=pretrain_model_url['realesrgan'], model_dir=os.path.join(item_path, '/checkpoints'), progress=True, file_name=None)
    
    
# set enhancer with RealESRGAN
def set_realesrgan():
    half = True if torch.cuda.is_available() else False
    model = RRDBNet(
        num_in_ch=3,
        num_out_ch=3,
        num_feat=64,
        num_block=23,
        num_grow_ch=32,
        scale=2,
    )

    re_model_path = 'checkpoints/RealESRGAN_x2plus.pth'
    re_model_dir = os.path.join(item_path, re_model_path)

    upsampler = RealESRGANer(
        scale=2,
        model_path= re_model_dir,
        model=model,
        tile=400,
        tile_pad=40,
        pre_pad=0,
        half=half,
    )
    return upsampler


def face_restoration(img, background_enhance, face_upsample, upscale, codeformer_fidelity, upsampler, codeformer_net, device):
    """Run a single prediction on the model"""
    try: # global try
        # take the default setting for the demo
        has_aligned = False
        only_center_face = False
        draw_box = False
        detection_model = "retinaface_resnet50"

        background_enhance = background_enhance if background_enhance is not None else True
        face_upsample = face_upsample if face_upsample is not None else True
        upscale = upscale if (upscale is not None and upscale > 0) else 2

        upscale = int(upscale) # convert type to int
        if upscale > 4: # avoid memory exceeded due to too large upscale
            upscale = 4 
        if upscale > 2 and max(img.shape[:2])>1000: # avoid memory exceeded due to too large img resolution
            upscale = 2 
        if max(img.shape[:2]) > 1500: # avoid memory exceeded due to too large img resolution
            upscale = 1
            background_enhance = False
            face_upsample = False

        face_helper = FaceRestoreHelper(
            upscale,
            face_size=512,
            crop_ratio=(1, 1),
            det_model=detection_model,
            save_ext="png",
            use_parse=True,
        )
        bg_upsampler = upsampler if background_enhance else None
        face_upsampler = upsampler if face_upsample else None

        if has_aligned:
            # the input faces are already cropped and aligned
            img = cv2.resize(img, (512, 512), interpolation=cv2.INTER_LINEAR)
            face_helper.is_gray = is_gray(img, threshold=5)
            face_helper.cropped_faces = [img]
        else:
            face_helper.read_image(img)
            # get face landmarks for each face
            num_det_faces = face_helper.get_face_landmarks_5(
            only_center_face=only_center_face, resize=640, eye_dist_threshold=5
            )
            # align and warp each face
            face_helper.align_warp_face()

        # face restoration for each cropped face
        for idx, cropped_face in enumerate(face_helper.cropped_faces):
            # prepare data
            cropped_face_t = img2tensor(
                cropped_face / 255.0, bgr2rgb=True, float32=True
            )
            normalize(cropped_face_t, (0.5, 0.5, 0.5), (0.5, 0.5, 0.5), inplace=True)
            cropped_face_t = cropped_face_t.unsqueeze(0).to(device)

            try:
                with torch.no_grad():
                    output = codeformer_net(
                        cropped_face_t, w=codeformer_fidelity, adain=True
                    )[0]
                    restored_face = tensor2img(output, rgb2bgr=True, min_max=(-1, 1))
                del output
                torch.cuda.empty_cache()
            except RuntimeError as error:
                print(f"Failed inference for CodeFormer: {error}")
                restored_face = tensor2img(
                    cropped_face_t, rgb2bgr=True, min_max=(-1, 1)
                )

            restored_face = restored_face.astype("uint8")
            face_helper.add_restored_face(restored_face)

        # paste_back
        if not has_aligned:
            # upsample the background
            if bg_upsampler is not None:
                # Now only support RealESRGAN for upsampling background
                bg_img = bg_upsampler.enhance(img, outscale=upscale)[0]
            else:
                bg_img = None
            face_helper.get_inverse_affine(None)
            # paste each restored face to the input image
            if face_upsample and face_upsampler is not None:
                restored_img = face_helper.paste_faces_to_input_image(
                    upsample_img=bg_img,
                    draw_box=draw_box,
                    face_upsampler=face_upsampler,
                )
            else:
                restored_img = face_helper.paste_faces_to_input_image(
                    upsample_img=bg_img, draw_box=draw_box
                )

        restored_img = cv2.cvtColor(restored_img, cv2.COLOR_BGR2RGB)
        return restored_img
    except Exception as error:
        print('Global exception', error)
        return None, None

codeformer_model_path = "checkpoints/codeformer.pth"
def cf_face_demo(image):
    target_img = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
    check_ckpts()
    upsampler = set_realesrgan()

    device = torch.device(
        "mps" if torch.backends.mps.is_available() else "cuda" if torch.cuda.is_available() else "cpu")

    codeformer_net = ARCH_REGISTRY.get("CodeFormer")(dim_embd=512, codebook_size=1024, n_head=8, n_layers=9,
                                                          connect_list=["32", "64", "128", "256"], ).to(device)
    checkpoint = torch.load(codeformer_model_path)["params_ema"]
    codeformer_net.load_state_dict(checkpoint)
    codeformer_net.eval()

    cf_result = face_restoration(target_img, True,
                                 True, 1, 0.5,
                                 upsampler,
                                 codeformer_net,
                                 device)

    return  cf_result

if __name__ == "__main__" :
    input = gr.Image(label="请输入人脸图像")
    output_1 = gr.Image(label="人脸超分效果")

    demo = gr.Interface(fn=cf_face_demo,inputs=input,outputs=output_1)

    demo.launch()

一键AI高清换脸——基于InsightFace、CodeFormer实现高清换脸与验证换脸后效果能否通过人脸比对、人脸识别算法,人脸智能算法,人工智能,算法,AI换脸,一键换脸,人脸欺骗,人脸识别,人脸验证
一键AI高清换脸——基于InsightFace、CodeFormer实现高清换脸与验证换脸后效果能否通过人脸比对、人脸识别算法,人脸智能算法,人工智能,算法,AI换脸,一键换脸,人脸欺骗,人脸识别,人脸验证
一键AI高清换脸——基于InsightFace、CodeFormer实现高清换脸与验证换脸后效果能否通过人脸比对、人脸识别算法,人脸智能算法,人工智能,算法,AI换脸,一键换脸,人脸欺骗,人脸识别,人脸验证

六、人脸验证与识别

1.人脸验证

Face verification(人脸验证)是指通过比对两张人脸图像,判断它们是否属于同一个人。这种技术常用于身份验证、解锁手机等场景。在进行人脸验证时,系统会对比两张图像中的人脸特征,判断它们是否匹配。如果匹配,则验证通过,认为是同一个人;如果不匹配,则验证失败,认为是不同的人。
算法将两张人脸图像的特征进行比对。这个比对过程通常使用算法来计算特征之间的相似性分数。如果相似性分数达到一定的阈值,系统就会认为两张图像属于同一个人,否则认为不是同一个人。
一般求相似度都用余弦相似度(Cosine Similarity),余弦相似度是n维空间中两个n维向量之间角度的余弦。它等于两个向量的点积(向量积)除以两个向量长度(或大小)的乘积。
一键AI高清换脸——基于InsightFace、CodeFormer实现高清换脸与验证换脸后效果能否通过人脸比对、人脸识别算法,人脸智能算法,人工智能,算法,AI换脸,一键换脸,人脸欺骗,人脸识别,人脸验证

2.人脸识别

人脸识别学用欧氏距离来衡量人脸特征两个向量之间的相似度。通常情况下,如果两个人脸特征向量的欧氏距离足够小,小于一个预定的阈值(默认是1.24),那么算法会认为这两个人脸图像属于同一个人。
一键AI高清换脸——基于InsightFace、CodeFormer实现高清换脸与验证换脸后效果能否通过人脸比对、人脸识别算法,人脸智能算法,人工智能,算法,AI换脸,一键换脸,人脸欺骗,人脸识别,人脸验证

3.测试结果

注:以下所用人脸是使用Stable Diffusion模型生成的。生成人脸底模是:Juggernaut XL这个。
一键AI高清换脸——基于InsightFace、CodeFormer实现高清换脸与验证换脸后效果能否通过人脸比对、人脸识别算法,人脸智能算法,人工智能,算法,AI换脸,一键换脸,人脸欺骗,人脸识别,人脸验证
一键AI高清换脸——基于InsightFace、CodeFormer实现高清换脸与验证换脸后效果能否通过人脸比对、人脸识别算法,人脸智能算法,人工智能,算法,AI换脸,一键换脸,人脸欺骗,人脸识别,人脸验证
一键AI高清换脸——基于InsightFace、CodeFormer实现高清换脸与验证换脸后效果能否通过人脸比对、人脸识别算法,人脸智能算法,人工智能,算法,AI换脸,一键换脸,人脸欺骗,人脸识别,人脸验证
一键AI高清换脸——基于InsightFace、CodeFormer实现高清换脸与验证换脸后效果能否通过人脸比对、人脸识别算法,人脸智能算法,人工智能,算法,AI换脸,一键换脸,人脸欺骗,人脸识别,人脸验证
一键AI高清换脸——基于InsightFace、CodeFormer实现高清换脸与验证换脸后效果能否通过人脸比对、人脸识别算法,人脸智能算法,人工智能,算法,AI换脸,一键换脸,人脸欺骗,人脸识别,人脸验证
注:人脸是使用Stable Diffusion的模型生成的。

七、视频换脸

视频换脸的效果,如果没有CodeFormer修复人脸的话,人脸周围会有虚影,效果并不是很好,下面是视频换脸的代码:

 def process_video(self, face_imgs, input_video_path, output_video_path,source_indexes, target_indexes):
        cap = cv2.VideoCapture(input_video_path)
        frame_width = int(cap.get(3))
        frame_height = int(cap.get(4))

        fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
        out = cv2.VideoWriter(output_video_path, fourcc, 25, (frame_width, frame_height))

        while(True):
            ret,frame = cap.read()
            if ret == True:
                image = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
                dis_result, _ = self.process(face_imgs,image,source_indexes,target_indexes)
                img = cv2.cvtColor(np.asarray(dis_result), cv2.COLOR_RGB2BGR)
                out.write(img)
            else:
                break

        cap.release()
        out.release()

视频效果:
一键AI高清换脸——基于InsightFace、CodeFormer实现高清换脸与验证换脸后效果能否通过人脸比对、人脸识别算法,人脸智能算法,人工智能,算法,AI换脸,一键换脸,人脸欺骗,人脸识别,人脸验证

八.总结与优化

1.优化

从运行结果对比来看,如果欧氏距离使用默认值1.24,所换的脸都能通过识别算法,但从余弦相似度的结果来看,使用CodeFormer修复人脸后,人脸的特征还是有一定的损失。在算法没有优化之前,直接换脸结果的余弦相似度都在0.8以上。但现在人脸验证的一般要求余弦相似度要在0.95以,所以如果直接现在的算法是无法通过人脸验证的算法,除非验证算法的阈值设置不合理。我试着去优化部分算法,但目前提升并不明显,如果使用一些盘外招,还是可以冲击一下95%余弦相似度,这里就不展开讲了。

2.升级

在对视频的处理方面,如果加上CodeFormer人脸修复的话,不管现在的这种方式,还是目前比较主流的单图换脸roop,处理都是很慢。如果要考虑实时性,可以按DeepFaceLive优化一个版本。文章来源地址https://www.toymoban.com/news/detail-718652.html

到了这里,关于一键AI高清换脸——基于InsightFace、CodeFormer实现高清换脸与验证换脸后效果能否通过人脸比对、人脸识别算法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 微信云开发AI短视频一键换脸小程序源码

    微信云开发AI一键视频换脸小程序源码是由极客二改后发布的,小程序增加了广告控制, 插屏广告,激励广告和原生广告,由于采用了微信云开发没有后台, 所以不需要域名和服务器也可以正常搭建使用,所有的配置都可以在app.js文件中进行修改, 目前接口还可以正常使用

    2024年02月08日
    浏览(80)
  • AI绘画SD图片高清化+面部修复+一键抠图,一些你不知道的事儿

    说到后期处理板块,大家第一印象就是图像放大,快速且高效。但是今天要讲的后期处理当中,肯定还有一些是你不知道的事儿。 # 放大算法 首先是关于放大算法,如果大家用的都是秋叶大佬的整合包的话,算法总共应该就是这些。常用的就是“R-ESRGAN 4x+”做写实图片,“

    2024年04月23日
    浏览(39)
  • 【AI绘画Stable Diffusion】高清图像放大+面部修复+一键抠图,谈谈你可能不知道的优化技巧!

    一提起后期处理,我猜你可能立马想到的就是图像放大。 今天,我要向你展示的后期处理手法,以及优化技巧。 如果你常用的是秋叶大佬的整合包,那么你对\\\"R-ESRGAN 4x+\\\"和\\\"R-ESRGAN 4x+ Anime6B\\\"应该不会陌生。 R-ESRGAN 4x+:写实图片 R-ESRGAN 4x+ Anime6B:二次元图片 然而,你是否曾在

    2024年02月16日
    浏览(58)
  • 一键快速还原修复人脸,CodeFormer 助力人脸图像修复

    今天在查资料的时候无意间看到了一个很有意思的工具,就是CodeFormer ,作者给出来的说明是用于人脸修复任务的,觉得很有意思就拿来实践了一下,这里记录分享一下。 首先对人脸修复任务进行简单的回顾总结: 人脸修复是指对损坏、有缺陷或者遮挡的人脸图像进行恢复、

    2024年02月10日
    浏览(34)
  • 基于AI绘画的换脸教学(初级)

    摸索了一段时间AI绘画,浅浅摸索到了一种基于AI绘画的换脸方法,先分享下初步简单方案。 后续会有更高效果的AI绘画换脸方法 效果展示如下   学习基础 先学会基础的AI绘画,知道图生图的用法。没玩过的小白想玩AI绘画,请移步b站找AI绘画一体包下载安装 基本原理 利用

    2024年02月02日
    浏览(40)
  • 基于GHOST-A的AI视频换脸

    paper:https://arxiv.org/pdf/2202.03046 paper还没怎么看,有时间了再回来把原理补上… 这篇文章的工作是在 FaceShifter 为 baseline 上进行的,提出了: 新的 eye-based 损失; 新的 face mask 平滑方法; 新的视频人脸交换pipeline; 新的用于减少相邻帧和SR阶段面部抖动的稳定技术。 git:http

    2024年02月12日
    浏览(38)
  • AI换脸软件有哪些?这几个工具能轻松实现换脸

    AI换脸是指利用人工智能技术将一张人脸的特征迁移到另一张人脸上,从而实现人脸转换的过程。这种技术已经被广泛应用于各个领域中,例如视频制作、视频修复、艺术创作和模拟仿真等。但是也有很多小伙伴感觉这个操作很有趣,想要将自己的照片进行AI换脸,体验一下身

    2024年02月05日
    浏览(50)
  • 如何用 ModelScope 实现 “AI 换脸” 视频

    前言         当下,视频内容火爆,带有争议性或反差大的换脸视频总能吸引人视线。虽然 AI 换脸在市面上已经流行了许久,相关制作工具或移动应用也是数不胜数。但是多数制作工具多数情况下不是会员就是收费,而且替换模板有限。以下在实战的角度,用阿里 ModelScop

    2024年02月08日
    浏览(42)
  • 基于Wav2Lip+GFPGAN的高清版AI主播

    继上一篇 基于Wav2Lip的AI主播 的内容之后很多小伙伴反应一个问题就是生成的AI人物并不是很清晰,尤其是放到编辑器里会出现明显的痕迹,因此这次带来的了 Wav2Lip+GFPGAN 高清版的内容,如果不太了解这个项目实做什么的可以来先看一下效果。该项目暂时没有中文介绍,我这

    2024年01月20日
    浏览(43)
  • AI绘画SD神器插件Inpaint Anything---简单快速实现换装换脸

    大家好,我是程序员晓晓 在AI绘画Stable DIffusion中,有一个 Inpaint Anything算法,可以实现移除、填补、替换一切内容,实现单击图像上的任何物体可以一键擦除替换任何内容、更改任意背景,这可以提高遮罩创建过程的效率和准确性,从而在节省时间和精力的同时获得更高质量

    2024年04月14日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包