前言

飞桨(PaddlePaddle)是集深度学习核心框架、工具组件和服务平台为一体的技术先进、功能完备的开源深度学习平台,已被中国企业广泛使用,深度契合企业应用需求,拥有活跃的开发者社区生态。提供丰富的官方支持模型集合,我们这里将要使用到其中的骨骼节点检测模型,通过PaddleHub提供的人体骨骼关键点检测预训练模型,我们就可以快速实现皮影戏的效果。
这里说一下这个项目的大体实现流程,先将现有的视频按帧剪切为一张张的图片,并保存到本地,使用PaddleHub提供的人体骨骼关键点检测预训练模型来获取每张图片里人物作出动作时的骨骼关键节点模型,例如左手、左脚、右手、右脚、躯干以及头颅的位置以及方向,在PaddleHub获取到人体骨骼关键点模型之后,就可以对这些关键点进行连接,从而形成了人体姿态。接着我们将皮影的身体躯干素材拼接到模型上,这就完成了将图片里的人物动作转化为皮影戏。
将每张图片都这样操作,保存拼接之后的的图片,将所有的图片合成为视频即可让皮影跟随人体姿态进行运动,就达到“皮影戏”的效果。
皮影素材
项目实现过程中使用的Python版本为3.7.0,其他依赖库的版本分别为cv2 4.5.1.48、matplotlib 2.2.2、numpy 1.19.3、tensorflow 2.4.1。

具体流程

一、安装依赖库以及模型

安装PaddlePaddle
windows cpu版本快速安装

python -m pip install paddlepaddle==2.0.2 -i https://mirror.baidu.com/pypi/simple

其他版本安装请参考官网https://www.paddlepaddle.org.cn/install/quick?docurl=/documentation/docs/zh/install/pip/windows-pip.html

安装PaddleHub

pip install PaddleHub

导入人体骨骼关键节点检测模型

hub install human_pose_estimation_resnet50_mpii==1.1.1

二、检测是否安装成功

检测图片骨骼节点

import os
import cv2
import paddlehub as hub
import matplotlib.pyplot as plt
from matplotlib.image import imread
import numpy as npdef show_img(img_path, size=8):'''文件读取图片显示'''im = imread(img_path)plt.figure(figsize=(size, size))plt.axis("off")plt.imshow(im)def img_show_bgr(image, size=8):'''cv读取的图片显示'''image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)plt.figure(figsize=(size, size))plt.imshow(image)plt.axis("off")plt.show()pose_estimation = hub.Module(name="human_pose_estimation_resnet50_mpii")
result = pose_estimation.keypoint_detection(paths=['test4.jpg'], visualization=True, output_dir="work/output_pose/")
print(result)

拼接皮影素材
这一步需要用到皮影戏的素材,请移步到文末下载

import os
import cv2
import paddlehub as hub
import matplotlib.pyplot as plt
from matplotlib.image import imread
import numpy as npdef show_img(img_path, size=8):'''文件读取图片显示'''im = imread(img_path)plt.figure(figsize=(size,size))plt.axis("off")plt.imshow(im)
def img_show_bgr(image,size=8):'''cv读取的图片显示'''image=cv2.cvtColor(image,cv2.COLOR_BGR2RGB)plt.figure(figsize=(size,size))plt.imshow(image)plt.axis("off")plt.show() pose_estimation = hub.Module(name="human_pose_estimation_resnet50_mpii")
##result = pose_estimation.keypoint_detection(paths=['test4.jpg'], visualization=True, output_dir="work/output_pose/")
##print(result)def get_true_angel(value):'''转转得到角度值'''return value/np.pi*180def get_angle(x1, y1, x2, y2):'''计算旋转角度'''dx = abs(x1- x2)dy = abs(y1- y2)result_angele = 0if x1 == x2:if y1 > y2:result_angele = 180else:if y1!=y2:the_angle = int(get_true_angel(np.arctan(dx/dy)))if x1 < x2:if y1>y2:result_angele = -(180 - the_angle)elif y1<y2:result_angele = -the_angleelif y1==y2:result_angele = -90elif x1 > x2:if y1>y2:result_angele = 180 - the_angleelif y1<y2:result_angele = the_angleelif y1==y2:result_angele = 90if result_angele<0:result_angele = 360 + result_angelereturn result_angeledef rotate_bound(image, angle, key_point_y):'''旋转图像,并取得关节点偏移量'''#获取图像的尺寸(h,w) = image.shape[:2]#旋转中心(cx,cy) = (w/2,h/2)# 关键点必须在中心的y轴上(kx,ky) = cx, key_point_yd = abs(ky - cy)#设置旋转矩阵M = cv2.getRotationMatrix2D((cx,cy), -angle, 1.0)cos = np.abs(M[0,0])sin = np.abs(M[0,1])# 计算图像旋转后的新边界nW = int((h*sin)+(w*cos))nH = int((h*cos)+(w*sin))# 计算旋转后的相对位移move_x = nW/2 + np.sin(angle/180*np.pi)*d move_y = nH/2 - np.cos(angle/180*np.pi)*d# 调整旋转矩阵的移动距离(t_{x}, t_{y})M[0,2] += (nW/2) - cxM[1,2] += (nH/2) - cyreturn cv2.warpAffine(image,M,(nW,nH)), int(move_x), int(move_y)def get_distences(x1, y1, x2, y2):return ((x1-x2)**2 + (y1-y2)**2)**0.5
def append_img_by_sk_points(img, append_img_path, key_point_y, first_point, second_point, append_img_reset_width=None,append_img_max_height_rate=1, middle_flip=False, append_img_max_height=None):'''将需要添加的肢体图片进行缩放'''append_image = cv2.imdecode(np.fromfile(append_img_path, dtype=np.uint8), cv2.IMREAD_UNCHANGED)# 根据长度进行缩放sk_height = int(get_distences(first_point[0], first_point[1], second_point[0], second_point[1])*append_img_max_height_rate)# 缩放制约if append_img_max_height:sk_height = min(sk_height, append_img_max_height)sk_width = int(sk_height/append_image.shape[0]*append_image.shape[1]) if append_img_reset_width is None else int(append_img_reset_width)if sk_width <= 0:sk_width = 1if sk_height <= 0:sk_height = 1# 关键点映射key_point_y_new = int(key_point_y/append_image.shape[0]*append_image.shape[1])# 缩放图片append_image = cv2.resize(append_image, (sk_width, sk_height))img_height, img_width, _ = img.shape# 是否根据骨骼节点位置在 图像中间的左右来控制是否进行 左右翻转图片# 主要处理头部的翻转, 默认头部是朝左if middle_flip:middle_x = int(img_width/2)if first_point[0] < middle_x and second_point[0] < middle_x:append_image = cv2.flip(append_image, 1)# 旋转角度angle = get_angle(first_point[0], first_point[1], second_point[0], second_point[1])append_image, move_x, move_y = rotate_bound(append_image, angle=angle, key_point_y=key_point_y_new)app_img_height, app_img_width, _ = append_image.shapezero_x = first_point[0] - move_xzero_y = first_point[1] - move_y(b, g, r) = cv2.split(append_image) for i in range(0, r.shape[0]):for j in range(0, r.shape[1]):if 230>r[i][j]>200 and 0<=zero_y+i<img_height and 0<=zero_x+j<img_width:img[zero_y+i][zero_x+j] = append_image[i][j]return img
body_img_path_map = {"right_hip" : "./work/shadow_play_material/right_hip.jpg","right_knee" : "./work/shadow_play_material/right_knee.jpg","left_hip" : "./work/shadow_play_material/left_hip.jpg","left_knee" : "./work/shadow_play_material/left_knee.jpg","left_elbow" : "./work/shadow_play_material/left_elbow.jpg","left_wrist" : "./work/shadow_play_material/left_wrist.jpg","right_elbow" : "./work/shadow_play_material/right_elbow.jpg","right_wrist" : "./work/shadow_play_material/right_wrist.jpg","head" : "./work/shadow_play_material/head.jpg","body" : "./work/shadow_play_material/body.jpg"
}def get_combine_img(img_path, pose_estimation=pose_estimation, body_img_path_map=body_img_path_map, backgroup_img_path= 'work/background.jpg'):'''识别图片中的关节点,并将皮影的肢体进行对应,最后与原图像拼接后输出'''result = pose_estimation.keypoint_detection(paths=[img_path])image=cv2.imread(img_path)# 背景图片backgroup_image = cv2.imread(backgroup_img_path)image_flag = cv2.resize(backgroup_image, (image.shape[1], image.shape[0]))# 最小宽度min_width = int(get_distences(result[0]['data']['head_top'][0], result[0]['data']['head_top'][1],result[0]['data']['upper_neck'][0], result[0]['data']['upper_neck'][1])/3)#右大腿append_img_reset_width = max(int(get_distences(result[0]['data']['pelvis'][0], result[0]['data']['pelvis'][1],result[0]['data']['left_hip'][0], result[0]['data']['right_hip'][1])*1.6), min_width)image_flag = append_img_by_sk_points(image_flag, body_img_path_map['right_hip'], key_point_y=10, first_point=result[0]['data']['right_hip'],second_point=result[0]['data']['right_knee'], append_img_reset_width=append_img_reset_width)# 右小腿append_img_reset_width = max(int(get_distences(result[0]['data']['pelvis'][0], result[0]['data']['pelvis'][1],result[0]['data']['left_hip'][0], result[0]['data']['right_hip'][1])*1.5), min_width)image_flag = append_img_by_sk_points(image_flag, body_img_path_map['right_knee'], key_point_y=10, first_point=result[0]['data']['right_knee'],second_point=result[0]['data']['right_ankle'], append_img_reset_width=append_img_reset_width)# 左大腿append_img_reset_width = max(int(get_distences(result[0]['data']['pelvis'][0], result[0]['data']['pelvis'][1],result[0]['data']['left_hip'][0], result[0]['data']['left_hip'][1])*1.6), min_width)image_flag = append_img_by_sk_points(image_flag, body_img_path_map['left_hip'], key_point_y=0, first_point=result[0]['data']['left_hip'],second_point=result[0]['data']['left_knee'], append_img_reset_width=append_img_reset_width)# 左小腿append_img_reset_width = max(int(get_distences(result[0]['data']['pelvis'][0], result[0]['data']['pelvis'][1],result[0]['data']['left_hip'][0], result[0]['data']['left_hip'][1])*1.5), min_width)image_flag = append_img_by_sk_points(image_flag, body_img_path_map['left_knee'], key_point_y=10, first_point=result[0]['data']['left_knee'],second_point=result[0]['data']['left_ankle'], append_img_reset_width=append_img_reset_width)# 右手臂image_flag = append_img_by_sk_points(image_flag, body_img_path_map['left_elbow'], key_point_y=25, first_point=result[0]['data']['right_shoulder'],second_point=result[0]['data']['right_elbow'], append_img_max_height_rate=1.2)# 右手肘append_img_max_height = int(get_distences(result[0]['data']['right_shoulder'][0], result[0]['data']['right_shoulder'][1],result[0]['data']['right_elbow'][0], result[0]['data']['right_elbow'][1])*1.6)image_flag = append_img_by_sk_points(image_flag, body_img_path_map['left_wrist'], key_point_y=10, first_point=result[0]['data']['right_elbow'],second_point=result[0]['data']['right_wrist'], append_img_max_height_rate=1.5, append_img_max_height=append_img_max_height)# 左手臂image_flag = append_img_by_sk_points(image_flag, body_img_path_map['right_elbow'], key_point_y=25, first_point=result[0]['data']['left_shoulder'], second_point=result[0]['data']['left_elbow'],  append_img_max_height_rate=1.2)# 左手肘append_img_max_height = int(get_distences(result[0]['data']['left_shoulder'][0], result[0]['data']['left_shoulder'][1],result[0]['data']['left_elbow'][0], result[0]['data']['left_elbow'][1])*1.6)image_flag = append_img_by_sk_points(image_flag, body_img_path_map['right_wrist'], key_point_y=10, first_point=result[0]['data']['left_elbow'],second_point=result[0]['data']['left_wrist'], append_img_max_height_rate=1.5, append_img_max_height=append_img_max_height)# 头image_flag = append_img_by_sk_points(image_flag, body_img_path_map['head'], key_point_y=10, first_point=result[0]['data']['head_top'],second_point=result[0]['data']['upper_neck'], append_img_max_height_rate=1.2, middle_flip=True)# 身体append_img_reset_width = max(int(get_distences(result[0]['data']['left_shoulder'][0], result[0]['data']['left_shoulder'][1],result[0]['data']['right_shoulder'][0], result[0]['data']['right_shoulder'][1])*1.2), min_width*3)image_flag = append_img_by_sk_points(image_flag, body_img_path_map['body'], key_point_y=20, first_point=result[0]['data']['upper_neck'],second_point=result[0]['data']['pelvis'], append_img_reset_width=append_img_reset_width, append_img_max_height_rate=1.2)result_img =  np.concatenate((image, image_flag), axis=1) return result_img
pos_img_path = 'work/output_pose/body01.jpg'result_img =  get_combine_img(pos_img_path, pose_estimation, body_img_path_map)
img_show_bgr(result_img, size=10)

三、让皮影动起来

准备一个含有人体动作视频,视频素材可以到b站舞蹈区进行下载,将代码中的路径更改为相应的视频路径,并新建mp4_img、mp4_img_analysis文件夹存储相关文件。
这一步耗时比较长,主要看你的电脑配置,我用的笔记本i5+MX150独显配置,两分钟的视频跑了一个半小时才跑完。

import os
import cv2
import paddlehub as hub
import matplotlib.pyplot as plt
from matplotlib.image import imread
import numpy as npdef show_img(img_path, size=8):'''文件读取图片显示'''im = imread(img_path)plt.figure(figsize=(size, size))plt.axis("off")plt.imshow(im)def img_show_bgr(image, size=8):'''cv读取的图片显示'''image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)plt.figure(figsize=(size, size))plt.imshow(image)plt.axis("off")plt.show()pose_estimation = hub.Module(name="human_pose_estimation_resnet50_mpii")
result = pose_estimation.keypoint_detection(paths=['test4.jpg'], visualization=True, output_dir="work/output_pose/")
print(result)def get_true_angel(value):'''转转得到角度值'''return value / np.pi * 180def get_angle(x1, y1, x2, y2):'''计算旋转角度'''dx = abs(x1 - x2)dy = abs(y1 - y2)result_angele = 0if x1 == x2:if y1 > y2:result_angele = 180else:if y1 != y2:the_angle = int(get_true_angel(np.arctan(dx / dy)))if x1 < x2:if y1 > y2:result_angele = -(180 - the_angle)elif y1 < y2:result_angele = -the_angleelif y1 == y2:result_angele = -90elif x1 > x2:if y1 > y2:result_angele = 180 - the_angleelif y1 < y2:result_angele = the_angleelif y1 == y2:result_angele = 90if result_angele < 0:result_angele = 360 + result_angelereturn result_angeledef rotate_bound(image, angle, key_point_y):'''旋转图像,并取得关节点偏移量'''# 获取图像的尺寸(h, w) = image.shape[:2]# 旋转中心(cx, cy) = (w / 2, h / 2)# 关键点必须在中心的y轴上(kx, ky) = cx, key_point_yd = abs(ky - cy)# 设置旋转矩阵M = cv2.getRotationMatrix2D((cx, cy), -angle, 1.0)cos = np.abs(M[0, 0])sin = np.abs(M[0, 1])# 计算图像旋转后的新边界nW = int((h * sin) + (w * cos))nH = int((h * cos) + (w * sin))# 计算旋转后的相对位移move_x = nW / 2 + np.sin(angle / 180 * np.pi) * dmove_y = nH / 2 - np.cos(angle / 180 * np.pi) * d# 调整旋转矩阵的移动距离(t_{x}, t_{y})M[0, 2] += (nW / 2) - cxM[1, 2] += (nH / 2) - cyreturn cv2.warpAffine(image, M, (nW, nH)), int(move_x), int(move_y)def get_distences(x1, y1, x2, y2):return ((x1 - x2) ** 2 + (y1 - y2) ** 2) ** 0.5def append_img_by_sk_points(img, append_img_path, key_point_y, first_point, second_point, append_img_reset_width=None,append_img_max_height_rate=1, middle_flip=False, append_img_max_height=None):'''将需要添加的肢体图片进行缩放'''append_image = cv2.imdecode(np.fromfile(append_img_path, dtype=np.uint8), cv2.IMREAD_UNCHANGED)# 根据长度进行缩放sk_height = int(get_distences(first_point[0], first_point[1], second_point[0], second_point[1]) * append_img_max_height_rate)# 缩放制约if append_img_max_height:sk_height = min(sk_height, append_img_max_height)sk_width = int(sk_height / append_image.shape[0] * append_image.shape[1]) if append_img_reset_width is None else int(append_img_reset_width)if sk_width <= 0:sk_width = 1if sk_height <= 0:sk_height = 1# 关键点映射key_point_y_new = int(key_point_y / append_image.shape[0] * append_image.shape[1])# 缩放图片append_image = cv2.resize(append_image, (sk_width, sk_height))img_height, img_width, _ = img.shape# 是否根据骨骼节点位置在 图像中间的左右来控制是否进行 左右翻转图片# 主要处理头部的翻转, 默认头部是朝左if middle_flip:middle_x = int(img_width / 2)if first_point[0] < middle_x and second_point[0] < middle_x:append_image = cv2.flip(append_image, 1)# 旋转角度angle = get_angle(first_point[0], first_point[1], second_point[0], second_point[1])append_image, move_x, move_y = rotate_bound(append_image, angle=angle, key_point_y=key_point_y_new)app_img_height, app_img_width, _ = append_image.shapezero_x = first_point[0] - move_xzero_y = first_point[1] - move_y(b, g, r) = cv2.split(append_image)for i in range(0, r.shape[0]):for j in range(0, r.shape[1]):if 230 > r[i][j] > 200 and 0 <= zero_y + i < img_height and 0 <= zero_x + j < img_width:img[zero_y + i][zero_x + j] = append_image[i][j]return imgbody_img_path_map = {"right_hip" : "./work/shadow_play_material/right_hip.jpg","right_knee" : "./work/shadow_play_material/right_knee.jpg","left_hip" : "./work/shadow_play_material/left_hip.jpg","left_knee" : "./work/shadow_play_material/left_knee.jpg","left_elbow" : "./work/shadow_play_material/left_elbow.jpg","left_wrist" : "./work/shadow_play_material/left_wrist.jpg","right_elbow" : "./work/shadow_play_material/right_elbow.jpg","right_wrist" : "./work/shadow_play_material/right_wrist.jpg","head" : "./work/shadow_play_material/head.jpg","body" : "./work/shadow_play_material/body.jpg"
}def get_combine_img(img_path, pose_estimation=pose_estimation, body_img_path_map=body_img_path_map,backgroup_img_path='background.jpg'):'''识别图片中的关节点,并将皮影的肢体进行对应,最后与原图像拼接后输出'''result = pose_estimation.keypoint_detection(paths=[img_path])image = cv2.imread(img_path)# 背景图片backgroup_image = cv2.imread(backgroup_img_path)image_flag = cv2.resize(backgroup_image, (image.shape[1], image.shape[0]))# 最小宽度min_width = int(get_distences(result[0]['data']['head_top'][0], result[0]['data']['head_top'][1],result[0]['data']['upper_neck'][0], result[0]['data']['upper_neck'][1]) / 3)# 右大腿append_img_reset_width = max(int(get_distences(result[0]['data']['pelvis'][0], result[0]['data']['pelvis'][1],result[0]['data']['left_hip'][0],result[0]['data']['right_hip'][1]) * 1.6), min_width)image_flag = append_img_by_sk_points(image_flag, body_img_path_map['right_hip'], key_point_y=10,first_point=result[0]['data']['right_hip'],second_point=result[0]['data']['right_knee'],append_img_reset_width=append_img_reset_width)# 右小腿append_img_reset_width = max(int(get_distences(result[0]['data']['pelvis'][0], result[0]['data']['pelvis'][1],result[0]['data']['left_hip'][0],result[0]['data']['right_hip'][1]) * 1.5), min_width)image_flag = append_img_by_sk_points(image_flag, body_img_path_map['right_knee'], key_point_y=10,first_point=result[0]['data']['right_knee'],second_point=result[0]['data']['right_ankle'],append_img_reset_width=append_img_reset_width)# 左大腿append_img_reset_width = max(int(get_distences(result[0]['data']['pelvis'][0], result[0]['data']['pelvis'][1],result[0]['data']['left_hip'][0],result[0]['data']['left_hip'][1]) * 1.6), min_width)image_flag = append_img_by_sk_points(image_flag, body_img_path_map['left_hip'], key_point_y=0,first_point=result[0]['data']['left_hip'],second_point=result[0]['data']['left_knee'],append_img_reset_width=append_img_reset_width)# 左小腿append_img_reset_width = max(int(get_distences(result[0]['data']['pelvis'][0], result[0]['data']['pelvis'][1],result[0]['data']['left_hip'][0],result[0]['data']['left_hip'][1]) * 1.5), min_width)image_flag = append_img_by_sk_points(image_flag, body_img_path_map['left_knee'], key_point_y=10,first_point=result[0]['data']['left_knee'],second_point=result[0]['data']['left_ankle'],append_img_reset_width=append_img_reset_width)# 右手臂image_flag = append_img_by_sk_points(image_flag, body_img_path_map['left_elbow'], key_point_y=25,first_point=result[0]['data']['right_shoulder'],second_point=result[0]['data']['right_elbow'], append_img_max_height_rate=1.2)# 右手肘append_img_max_height = int(get_distences(result[0]['data']['right_shoulder'][0], result[0]['data']['right_shoulder'][1],result[0]['data']['right_elbow'][0], result[0]['data']['right_elbow'][1]) * 1.6)image_flag = append_img_by_sk_points(image_flag, body_img_path_map['left_wrist'], key_point_y=10,first_point=result[0]['data']['right_elbow'],second_point=result[0]['data']['right_wrist'], append_img_max_height_rate=1.5,append_img_max_height=append_img_max_height)# 左手臂image_flag = append_img_by_sk_points(image_flag, body_img_path_map['right_elbow'], key_point_y=25,first_point=result[0]['data']['left_shoulder'],second_point=result[0]['data']['left_elbow'], append_img_max_height_rate=1.2)# 左手肘append_img_max_height = int(get_distences(result[0]['data']['left_shoulder'][0], result[0]['data']['left_shoulder'][1],result[0]['data']['left_elbow'][0], result[0]['data']['left_elbow'][1]) * 1.6)image_flag = append_img_by_sk_points(image_flag, body_img_path_map['right_wrist'], key_point_y=10,first_point=result[0]['data']['left_elbow'],second_point=result[0]['data']['left_wrist'], append_img_max_height_rate=1.5,append_img_max_height=append_img_max_height)# 头image_flag = append_img_by_sk_points(image_flag, body_img_path_map['head'], key_point_y=10,first_point=result[0]['data']['head_top'],second_point=result[0]['data']['upper_neck'], append_img_max_height_rate=1.2,middle_flip=True)# 身体append_img_reset_width = max(int(get_distences(result[0]['data']['left_shoulder'][0], result[0]['data']['left_shoulder'][1],result[0]['data']['right_shoulder'][0], result[0]['data']['right_shoulder'][1]) * 1.2),min_width * 3)image_flag = append_img_by_sk_points(image_flag, body_img_path_map['body'], key_point_y=20,first_point=result[0]['data']['upper_neck'],second_point=result[0]['data']['pelvis'],append_img_reset_width=append_img_reset_width, append_img_max_height_rate=1.2)result_img = np.concatenate((image, image_flag), axis=1)return result_img##pos_img_path = 'test3.jpg'##result_img =  get_combine_img(pos_img_path, pose_estimation, body_img_path_map)
##img_show_bgr(result_img, size=10)input_video = 'work/test.mp4'def transform_video_to_image(video_file_path, img_path):'''将视频中每一帧保存成图片'''video_capture = cv2.VideoCapture(video_file_path)fps = video_capture.get(cv2.CAP_PROP_FPS)count = 0while(True):ret, frame = video_capture.read()if ret:cv2.imwrite(img_path + '%d.jpg' % count, frame)count += 1else:breakvideo_capture.release()print('视频图片保存成功, 共有 %d 张' % count)return fpsfps = transform_video_to_image(input_video, 'work/mp4_img/')def analysis_pose(input_frame_path, output_frame_path, is_print=True):'''分析图片中的人体姿势, 并转换为皮影姿势,输出结果'''file_items = os.listdir(input_frame_path)file_len = len(file_items)for i, file_item in enumerate(file_items):if is_print:print(i+1,'/', file_len, ' ', os.path.join(output_frame_path, file_item))combine_img = get_combine_img(os.path.join(input_frame_path, file_item))cv2.imwrite(os.path.join(output_frame_path, file_item), combine_img)analysis_pose('work/mp4_img/', 'work/mp4_img_analysis/', is_print=False)def combine_image_to_video(comb_path, output_file_path, fps=30, is_print=False):'''合并图像到视频'''fourcc = cv2.VideoWriter_fourcc(*'MP4V')file_items = os.listdir(comb_path)file_len = len(file_items)# print(comb_path, file_items)if file_len > 0:temp_img = cv2.imread(os.path.join(comb_path, file_items[0]))img_height, img_width = temp_img.shape[0], temp_img.shape[1]out = cv2.VideoWriter(output_file_path, fourcc, fps, (img_width, img_height))for i in range(file_len):pic_name = os.path.join(comb_path, str(i) + ".jpg")if is_print:print(i + 1, '/', file_len, ' ', pic_name)img = cv2.imread(pic_name)out.write(img)out.release()combine_image_to_video('work/mp4_img_analysis/', 'work/mp4_analysis.mp4', fps)

实现效果

实现效果视频链接极乐天堂皮影戏

使用飞桨PaddleHub实现将视频动作转化为皮影戏相关推荐

  1. 飞桨PaddleHub实现皮影戏

    飞桨(PaddlePaddle)是集深度学习核心框架.工具组件和服务平台为一体的技术先进.功能完备的开源深度学习平台,已被中国企业广泛使用,深度契合企业应用需求,拥有活跃的开发者社区生态.提供丰富的官 ...

  2. 当飞桨PaddleHub遇到微信小程序,AI也能指物作诗

    点击左上方蓝字关注我们 [飞桨开发者说]刘建建,飞桨开发者,现工作于西部某厂,从事管理工作. 项目构想 最近飞桨PaddleHub大火,吸引无数开发者眼球,作为俗人的我也不例外,被看图写诗和艺术风格迁 ...

  3. Linux系统 安装飞桨PaddleHub+LAC实现词法分析 实现加载自定义词典分词 (解决Lac服务启动报错问题、解决自定义词典空格无法分词问题)

    1.先上链接:飞桨PaddlePaddle-源于产业实践的开源深度学习平台 2.LAC模型简介:Lexical Analysis of Chinese,简称 LAC,是一个联合的词法分析模型,能整体性 ...

  4. WAVE SUMMIT 2022定档520 飞桨又双叒有大动作

    今天,我们面对的是一个充满变动的世界,科技正是一股改变的力量.人工智能拓展了人类看待问题.解决问题的角度,更让很多看似"无解"的难题迎来可触及答案的可能. 2022年的夏至虽尚未至 ...

  5. WAVE SUMMIT 2022 定档520 飞桨又双叒有大动作

    今天,我们面对的是一个充满变动的世界,科技正是一股改变的力量.人工智能拓展了人类看待问题.解决问题的角度,更让很多看似"无解"的难题迎来可触及答案的可能. 2022年的夏至虽尚未至 ...

  6. 一键人物抠图、人物图片背景替换——飞桨PaddleHub实战

    PaddleHub一键抠图并替换背景 抠图模型千千万,而我就用DeepLabv3+.DeepLabv3+ 是Google DeepLab语义分割系列网络的最新作,其前作有 DeepLabv1,Deep ...

  7. 超有范,使用飞桨paddleHub抠图制作任意形状的词云(学习心得)

    文章目录 1 抠图代码 2 抠图效果 3 绘制词云图 4 词云效果图 5 项目链接 链接 1 抠图代码 # 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Als ...

  8. 人脸美颜——飞桨PaddleHub实战

    基于PaddleHub的人脸美颜 随着各种美颜相机的出现,我们可以拍出各种胜似明星的照片,我们可以瘦脸.大眼.红唇以及增白,但这背后是如何实现的,你又了解多少呢? AI美颜核心技术之一就是人脸关键点检 ...

  9. PPDE迎新 | 欢迎18位AI开发者加入飞桨开发者技术专家计划!

    PPDE计划是飞桨开发者技术专家的荣誉认证体系,无论是热爱编程开发的资深程序员.大型技术社区的引领者,还是顶级开源软件的Committer.新兴科技公司创始人或CTO,这些开发者技术专家将通过线上线下 ...

最新文章

  1. VGG16迁移学习实现
  2. c++经典代码大全_宁海檩条C型钢型号大全
  3. android 情景感知 sdk,情景感知服务
  4. 转:【Python3网络爬虫开发实战】6.4-分析Ajax爬取今日头条街拍美图
  5. 每次ubuntu12.04重启后,/etc/resolv.conf被重写为空或127.0.0.1
  6. 异或!!不占用额外空间!!
  7. Sharepoin学习笔记—架构系列—Sharepoint服务(Services)与服务应用程序框架(Service Application Framework) 1
  8. LeetCode 305. 岛屿数量 II(并查集)
  9. mysql 查询倒数第二条记录_MySQL查询倒数第二条记录实现方法
  10. 简化java_JAVA之旅-简化java开发
  11. java设计模式并发_[高并发Java 七] 并发设计模式
  12. golang goroutine协程运行机制及使用详解
  13. python读取word element_Python:通过解析word将文本从docx提取到txt/文档.xm
  14. es6.0 java,es6.0.0源码idea启动问题
  15. 血腥!实况转播SQL注入全过程,让你知道危害有多大。
  16. React生命周期钩子函数
  17. 计算机英特尔显卡在哪找,Win10英特尔显卡设置图标不见了该怎么办 - 系统之家...
  18. 路由器修改wifi密码
  19. jump大乱斗维护服务器,Jump大乱斗常见问题解决方法_Jump大乱斗常见问题解决及按键设置方法_飞翔教程...
  20. 《利用python进行数据分析》读书笔记--第十一章 金融和经济数据应用(一)

热门文章

  1. 谈谈能带来高薪报酬的软件技术有哪些?
  2. QT-局域网电脑远程桌面
  3. PADS-Logic学习笔记
  4. 【算法专题】卡特兰数
  5. 学习LSM(Linux security module)之一:解读yama
  6. linux 在沙盒中运行,Linux容器的细粒度沙盒策略执行方法与流程
  7. Ubuntu下载binutils遇到的问题
  8. 对c++输入输出的一些封装(bushi)
  9. python应聘项目经历怎么写_简历中怎么写「项目经历」最好?为什么?
  10. 怎么查看自己的电脑是几位操作系统?