AI实现皮影戏,传承正在消失的艺术
收藏
快速回复
AI Studio平台使用 文章Notebook项目 6506 38
AI实现皮影戏,传承正在消失的艺术
收藏
快速回复
AI Studio平台使用 文章Notebook项目 6506 38

一、项目背景
领略千年皮影戏魅力,传承正在消失的艺术, 皮影戏的神奇,在于小小皮影在指尖上飞舞,时而刀光剑影、时而策马扬鞭、时而缠绵悱恻,千军万马是他,单打独斗也是他。皮影戏可谓是闻名中外,它是把光影声色做到极致的一门古老艺术。


先辈门通过手艺演绎着皮影戏,同样我们也可以通过AI方式来实现。为了实现皮影戏,可以通过PaddleHub提供的人体骨骼关键点检测库完成将人体姿态检测,同时映射到皮影身上,让皮影动起来。

二、效果展示
根据PaddleHub完成人体骨骼关键点检测教程,我们通过人体骨骼关键点可以获取人体的动作,在加上皮影的肢体,我们就可以实现“皮影戏”效果,最终效果见下方:

可以识别单张图片,左边是原始图片,右边就是我们实现皮影效果:


当然实现单张图片之后,我们就可以识别视频中的人物,让皮影动起来! 我找了b站上一个可爱的小姐姐进行转换,效果如下:

NOTE: 目前帖子里面不能上传gif动态图,希望看图的小伙伴可以,到项目地址https://aistudio.baidu.com/aistudio/projectdetail/764130 需要首先fork该项目示例。之后按照该示例操作即可。

三、实现步骤
1. 安装依赖库
PaddleHub 的人体骨骼关键点检测库 官方地址

! hub install human_pose_estimation_resnet50_mpii==1.1.1

# 测试是否安装成功
! hub run human_pose_estimation_resnet50_mpii --input_path "work/imgs/body01.jpg" --visualization True --output_dir "work/output_pose"

 2. 目录和资源
所有资源在work目录下work/imgs 目录下是从网上找的图片资源
- work/output_pose 是人体骨骼关键点识别后的图片目录
- work/img_change 是皮影的素材图片
- work/mp4_img 是视频导出的图片
- work/mp4_img_analysis 视频图片分析结果

3. 查看单张图片的人体骨骼关键点检测效果

import os
import cv2
import paddlehub as hub
import matplotlib.pyplot as plt
from matplotlib.image import imread
import numpy as np
%matplotlib inline

def 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() 


show_img('work/imgs/body01.jpg')

 

#通过代码获取图片中的结果
pose_estimation = hub.Module(name="human_pose_estimation_resnet50_mpii")
result = pose_estimation.keypoint_detection(paths=['work/imgs/body01.jpg'], visualization=True, output_dir="work/output_pose/")

show_img('work/output_pose/body01.jpg')

 

4. 实现思路
要实现皮影戏的效果我们首先要解析,人体各个骨骼关键点的位置信息,通过关节点的信息计算皮影的肢体位置,和旋转方向,从而达到肢体同步。

1. 首先解析某个部位骨骼关键点的,这里以手臂进行举例: 

    通过PaddleHub中解析结果,获取手臂具体位置,我们可以通过肩膀(shoulder)和肘(elbow)得到,那么就可以获取对应的坐标点信息

2. 通过2个骨骼关键点确认肢体的长度和旋转角度,并将其映射到肢体素材中。

3. 将得到各个肢体变换后,合并到背景图像中进行输出。
了解完实现思路后,我们就可以开始动手实践了

def get_true_angel(value):
    '''
    转转得到角度值
    '''
    return value/np.pi*180
def get_angle(x1, y1, x2, y2):
    '''
    计算旋转角度
    '''
    dx = abs(x1- x2)
    dy = abs(y1- y2)
    result_angele = 0
    if x1 == x2:
        if y1 > y2:
            result_angele = 180
    else:
        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 x2:
            if y1>y2:
                result_angele = 180 - the_angle
            elif y1
def rotate_bound(image, angle, key_point_y):
    '''
    旋转图像,并取得关节点偏移量
    '''
    #获取图像的尺寸
    #旋转中心
    (h,w) = image.shape[:2]
    (cx,cy) = (w/2,h/2)
    # 关键点必须在中心的y轴上
    (kx,ky) = cx, key_point_y
    d = abs(ky - cy)
    
    move_x = 0
    move_y = 0

    if angle == 90:
        move_x = d
        move_y = cy - ky
    elif angle == 180:
        move_x = 0
        move_y = cy + d
    elif angle == 270:
        move_x = -d
        move_y = d
    else:
        move_x =  np.sin(angle/180*np.pi)*d
        move_y = d - np.cos(angle/180*np.pi)*d
    
    
    #设置旋转矩阵
    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))
    
    # 调整旋转矩阵的移动距离(t_{x}, t_{y})
    M[0,2] += (nW/2) - cx
    M[1,2] += (nH/2) - cy

    return 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, key_point_y_new_move_up_rate=1, move_x_sk_width_rate=0):
    '''
    将需要添加的肢体图片进行缩放
    '''
    append_image = cv2.imdecode(np.fromfile(append_img_path, dtype=np.uint8), cv2.IMREAD_UNCHANGED)

    # 根据长度进行缩放
    sk_height = int(np.sqrt((first_point[1] - second_point[1])**2 + (first_point[0] - second_point[0])**2)*append_img_max_height_rate)
    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 = 1
    if 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))

    # 旋转角度
    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)

    zero_x = int(first_point[0] - sk_width/2) - move_x + int(sk_width*move_x_sk_width_rate)
    zero_y = first_point[1] - int(key_point_y_new*key_point_y_new_move_up_rate) - move_y

    max_height, max_width, _ = img.shape
    (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
....

由于发布帖子单次添加代码长度限制,显示不全,具体代码小伙伴们还是到项目地址 https://aistudio.baidu.com/aistudio/projectdetail/764130 进行查看吧

5. 让皮影动起来
具体实现步骤如下:

  1.首先我们需要获取视频需要各位自行下载,本教程已经下载好(work/001.mp4)
  2. 将视频中每一帧保存成图片
  3.分析图片中的人体姿势, 并转换为皮影姿势,输出结果
  4.合并图像到视频,得到最终的结果

 

def transform_video_to_image(video_file_path, img_path):
    '''
    将视频中每一帧保存成图片
    '''
    video_capture = cv2.VideoCapture(video_file_path)
    count = 0
    while(True):
        ret, frame = video_capture.read() 
        if ret:
            cv2.imwrite(img_path + '%d.jpg' % count, frame)
            count += 1
        else:
            break
    video_capture.release()
    print('视频图片保存成功, 共有 %d 张' % count)



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,'/', 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)


def combine_image_to_video(comb_path, output_file_path, is_print=False):
    '''
        合并图像到视频
    '''
    fourcc = cv2.VideoWriter_fourcc(*'MP4V')    
    
    file_items = os.listdir(comb_path)
    file_len = len(file_items)
    
    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, 30, (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,'/', file_len, ' ', pic_name)
        img = cv2.imread(pic_name)
        out.write(img)
    out.release()


# 将视频中每一帧保存成图片
transform_video_to_image('work/001.mp4', 'work/mp4_img/')
# 分析图片中的人体姿势, 并转换为皮影姿势,输出结果
analysis_pose('work/mp4_img/', 'work/mp4_img_analysis/', is_print=False)
# 合并图像到视频
combine_image_to_video('work/mp4_img_analysis/', 'work/mp4_analysis.mp4')

最后的最后我们得到动起来的皮影戏了!!! 

 

6. 总结
本文在弘扬传统文化同时,能让读者学习AI知识,体会到 PaddleHub 的强大, 可谓一举两得!

后续版本会考虑让皮影的动作更贴合人体姿态,整体视觉效果上更好!!!

来AI Studio互粉吧,来互关呀~,~等你哦~ https://aistudio.baidu.com/aistudio/personalcenter/thirdview/331031

欢迎大家fork喜欢评论三连,感兴趣的朋友也可互相关注一下啊~

4
收藏
回复
全部评论(38)
时间顺序
aaaaaa
#2 回复于2020-08

0
回复
thinc
#3 回复于2020-08

6...6666666

0
回复
AIStudio810260
#4 回复于2020-08

666666,赶紧到置顶帖投个稿呀

0
回复
Mr.郑先生_
#5 回复于2020-08

哇塞!这个太有意思了!

0
回复
半岛铁盒
#6 回复于2020-08

这也太厉害了吧

0
回复
乌拉__----
#7 回复于2020-08

666666666666

0
回复
exemal
#8 回复于2020-08

这个厉害了!

0
回复
老师-8
#9 回复于2020-08

666

0
回复
Zohar
#10 回复于2020-09

欢迎大家到项目页面 点赞/Fork,呵呵!

0
回复
Mr.郑先生_
#11 回复于2020-09
Zohar #10
欢迎大家到项目页面 点赞/Fork,呵呵!

必须的,来了哈哈哈

0
回复
AIStudio810258
#12 回复于2020-09

非常酷的项目~~

0
回复
AIStudio810258
#13 回复于2020-09

可以放我们城市展览馆

0
回复
AIStudio810258
#14 回复于2020-09

有一个皮影流派就是我们这里的,哈哈

0
回复
AIStudio810258
#15 回复于2020-09

前好几年的春晚,我们这还派出一组老大姨们真人表演皮影来着~~

0
回复
Zohar
#16 回复于2020-09
Zohar #10
欢迎大家到项目页面 点赞/Fork,呵呵!

哈哈,过奖了,班门弄斧,和你们的项目差远了~~

0
回复
Zohar
#17 回复于2020-09
前好几年的春晚,我们这还派出一组老大姨们真人表演皮影来着~~

看来皮影的文化还在老一辈人手里传承着呢!

0
回复
thinc
#18 回复于2020-09
Zohar #17
看来皮影的文化还在老一辈人手里传承着呢!

得有更多年轻人去学才能把这些技术传承下来

0
回复
thinc
#19 回复于2020-09
前好几年的春晚,我们这还派出一组老大姨们真人表演皮影来着~~

真人表演皮影~~真皮~~~哈哈哈 想看看

0
回复
七年期限
#20 回复于2020-09

超级帅

0
回复
AIStudio810258
#21 回复于2020-09
Zohar #17
看来皮影的文化还在老一辈人手里传承着呢!

我闺女小时候以为这是动画片,哈哈

0
回复
在@后输入用户全名并按空格结束,可艾特全站任一用户