(九)把一切放在一起:用深度伪造换脸

目录

将src人脸转换为dst人脸

用dst人脸交换来自src帧的人脸

视频重建:获取我们的深度伪造视频


深度伪造——使用深度学习在视频中将一个人的脸换成另一个人的脸——是当今使用人工智能的最有趣最可怕的方式之一。

虽然深度伪造可用于合法目的,但它们也可用于虚假信息。能够轻松地将某人的脸换成任何视频,我们真的可以相信我们的眼睛告诉我们的吗?政治家或演员做或说令人震惊的事情的真实视频可能根本不是真实的。

在本系列文章中,我们将展示深度伪造的工作原理,并展示如何从头开始实现它们。然后我们将看看DeepFaceLab,它是一种多合一的Tensorflow 驱动的工具,通常用于创建令人信服的深度伪造。

上一篇文章中,我们讨论了Google AI Platform以及如何在Docker容器的帮助下在那里训练模型。在本文中,我将启动一个新notebook(我在Kaggle中完成了此操作,但如果您的计算机启用了GPU,则您可以在本地完成)并获取先前训练的结果模型,使用它们交换src帧中的人脸以最终合并他们并重新创建原始视频,但这次我们将获得最终的深度伪造。

如果你在Kaggle Notebook中训练你的模型并且你打算留在这个平台上,使用它的输出作为我们将要创建的那个的输入。如果您在AI Platform中训练了模型并计划在Kaggle上工作,请像通常导入数据集一样导入它们,如果您计划在本地工作,则将模型移至Notebook目录。请记住,您的机器需要有GPU,否则在尝试加载模型时会崩溃。

就我而言,我使用最后一个notebook的输出作为我将在Kaggle中启动以结束项目的那个notebook的输入。您需要获取的一个重要元素是shape_predictor_68_face_landmarks.dat文件。在继续之前立即下载。

src人脸转换为dst人脸

在接下来的几行中,我们要做的是从src视频中提取帧,从帧中提取人脸,使用这些人脸获得转换后的dst脸,然后将它们插入到src帧中。然后我们简单地将它们链接在一起以获得深度假视频。

让我们从导入所需的库开始:

import numpy as np
import pandas as pd
import keras
import tensorflow
from tensorflow.keras.models import load_model
import gc
import matplotlib.pyplot as plt
import cv2
import os
import dlib
from IPython.display import clear_output

现在我们需要创建一些目录,我们将沿着这个notebook保存生成的图像:

!cd /kaggle/working/
!mkdir frames
!mkdir results
!mkdir transformed
!mkdir final
!ls /kaggle/working/
__notebook__.ipynb  final  frames  results  transformed

 现在,是时候提取src帧并根据它们的顺序存储它们了。为此,我们将使用升序将它们保存为特定目录中的文件名:

input_path = '/kaggle/input/presidentsdataset/presidents/trump1.mp4'
output_path = '/kaggle/working/frames/'
 
def extract_frames(input_path,output_path):
    videocapture = cv2.VideoCapture(input_path)
    success,image = videocapture.read()
    count = 0
    while success:
        cv2.imwrite(output_path+"%d.jpg" % count, image)     
        success,image = videocapture.read()
        count += 1
    print('Frames extraction has ended')
    return count
 
frames = extract_frames(input_path,output_path)

Frames extraction has ended

让我们看看一帧是什么样的:

%matplotlib inline
plt.figure()
image = cv2.imread('/kaggle/working/frames/120.jpg')
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
plt.imshow(image)
plt.show()

现在是时候从src帧中提取人脸,并使用与各自帧相同的名称保存它们。我们将像之前一样使用MTCNN库来提取人脸:

!pip install mtcnn
from mtcnn import MTCNN
 
def extract_faces(source,destination,detector):
    counter = 0
    for dirname, _, filenames in os.walk(source):
        for filename in filenames:
            try:
                image = cv2.imread(os.path.join(dirname, filename))
                image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
                detections = detector.detect_faces(image)
                x, y, width, height = detections[0]['box']
                x1,y1,x2,y2 = x-10,y+10,x-10 +width + 20,y+10+height
                face = image[y1:y2, x1:x2]
                face = cv2.resize(face, (120, 120), interpolation=cv2.INTER_LINEAR)
                plt.imsave(os.path.join(destination,filename),face)
                clear_output(wait=True)
                print("Extraction progress: "+str(counter)+"/"+str(len(filenames)-1))
            except:
                pass
            counter += 1

Extraction progress: 1701/1701

我们来看看其中一张提取的人脸:

%matplotlib inline
plt.figure()
image = cv2.imread('/kaggle/working/results/120.jpg')
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
plt.imshow(image)
plt.show()

图片:

现在我们已经提取了所有面部并将其保存在各自的目录中,让我们转换所有面部以获得它们的dst版本。请记住,这里的目标是使用来自src 脸的面部手势获取dst脸。要加载自动编码器模型,请发出以下命令:

autoencoder_a = load_model("/kaggle/input/deepfakes-model-training/autoencoder_a.hdf5")
autoencoder_b = load_model("/kaggle/input/deepfakes-model-training/autoencoder_b.hdf5")

使用autoencoder_a的编码器和autoencoder_b的解码器来变换人脸:

# LOADING THE ENCODER A
encoder_a = keras.Model(autoencoder_a.layers[1].input, autoencoder_a.layers[1].output)
# LOADING THE DECODER B
decoder_b = keras.Model(autoencoder_b.layers[2].input, autoencoder_b.layers[2].output)

现在让我们创建将转换实际人脸的函数:

def face_transform(source,destination,encoder,decoder):
    counter = 0
    for dirname, _, filenames in os.walk(source):
        for filename in filenames:
            # load the image
            try:
                image = cv2.imread(os.path.join(source, filename))
                image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
                image = image.astype('float32')
                image /= 255.0
                image = encoder.predict(np.array([image]))
                image = decoder.predict(image)
                image = cv2.normalize(image, None, alpha = 0, beta = 255, norm_type = cv2.NORM_MINMAX, dtype = cv2.CV_32F)
                image = image.astype(np.uint8)
                plt.imsave(os.path.join(destination,filename),image[0])
                counter += 1
                clear_output(wait=True)
                print("Transformation progress: "+str(counter)+"/"+str(len(filenames)))
            except:
                print('exception')
                Pass

并通过发出以下命令来运行它:

face_transform('/kaggle/working/results/','/kaggle/working/transformed',encoder_a,decoder_b)

Transformation progress: 1701/1701

让我们绘制与显示的前一张脸相对应的变换图像:

%matplotlib inline
plt.figure()
image = cv2.imread('/kaggle/working/transformed/120.jpg')
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
plt.imshow(image)
plt.show()

一旦您将转换后的dst脸保存为相应src脸的相应名称,就可以开始人脸交换了。

dst人脸交换来自src帧的人脸

有几种方法可以执行换脸操作。您可以使用自己的脚本或使用现有脚本来节省几个小时的工作。最后,您可能会得到与DIY解决方案相同的结果,因为这些算法中的大多数都基于相同的原理(Delanuay三角剖分应用于面部交换)。有三种流行的脚本,我已经研究:WuhuikaiFaceSwap SatyaFaceSwapMatthew EarlMallick faceswap

我们将使用最后一个,因为它实现了部分面部交换,这在测试期间对我们来说效果更好。根据您在面部变换过程中获得的结果,您可能会发现另一种方法更适合您,因此请尝试所有方法!现在,让我们从实际代码开始:

将建议的repo克隆到notebook/working目录:

!git clone https://github.com/matthewearl/faceswap.git

请记住,我们将使用我之前提到的shape_predictor_68_face_landmarks文件。它是dlib库用来检测包含我们帧中人脸的区域的模型。

现在我们需要对脚本进行一些修改,使其在我们的notebook中可执行。为此,请使用的python魔法命令%load ./faceswap/faceswap.py加载faceswap.py文件。

该文件将自动在该notebook单元格中打开并允许您对其进行修改。

打开文件后,查找PREDICTOR_PATH变量并将其修改为指向shape_predictor_68_face_landmarks.dat文件的变量。就我而言,我已将其修改为PREDICTOR_PATH = '../input/shape-predictor-68-face-landmarksdat/shape_predictor_68_face_landmarks.dat'

其次,我们需要修改最后一行,以便将生成的人脸交换输出图像保存到我们需要的文件夹中,并使用我们需要的名称。为此,请注释最后一行,并在其下方添加以下内容:

cv2.imwrite(sys.argv[3], output_im)

最后,要重写文件,删除出现在文件顶部注释的 python魔发命令%load ./faceswap/faceswap.py,并将其替换为%%writefile ./faceswap/faceswap.py

运行单元格,如果一切顺利,您应该会收到一条消息,指出文件已被覆盖。如果您对如何修改文件以及最终结果应该是什么样子有疑问,请查看本文的notebook

是时候使用修改后的脚本交换人脸了。我编写了一个函数,可以为我们完成繁重的工作:

def massive_face_swap(source,destination,output):
    counter = 0
    for dirname, _, filenames in os.walk(source):
        for filename in filenames:
            current_src = os.path.join(dirname, filename)
            current_dst = os.path.join(destination, filename)
            current_out = os.path.join(output, filename)
            !python /kaggle/working/faceswap/faceswap.py {current_dst} {current_src} {current_out}
            clear_output(wait=True)
            print("Swap progress: "+str(counter)+"/"+str(len(filenames)-1))
            counter += 1

通过传递转换后的人脸集合的相对路径、帧以及要保存带有交换人脸的帧的位置来运行它:

massive_face_swap('./transformed','./frames','./final')

Swap progress: 1700/1700

让我们绘制一个样本:

%matplotlib inline
plt.figure()
image = cv2.imread('/kaggle/working/final/150.jpg')
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
plt.imshow(image)
plt.show()

将其与原始帧进行比较:

plt.figure()
image = cv2.imread('/kaggle/working/frames/150.jpg')
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
plt.imshow(image)
plt.show()

还不错吧?但是,在这里您会注意到面部的变换和交换存在某些缺陷。在创建深度伪造时,可能会发生这种情况,因为人脸集合太小,或者因为您没有对模型进行足够的迭代训练。在我们的例子中,正如我之前提到的,我们训练了2700 epoch,但通常这些模型需要训练超过15000 次迭代。

这些是我们可以获得的一些最佳帧:

既然您已经看到了最后的步骤是多么复杂,现在是时候将所有内容放在一起并生成我们的深度伪造了。

视频重建:获取我们的深度伪造视频

为了最终得到我们期待已久的深度伪造,我们只需要用结果帧而不是原始帧来重建视频。为此,在openCV的帮助下,运行以下代码行:

frames = []
for i in range(1701):
    image = image = cv2.imread(os.path.join('/kaggle/working/final', str(i)+'.jpg'))
    height, width, layers = image.shape
    frames.append(image)
frames = np.array(frames)
videomaker = cv2.VideoWriter('/kaggle/working/deepfake.avi', cv2.VideoWriter_fourcc(*'DIVX'), 25, (width,height))
 
for frame in frames:
    videomaker.write(frame)
 
videomaker.release()

执行结束后,如果这是您定义的目录,您可以在/kaggle/working看到您的deepfake.avi(我的在这里)。目前为止就这样了!我希望这些步骤对您使用这种DIY方法进行深度伪造有所帮助。在最后一篇文章中,我们将探讨DeepFaceLab作为我们最后一种方法的替代方法。

https://www.codeproject.com/Articles/5298030/Putting-it-all-Together-Swapping-Faces-with-Deep-F

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值