讓圖片動起來,特朗普和蒙娜麗莎深情合唱《Unravel》

點擊上方“Python爬蟲與數據挖掘”,進行關注

回覆“書籍”即可獲贈Python從入門到進階共10本電子書

君不見吳中張翰稱達生,秋風忽憶江東行。



1


前言

讓一張圖片,動起來,應該怎麼做?

DeepFake 一階運動模型,讓萬物皆可動。

利用這項技術,用特朗普和蒙娜麗莎的圖片,合唱一首《Unravel》,是什麼效果?

今天,它來了!




今天,繼續手把手教學

算法原理、環境搭建、效果實現,一條龍服務,盡在下文!

2


算法原理

First Order Motion,也就是一階運動模型,來自 NeurIPS 2019 論文。

「First Order Motion Model for Image Animation」

論文最初的目的是讓「靜態圖片」動起來。如下圖所示:“你動,它也動”。


這個模型可以輕易地讓「權利的遊戲」中的人物模仿特朗普進行講話,還可以讓靜態的馬跑起來等。



一階運動模型的思想是用一組自學習的關鍵點和局部仿射變換來建立複雜運動模型。

模型由運動估計模塊和圖像生成模塊兩個主要部分組成。


首先進行關鍵點檢測,然後根據關鍵點,進行運動估計,最後使用圖像生成模塊,生成最終效果。

在運動估計模塊中,該模型通過自監督學習將目標物體的外觀和運動信息進行分離,並進行特徵表示。

而在圖像生成模塊中,模型會對目標運動期間出現的遮擋進行建模,然後從給定的圖片中提取外觀信息,結合先前獲得的特徵表示,生成圖片。

作者使用該算法在四個數據集上進行了訓練和測試。

VoxCeleb 數據集、UvA-Nemo 數據集、The BAIR robot pushing dataset、作者自己收集的數據集。

其中,VoxCeleb 是一個大型人聲識別數據集。

它包含來自 YouTube 視頻的 1251 位名人的約 10 萬段語音,同時數據基本上是性別平衡的(男性佔 55%),這些名人有不同的口音、職業和年齡。


First Order Motion 利用了這個數據集的視頻圖像,進行了模型訓練。

我們就可以利用這個訓練好的,人臉的運動估計模型,完成我們今天的任務。

「特朗普和蒙娜麗莎的深情合唱」。

除了需要用到這個一階運動模型,還需要使用 OpenCV 和 ffmpeg 做視頻、音頻和圖像的處理。

具體的實現,在下文的「效果實現」中說明。

3


環境搭建

效果實現上,我們可以直接用已有的庫去實現我們想要的功能。

「Real Time Image Animation」

項目地址:
https://github.com/anandpawara/Real_Time_Image_Animation

Python 爲什麼這麼受歡迎,就是因爲這一點

有很多開源項目,方便我們快速實現自己想要的功能,極大降低了開發成本。

真是,誰用誰知道啊。

環境搭建,還是建議使用 Anaconda,安裝一些必要的第三方庫,可以參考這篇開發環境搭建的內容:

《Pytorch深度學習實戰教程(一):語義分割基礎與環境搭建

這個項目需要用到的第三方庫,也都寫的很全:
https://github.com/anandpawara/Real_Time_Image_Animation/blob/master/requirements.txt

直接使用 pip 安裝即可:

python -m pip install -r requirements.txt

此外,爲了處理音頻和視頻,還需要配置 ffmpeg。

安裝好 ffmpeg 並配置好環境變量即可。

ffmpeg 下載地址:
https://ffmpeg.zeranoe.com/builds/

4


效果實現

實現也非常簡單。

首先,整理一下思路:

「Real Time Image Animation」使用一階運動模型,根據已有視頻,讓靜態圖動起來。


左圖爲原始圖片,中間爲生成結果,右側爲原始視頻。

但是,這個項目只能處理圖像不能保留音頻

所以,我們需要先將音頻保存,再將處理好的視頻和音頻進行合成。

這個功能,就用我們下載好的 ffmpeg 實現。

編寫如下代碼:

import subprocessimport osfrom PIL import Image
def video2mp3(file_name): """ 將視頻轉爲音頻 :param file_name: 傳入視頻文件的路徑 :return: """ outfile_name = file_name.split('.')[0] + '.mp3' cmd = 'ffmpeg -i ' + file_name + ' -f mp3 ' + outfile_name subprocess.call(cmd, shell=True)
def video_add_mp3(file_name, mp3_file): """ 視頻添加音頻 :param file_name: 傳入視頻文件的路徑 :param mp3_file: 傳入音頻文件的路徑 :return: """ outfile_name = file_name.split('.')[0] + '-f.mp4' subprocess.call('ffmpeg -i ' + file_name + ' -i ' + mp3_file + ' -strict -2 -f mp4 ' + outfile_name, shell=True)

搞定,視頻轉音頻,以及音頻合成都搞定了。

我們需要對「Real Time Image Animation」這個項目進行修改,修改 image_animation.py 文件。

import imageioimport torchfrom tqdm import tqdmfrom animate import normalize_kpfrom demo import load_checkpointsimport numpy as npimport matplotlib.pyplot as pltimport matplotlib.animation as animationfrom skimage import img_as_ubytefrom skimage.transform import resizeimport cv2import osimport argparse
import subprocessimport osfrom PIL import Image
def video2mp3(file_name): """ 將視頻轉爲音頻 :param file_name: 傳入視頻文件的路徑 :return: """ outfile_name = file_name.split('.')[0] + '.mp3' cmd = 'ffmpeg -i ' + file_name + ' -f mp3 ' + outfile_name print(cmd) subprocess.call(cmd, shell=True)

def video_add_mp3(file_name, mp3_file): """ 視頻添加音頻 :param file_name: 傳入視頻文件的路徑 :param mp3_file: 傳入音頻文件的路徑 :return: """ outfile_name = file_name.split('.')[0] + '-f.mp4' subprocess.call('ffmpeg -i ' + file_name + ' -i ' + mp3_file + ' -strict -2 -f mp4 ' + outfile_name, shell=True)
ap = argparse.ArgumentParser()ap.add_argument("-i", "--input_image", required=True,help="Path to image to animate")ap.add_argument("-c", "--checkpoint", required=True,help="Path to checkpoint")ap.add_argument("-v","--input_video", required=False, help="Path to video input")
args = vars(ap.parse_args())
print("[INFO] loading source image and checkpoint...")source_path = args['input_image']checkpoint_path = args['checkpoint']if args['input_video']: video_path = args['input_video']else: video_path = Nonesource_image = imageio.imread(source_path)source_image = resize(source_image,(256,256))[..., :3]
generator, kp_detector = load_checkpoints(config_path='config/vox-256.yaml', checkpoint_path=checkpoint_path)
if not os.path.exists('output'): os.mkdir('output')

relative=Trueadapt_movement_scale=Truecpu=False
if video_path: cap = cv2.VideoCapture(video_path) print("[INFO] Loading video from the given path")else: cap = cv2.VideoCapture(0) print("[INFO] Initializing front camera...")
fps = cap.get(cv2.CAP_PROP_FPS)size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))

video2mp3(file_name = video_path)


fourcc = cv2.VideoWriter_fourcc('M','P','E','G')#out1 = cv2.VideoWriter('output/test.avi', fourcc, fps, (256*3 , 256), True)out1 = cv2.VideoWriter('output/test.mp4', fourcc, fps, size, True)
cv2_source = cv2.cvtColor(source_image.astype('float32'),cv2.COLOR_BGR2RGB)with torch.no_grad() : predictions = [] source = torch.tensor(source_image[np.newaxis].astype(np.float32)).permute(0, 3, 1, 2) if not cpu: source = source.cuda() kp_source = kp_detector(source) count = 0 while(True): ret, frame = cap.read() frame = cv2.flip(frame,1) if ret == True:
if not video_path: x = 143 y = 87 w = 322 h = 322 frame = frame[y:y+h,x:x+w] frame1 = resize(frame,(256,256))[..., :3]
if count == 0: source_image1 = frame1 source1 = torch.tensor(source_image1[np.newaxis].astype(np.float32)).permute(0, 3, 1, 2) kp_driving_initial = kp_detector(source1)
frame_test = torch.tensor(frame1[np.newaxis].astype(np.float32)).permute(0, 3, 1, 2)
driving_frame = frame_test if not cpu: driving_frame = driving_frame.cuda() kp_driving = kp_detector(driving_frame) kp_norm = normalize_kp(kp_source=kp_source, kp_driving=kp_driving, kp_driving_initial=kp_driving_initial, use_relative_movement=relative, use_relative_jacobian=relative, adapt_movement_scale=adapt_movement_scale) out = generator(source, kp_source=kp_source, kp_driving=kp_norm) predictions.append(np.transpose(out['prediction'].data.cpu().numpy(), [0, 2, 3, 1])[0]) im = np.transpose(out['prediction'].data.cpu().numpy(), [0, 2, 3, 1])[0] im = cv2.cvtColor(im,cv2.COLOR_RGB2BGR) #joinedFrame = np.concatenate((cv2_source,im,frame1),axis=1) #joinedFrame = np.concatenate((cv2_source,im,frame1),axis=1)
#cv2.imshow('Test',joinedFrame) #out1.write(img_as_ubyte(joinedFrame)) out1.write(img_as_ubyte(im)) count += 1# if cv2.waitKey(20) & 0xFF == ord('q'):# break else: break
cap.release() out1.release() cv2.destroyAllWindows()
video_add_mp3(file_name='output/test.mp4', mp3_file=video_path.split('.')[0] + '.mp3')

然後下載算法需要的權重文件視頻圖片素材



修改好的代碼權重文件視頻圖片素材我都已經打包好了拿來直接用也可以

下載鏈接(密碼:amz5):
https://pan.baidu.com/s/1TEd7SOaO5mzPaxpOh2pALQ 

運行命令:

python image_animation.py -i path_to_input_file -c path_to_checkpoint -v path_to_video_file

path_to_input_file 是輸入的模板圖片。

path_to_checkpoint 是權重文件路徑。

path_to_video_file 是輸入的視頻文件。

如果使用我打包好的程序,可以使用如下指令直接運行,獲得文章開頭的視頻:

python image_animation.py -i Inputs/trump2.png -c checkpoints/vox-cpk.pth.tar -v 1.mp4

最後生成的視頻存放在 output 文件夾下。

大功告成!

5


最後

算法處理視頻的速度很快,用 GPU 幾秒鐘就能搞定。

------------------- End -------------------

往期精彩文章推薦:

歡迎大家點贊,留言,轉發,轉載,感謝大家的相伴與支持

想加入Python學習羣請在後臺回覆【入羣

萬水千山總是情,點個【在看】行不行

/今日留言主題/

隨便說一兩句吧~~

本文分享自微信公衆號 - Python爬蟲與數據挖掘(crawler_python)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章