Python first-order-model实现让照片动起来


Posted in Python onJune 25, 2022

前言

看到一个很有意思的项目,其实在之前就在百度飞浆等平台上看到类似的实现效果。

可以将照片按照视频的表情,动起来。看一下项目给出的效果。

Python first-order-model实现让照片动起来

项目地址:first-order-model项目地址

还是老样子,不管作者给出的种种效果,自己测试一下。

资源下载和安装

我们先看一下README关于项目的基本信息,可以看出除了表情驱动照片,还可以姿态迁移。

Python first-order-model实现让照片动起来

Python first-order-model实现让照片动起来

模型文件提供了线上的下载地址。

Python first-order-model实现让照片动起来

文件很大而且难下,我下好了放到我的云盘上,可以从下面云盘下载。

链接 提取码:ikix

模型文件放到根目录下新建的checkpoint文件夹下。

Python first-order-model实现让照片动起来

Python first-order-model实现让照片动起来

将requirements.txt中的依赖安装一下。

Python first-order-model实现让照片动起来

安装补充 

在测试README中的命令的时候,如果出现一下报错。

Traceback (most recent call last):
  File "demo.py", line 17, in <module>
    from animate import normalize_kp
  File "D:\spyder\first-order-model\animate.py", line 7, in <module>
    from frames_dataset import PairedDataset
  File "D:\spyder\first-order-model\frames_dataset.py", line 10, in <module>
    from augmentation import AllAugmentationTransform
  File "D:\spyder\first-order-model\augmentation.py", line 13, in <module>
    import torchvision
  File "C:\Users\huyi\.conda\envs\fom\lib\site-packages\torchvision\__init__.py", line 2, in <module>
    from torchvision import datasets
  File "C:\Users\huyi\.conda\envs\fom\lib\site-packages\torchvision\datasets\__init__.py", line 9, in <module>
    from .fakedata import FakeData
  File "C:\Users\huyi\.conda\envs\fom\lib\site-packages\torchvision\datasets\fakedata.py", line 3, in <module>
    from .. import transforms
  File "C:\Users\huyi\.conda\envs\fom\lib\site-packages\torchvision\transforms\__init__.py", line 1, in <module>
    from .transforms import *
  File "C:\Users\huyi\.conda\envs\fom\lib\site-packages\torchvision\transforms\transforms.py", line 16, in <module>
    from . import functional as F
  File "C:\Users\huyi\.conda\envs\fom\lib\site-packages\torchvision\transforms\functional.py", line 5, in <module>
    from PIL import Image, ImageOps, ImageEnhance, PILLOW_VERSION
ImportError: cannot import name 'PILLOW_VERSION' from 'PIL' (C:\Users\huyi\.conda\envs\fom\lib\site-packages\PIL\__init__.py)

这个问题主要是我使用的pillow版本过高的原因,如果不想找对应的低版本,可以按照我的方式解决。 

1、修改functional.py代码,将PILLOW_VERSION调整为__version__。

Python first-order-model实现让照片动起来

2、将imageio升级。

pip install --upgrade imageio -i https://pypi.douban.com/simple

3、安装imageio_ffmpeg模块。

pip install imageio-ffmpeg -i https://pypi.douban.com/simple

工具代码验证

官方给出的使用方法我就不重复测试,大家可以按照下面的命令去测试一下。

Python first-order-model实现让照片动起来

这里我推荐一个可视化的库gradio,下面我将demo.py的代码改造了一下。

新的工具文件代码如下:

#!/user/bin/env python
# coding=utf-8
"""
@project : first-order-model
@author  : 剑客阿良_ALiang
@file   : hy_gradio.py
@ide    : PyCharm
@time   : 2022-06-23 14:35:28
"""
import uuid
from typing import Optional
 
import gradio as gr
import matplotlib
 
matplotlib.use('Agg')
import os, sys
import yaml
from argparse import ArgumentParser
from tqdm import tqdm
 
import imageio
import numpy as np
from skimage.transform import resize
from skimage import img_as_ubyte
import torch
from sync_batchnorm import DataParallelWithCallback
 
from modules.generator import OcclusionAwareGenerator
from modules.keypoint_detector import KPDetector
from animate import normalize_kp
from scipy.spatial import ConvexHull
 
if sys.version_info[0] < 3:
    raise Exception("You must use Python 3 or higher. Recommended version is Python 3.7")
 
 
def load_checkpoints(config_path, checkpoint_path, cpu=False):
    with open(config_path) as f:
        config = yaml.load(f)
 
    generator = OcclusionAwareGenerator(**config['model_params']['generator_params'],
                                        **config['model_params']['common_params'])
    if not cpu:
        generator.cuda()
 
    kp_detector = KPDetector(**config['model_params']['kp_detector_params'],
                             **config['model_params']['common_params'])
    if not cpu:
        kp_detector.cuda()
 
    if cpu:
        checkpoint = torch.load(checkpoint_path, map_location=torch.device('cpu'))
    else:
        checkpoint = torch.load(checkpoint_path)
 
    generator.load_state_dict(checkpoint['generator'])
    kp_detector.load_state_dict(checkpoint['kp_detector'])
 
    if not cpu:
        generator = DataParallelWithCallback(generator)
        kp_detector = DataParallelWithCallback(kp_detector)
 
    generator.eval()
    kp_detector.eval()
 
    return generator, kp_detector
 
 
def make_animation(source_image, driving_video, generator, kp_detector, relative=True, adapt_movement_scale=True,
                   cpu=False):
    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()
        driving = torch.tensor(np.array(driving_video)[np.newaxis].astype(np.float32)).permute(0, 4, 1, 2, 3)
        kp_source = kp_detector(source)
        kp_driving_initial = kp_detector(driving[:, :, 0])
 
        for frame_idx in tqdm(range(driving.shape[2])):
            driving_frame = driving[:, :, frame_idx]
            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])
    return predictions
 
 
def find_best_frame(source, driving, cpu=False):
    import face_alignment
 
    def normalize_kp(kp):
        kp = kp - kp.mean(axis=0, keepdims=True)
        area = ConvexHull(kp[:, :2]).volume
        area = np.sqrt(area)
        kp[:, :2] = kp[:, :2] / area
        return kp
 
    fa = face_alignment.FaceAlignment(face_alignment.LandmarksType._2D, flip_input=True,
                                      device='cpu' if cpu else 'cuda')
    kp_source = fa.get_landmarks(255 * source)[0]
    kp_source = normalize_kp(kp_source)
    norm = float('inf')
    frame_num = 0
    for i, image in tqdm(enumerate(driving)):
        kp_driving = fa.get_landmarks(255 * image)[0]
        kp_driving = normalize_kp(kp_driving)
        new_norm = (np.abs(kp_source - kp_driving) ** 2).sum()
        if new_norm < norm:
            norm = new_norm
            frame_num = i
    return frame_num
 
 
def h_interface(input_image: str):
    parser = ArgumentParser()
    opt = parser.parse_args()
    opt.config = "./config/vox-256.yaml"
    opt.checkpoint = "./checkpoint/vox-cpk.pth.tar"
    opt.source_image = input_image
    opt.driving_video = "./data/input/ts.mp4"
    opt.result_video = "./data/result/{}.mp4".format(uuid.uuid1().hex)
    opt.relative = True
    opt.adapt_scale = True
    opt.cpu = True
    opt.find_best_frame = False
    opt.best_frame = False
    # source_image = imageio.imread(opt.source_image)
    source_image = opt.source_image
    reader = imageio.get_reader(opt.driving_video)
    fps = reader.get_meta_data()['fps']
    driving_video = []
    try:
        for im in reader:
            driving_video.append(im)
    except RuntimeError:
        pass
    reader.close()
 
    source_image = resize(source_image, (256, 256))[..., :3]
    driving_video = [resize(frame, (256, 256))[..., :3] for frame in driving_video]
    generator, kp_detector = load_checkpoints(config_path=opt.config, checkpoint_path=opt.checkpoint, cpu=opt.cpu)
 
    if opt.find_best_frame or opt.best_frame is not None:
        i = opt.best_frame if opt.best_frame is not None else find_best_frame(source_image, driving_video, cpu=opt.cpu)
        print("Best frame: " + str(i))
        driving_forward = driving_video[i:]
        driving_backward = driving_video[:(i + 1)][::-1]
        predictions_forward = make_animation(source_image, driving_forward, generator, kp_detector,
                                             relative=opt.relative, adapt_movement_scale=opt.adapt_scale, cpu=opt.cpu)
        predictions_backward = make_animation(source_image, driving_backward, generator, kp_detector,
                                              relative=opt.relative, adapt_movement_scale=opt.adapt_scale, cpu=opt.cpu)
        predictions = predictions_backward[::-1] + predictions_forward[1:]
    else:
        predictions = make_animation(source_image, driving_video, generator, kp_detector, relative=opt.relative,
                                     adapt_movement_scale=opt.adapt_scale, cpu=opt.cpu)
    imageio.mimsave(opt.result_video, [img_as_ubyte(frame) for frame in predictions], fps=fps)
    return opt.result_video
 
 
if __name__ == "__main__":
    demo = gr.Interface(h_interface, inputs=[gr.Image(shape=(500, 500))], outputs=[gr.Video()])
 
    demo.launch()
    # h_interface("C:\\Users\\huyi\\Desktop\\xx3.jpg")

代码说明

1、将原demo.py中的main函数内容,重新编辑为h_interface方法,输入是想要驱动的图片。

2、其中driving_video参数使用了我自己录制的一段表情视频ts.mp4,我建议在使用的时候可以自己用手机录制一段替换。

3、使用gradio来生成方法的页面,下面会展示给大家看。

4、使用uuid为结果视频命名。

执行结果如下

Running on local URL:  http://127.0.0.1:7860/
To create a public link, set `share=True` in `launch()`.

打开本地的地址:http://localhost:7860/

可以看到我们实现的交互界面如下:

Python first-order-model实现让照片动起来

我们上传一下我准备的样例图片,提交制作。

Python first-order-model实现让照片动起来

看一下执行的日志,如下图。

Python first-order-model实现让照片动起来

看一下制作结果。

Python first-order-model实现让照片动起来

由于上传不了视频,我将视频转成了gif。

Python first-order-model实现让照片动起来

还是蛮有意思的,具体的参数调优我就不弄了,大家可能根据需要调整我提供的方法里面的参数。

以上就是Python first-order-model实现让照片动起来的详细内容,更多关于Python 照片动起来的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
使用Python的SymPy库解决数学运算问题的方法
Mar 27 Python
python实现对图片进行旋转,放缩,裁剪的功能
Aug 07 Python
Python 从subprocess运行的子进程中实时获取输出的例子
Aug 14 Python
详解python列表(list)的使用技巧及高级操作
Aug 15 Python
python 实现提取log文件中的关键句子,并进行统计分析
Dec 24 Python
使用Tkinter制作信息提示框
Feb 18 Python
Python 随机生成测试数据的模块:faker基本使用方法详解
Apr 09 Python
pyspark 随机森林的实现
Apr 24 Python
Python+OpenCV图像处理——实现直线检测
Oct 23 Python
pytorch 移动端部署之helloworld的使用
Oct 30 Python
pytorch实现线性回归以及多元回归
Apr 11 Python
Python机器学习之基于Pytorch实现猫狗分类
Jun 08 Python
python热力图实现的完整实例
彻底弄懂Python中的回调函数(callback)
Jun 25 #Python
利用Python实现翻译HTML中的文本字符串
Jun 21 #Python
使用scrapy实现增量式爬取方式
Jun 21 #Python
python+opencv实现目标跟踪过程
Jun 21 #Python
使用opencv-python如何打开USB或者笔记本前置摄像头
Python+DeOldify实现老照片上色功能
You might like
Yii2搭建后台并实现rbac权限控制完整实例教程
2016/04/28 PHP
php 使用curl模拟ip和来源进行访问的实现方法
2017/05/02 PHP
PHP的PDO预定义常量讲解
2019/01/24 PHP
Laravel框架之解决前端显示图片问题
2019/10/24 PHP
js form 验证函数 当前比较流行的错误提示
2009/06/23 Javascript
仿谷歌主页js动画效果实现代码
2013/07/14 Javascript
使用Browserify配合jQuery进行编程的超级指南
2015/07/28 Javascript
ArtEditor富文本编辑器增加表单提交功能
2016/04/18 Javascript
checkbox批量选中,获取选中项的值的简单实例
2016/06/28 Javascript
js中的面向对象入门
2017/03/06 Javascript
jQuery图片瀑布流的简单实现代码
2017/03/15 Javascript
Bootstrap多级菜单的实现代码
2017/05/23 Javascript
详解JavaScript调用栈、尾递归和手动优化
2017/06/03 Javascript
Vue实现textarea固定输入行数与添加下划线样式的思路详解
2018/06/28 Javascript
微信小程序云开发 生成带参小程序码流程
2019/05/18 Javascript
JavaScript实现Tab选项卡切换
2020/02/13 Javascript
Vue两个版本的区别和使用方法(更深层次了解)
2020/02/16 Javascript
python实现k均值算法示例(k均值聚类算法)
2014/03/16 Python
Python中使用dom模块生成XML文件示例
2015/04/05 Python
python 判断是否为正小数和正整数的实例
2017/07/23 Python
CentOS下使用yum安装python-pip失败的完美解决方法
2017/08/16 Python
hmac模块生成加入了密钥的消息摘要详解
2018/01/11 Python
Python3操作Excel文件(读写)的简单实例
2019/09/02 Python
解决Keras中Embedding层masking与Concatenate层不可调和的问题
2020/06/18 Python
python获取本周、上周、本月、上月及本季的时间代码实例
2020/09/08 Python
雷曼兄弟的五金店:Lehman’s Hardware Store
2019/04/10 全球购物
JDK安装目录下有哪些内容
2014/08/25 面试题
2014社区三八妇女节活动总结
2014/03/01 职场文书
施工员岗位职责
2014/03/16 职场文书
2014红色之旅心得体会
2014/10/07 职场文书
干部作风建设心得体会
2014/10/22 职场文书
教师党员个人总结
2015/02/10 职场文书
社区活动总结范文
2015/05/07 职场文书
教你用python实现一个无界面的小型图书管理系统
2021/05/21 Python
用Python可视化新冠疫情数据
2022/01/18 Python
MySQL 条件查询的常用操作
2022/04/28 MySQL