目录
- 1. 前言
- 2. 2种搭建思路
- 3. 写在前面的坑
- (1)版本一定要严格遵守要求;
- (2)下载faceswap的github源码
- (3)Anacoda也不是万能的
- (4)tensorflow 与cuda、cudnn、python、keras的版本对应
- 4. 利用Anacoda搭建虚拟环境
- 4.1下载并安装Anacoda
- 4.2 首先安装cuda和cudnn
- 4.3 安装其他主要依赖库
- 5. 数据预处理
- 5.1 3种数据
- 5.2 数据预处理
- 6. 脸部提取
- 7. 训练模型
- 8. 脸部替换
- 9. 结果处理
1. 前言
最近比较火的AI换脸,其实都源于2018年github上deepfakes 的faceswap,今天就抽空下载faceswap的代码,在Ubuntu 18.04上搭建一下工程环境。
2. 2种搭建思路
有2种搭建思路,一是直接在本机上安装各种依赖库,另一种是利用Anacoda建立虚拟环境。
由于faceswap的代码较早,依赖库的版本普遍版本号很低,尤其是tensorflow和cuda等环境,在本地用pip等根本无法安装指定版本的,而经过本人2天的测试发现,只要faceswap要求的依赖项版本号稍微差一点,就可能出现各种问题。所以最终,我还是选择了在Ubuntu18.04上利用Anacoda搭建虚拟环境,在虚拟环境种安装。
这样的优点有三: 一是随时可以推翻重来; 二是怎么折腾都不影响本机环境; 三是可以利用conda install 安装一些主要依赖库,可以自动安装其他琐碎的依赖项。
3. 写在前面的坑
(1)版本一定要严格遵守要求;
GPU版faceswap需要的主要依赖库和版本号为:
pathlib1.0.1
scandir1.6
h5py2.7.1
Keras2.1.2
opencv-python3.3.0.10
tensorflow-gpu1.4.0
scikit-image
dlib
face_recognition
tqdm
(2)下载faceswap的github源码
注意一定是官方的源码:
https://github.com/deepfakes/faceswap/tree/20753a64b76a156aea17724348269d60dd525f87
github上有一个国人自己搞的 faceswap-master,一开始我下了这个,结果太多的坑,实在走不下去了,浪费了大半天的时间。
(3)Anacoda也不是万能的
因为一些需要的依赖库版本实在太老了,用 conda install 根本找不到,需要在conda虚拟环境下再用pip安装依赖项。
(4)tensorflow 与cuda、cudnn、python、keras的版本对应
这是一个大坑,一定要实现查对好,否则在调用keras函数时出错、或者无法使用GPU进行计算。具体的对应关系参照下面两张图:
根据前述内容,faceswap 需要 TensorFlow-GPU=1.4.0,对应keras=2.1.2、Python=3.5、cuda=8.0、cudnn=6.0.
4. 利用Anacoda搭建虚拟环境
参考博文如下:
https://blog.csdn.net/sinat_38816924/article/details/88752817
https://www.jianshu.com/p/7265011ba3f2
https://blog.csdn.net/ytusdc/article/details/99699228
https://blog.csdn.net/ytusdc/article/details/99699228
4.1下载并安装Anacoda
(1)可以去清华源下载:
https://mirrors.tuna.tsinghua.edu.cn/help/anaconda/
(2)使用以下命令安装:
bash ~/Downloads/Anaconda3-*-Linux-x86_64.sh
# *号对应下载的版本号
(3)环境变量配置
在Anaconda安装过程中会让你选择是否修改环境变量,主要要输入“y”,否则需要手动进行修改,运行以下命令:
export PATH="/home/anaconda3/bin:$PATH"
source ~/.bashrc
# 环境变量有问题时,输入 conda命令会提示你如何手动修改
(4)创建并激活虚拟环境,输入以下命令:
conda create -n faceswap python=3.5
conda activate faceswap
# 激活 faceswap 虚拟环境后,你的命令行前面会多出虚拟环境的名称 (faceswap)
(5)万一环境搞砸了,直接删除重来,输入以下命令删除faceswap虚拟环境:
conda remove -n faceswap --all
# 如果想卸载Anaconda,直接 sudo rm -rf */anaconda3
4.2 首先安装cuda和cudnn
(1) 首先根据上一步激活 faceswap 的虚拟环境;
(2)安装cuda8.0,输入以下命令:
conda install cudatoolkit=8.0 -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/linux-64/
# 这里也可以在anaconda安装完成后替换一下源,具体操作见上述参考博文
(3)安装cudnn6.0,输入以下命令:
conda install cudnn=6.0 -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/linux-64/
(4)注意,装完cuda和cudnn后,在虚拟环境中用常规的方法查到的是本机的版本,比如:
cat /usr/local/cuda/version.txt
cat /usr/local/cuda/include/cudnn.h | grep CUDNN_MAJOR -A 2
只要安装过程中不报错就行。
4.3 安装其他主要依赖库
tensorflow、keras、opencv等直接用conda install 会找不到对应的版本,所以这里直接在虚拟环境下使用pip安装,输入以下命令:
pip install pathlib==1.0.1 scandir==1.6 h5py==2.7.1 Keras==2.1.2 opencv-python==3.3.0.10 tensorflow-gpu==1.4.0 scikit-image dlib face_recognition tqdm
# 如果失败了一般是网不好,可以加个源 -i https://pypi.tuna.tsinghua.edu.cn/simple/
# 或者可以增加等待时间 --timeout=1000
5. 数据预处理
5.1 3种数据
假设我们要用B替换A,那么我们需要3种数据:
(1)B的训练数据:最好只有B一个人的、各个角度和衣服的图片或视频;
(2)A的训练数据:最好只有A一个人的、各个角度和衣服的图片或视频;
(3)想要替换的、原始的、有B的图片或视频。
注意faceswap原版是不支持视频的,我自己写了2个程序分别将视频转成帧图片和将帧图片合并成视频。
5.2 数据预处理
(1)在faceswap 源码的工程根目录下新建文件夹data,并根据使用次数建立相应的额test文件夹,代码如下:
cd data
mkdir test*
d test*
mkdir srcvideo srcpic srcface targetvideo targetpic targetface inputvideo inputpic outpic
# * 代表了次数,比如今天使用是test1
(2)拷贝数据
拷贝A的训练视频到 ‘/home/wz/Documents/faceswap-master/data/test*/srcvideo/’ 路径;
拷贝B的训练数据到 ‘/home/wz/Documents/faceswap-master/data/test*/targetvideo/’ 路径;
拷贝需要被替换的、含有A的视频到 ‘/home/wz/Documents/faceswap-master/data/test*/inputvideo/’ 路径。
(3)修改video2pic.py中的’videopath’ 和 ‘picpath’,分别修改运行3次,以便将B的训练视频、A的训练视频和需要被替换的视频转成图片。代码如下:
# video2pic.py
import cv2
import os
def save_img():video_path = '/home/wz/Documents/faceswap/data/test1/inputvideo/'pic_path = '/home/wz/Documents/faceswap/data/test1/inputpic/'videos = os.listdir(video_path)count = 0for video_name in videos:file_name = video_name.split('.')[0]#folder_name = video_path + file_name#os.makedirs(folder_name,exist_ok=True)vc = cv2.VideoCapture(video_path+video_name) #读入视频文件c=0rval=vc.isOpened()while rval: #循环读取视频帧c = c + 1rval, frame = vc.read()#pic_path = folder_name+'/'if rval:# 通过修改 c%* == 0,来选择跳几帧图像if c%1==0:#height, width = frame.shape[:2] #frame = cv2.resize(frame,(512,int(height*(512/width))))print(pic_path + file_name+ '_'+str(c) + '.jpg')count = count + 1length=len(str(count))if length ==1:COUNT = '0000'+str(count)elif length == 2:COUNT = '000'+str(count)elif length == 3:COUNT = '00'+str(count)elif length == 4:COUNT = '0'+str(count)else:COUNT = str(count)cv2.imwrite(pic_path + COUNT + '.jpg', frame) #存储为图像,保存名为 文件夹名_数字(第几个文件).jpgelse:continueelse:breakvc.release()print('save_success')#print(folder_name)save_img()
这里还需要将图片中非人脸的照片手动删除。
这个程序,我在别人的代码上增加了5位数编码命名的过程,以便在后续视频合成的时候有顺序可寻。原始代码出自:(找不到了)
6. 脸部提取
还需要将转成图片的训练数据将脸部裁剪出来进行模型训练,这一步需要在conda虚拟环境中进行,代码如下:
python3 faceswap.py extract -i /home/Documents/faceswap/data/test*/srcpic/ -o /home/Documents/faceswap/data/test*/srcface/
python3 faceswap.py extract -i /home/Documents/faceswap/data/test*/targetpic/ -o /home/Documents/faceswap/data/test*/targetface/
# 换成自己的路径
结果如下:
这里需要将非人脸或者非主角人脸的照片删除。
7. 训练模型
在虚拟环境中输入以下命令:
python3 faceswap.py train -A /home/Documents/faceswap/data/test*/srcface/ -B /home/Documents/faceswap/data/test*/targetface/
# 换成自己的额数据路径
# 切记 A是被替换的人脸数据,B是用来替换的人脸数据
如果这一步出错或者不能使用GPU训练,检查上述tensorflow、cuda、cudnn、keras和python的版本对应关系。
模型训练自动保存模型文件或者手动按回车键停止保存,停止后再次训练会自动加载之前的模型,所以不同的人脸替换,各自模型要及时转移保存。
8. 脸部替换
在虚拟环境中输入以下命令:
python3 faceswap.py convert -i /home/Documents/faceswap/data/test1/inputpic/ -o /home/Documents/faceswap/data/test1/outpic/ -m /home/Documents/faceswap/models/
# 换成自己的路径
此时的结果为图片。
转换时可以添加很多指定参数,推荐开启“-S --seamless -D --cnn”,使得替换结果看起来很自然。
可指定的参数源码如下:
def add_optional_arguments(self, parser):parser.add_argument('-m', '--model-dir',action=FullPaths,dest="model_dir",default="models",help="Model directory. A directory containing the trained model \you wish to process. Defaults to 'models'")parser.add_argument('-t', '--trainer',type=str,choices=("Original", "LowMem", "GAN"), # case sensitive because this is used to load a plug-in.default="Original",help="Select the trainer that was used to create the model.")parser.add_argument('-s', '--swap-model',action="store_true",dest="swap_model",default=False,help="Swap the model. Instead of A -> B, swap B -> A.")parser.add_argument('-c', '--converter',type=str,choices=("Masked", "Adjust", "GAN"), # case sensitive because this is used to load a plugin.default="Masked",help="Converter to use.")parser.add_argument('-D', '--detector',type=str,choices=("hog", "cnn"), # case sensitive because this is used to load a plugin.default="hog",help="Detector to use. 'cnn' detects much more angles but will be much more resource intensive and may fail on large files.")parser.add_argument('-fr', '--frame-ranges',nargs="+",type=str,help="frame ranges to apply transfer to e.g. For frames 10 to 50 and 90 to 100 use --frame-ranges 10-50 90-100. \Files must have the frame-number as the last number in the name!")parser.add_argument('-d', '--discard-frames',action="store_true",dest="discard_frames",default=False,help="When used with --frame-ranges discards frames that are not processed instead of writing them out unchanged.")parser.add_argument('-f', '--filter',type=str,dest="filter",default="filter.jpg",help="Reference image for the person you want to process. Should be a front portrait")parser.add_argument('-b', '--blur-size',type=int,default=2,help="Blur size. (Masked converter only)")parser.add_argument('-S', '--seamless',action="store_true",dest="seamless_clone",default=False,help="Seamless mode. (Masked converter only)")parser.add_argument('-M', '--mask-type',type=str.lower, #lowercase this, because its just a string later on.dest="mask_type",choices=["rect", "facehull", "facehullandrect"],default="facehullandrect",help="Mask to use to replace faces. (Masked converter only)")parser.add_argument('-e', '--erosion-kernel-size',dest="erosion_kernel_size",type=int,default=None,help="Erosion kernel size. (Masked converter only)")parser.add_argument('-sm', '--smooth-mask',action="store_true",dest="smooth_mask",default=True,help="Smooth mask (Adjust converter only)")parser.add_argument('-aca', '--avg-color-adjust',action="store_true",dest="avg_color_adjust",default=True,help="Average color adjust. (Adjust converter only)")return parser
9. 结果处理
需要将上述步骤的结果图片合成为视频,代码如下:
# pic2video.py
import os
import cv2
def makeVideo(path, size):filelist = os.listdir(path)filelist2 = [os.path.join(path, i) for i in filelist]print(filelist2)fps = 30 # 我设定位视频每秒1帧,可以自行修改# size = (1920, 1080) # 需要转为视频的图片的尺寸,这里必须和图片尺寸一致video = cv2.VideoWriter(path + "result.avi", cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'), fps,size) filelist2.sort()for item in filelist2:if item.endswith('.jpg'):print(item)img = cv2.imread(item)video.write(img)video.release()cv2.destroyAllWindows()print('视频合成生成完成啦')if __name__ == '__main__':# 换成你自己的路径path = r'/home/wz/Documents/faceswap/data/test1/inputpic/' # 需要转为视频的图片的尺寸,必须所有图片大小一样,不然无法合并成功# 手动指定尺寸size = (720, 1280)makeVideo(path, size)
这个程序,我在别人的代码上增加了对遍历文件夹后的名称目录排序的语句,保证合成的视频帧顺序不会乱。
原始代码出自:
https://blog.csdn.net/weixin_42081389/article/details/100517667
效果视频我就不放了,有伤风化。