NTU RGB-D 60 骨架数据集3D可视化

1. 说明

本文是对动作识别、动作预测常见数据集NTU RGB-D 60的3D可视化,运行中可以用鼠标拖动可以查看不同视角,可以保存成GIF图,可以将Gif解析成单帧PNG图片进行进一步处理,可以将所有帧图片凭借成一个整体,实现论文中的美观度。

当然,这个代码适用于所有的骨架数据集,只需要做出一点点修改即可

2. 实现效果

实现的效果如图:
在这里插入图片描述


旋转视角看看:
在这里插入图片描述


解析成单帧图片:

在这里插入图片描述


拼接成一个整体图:
在这里插入图片描述

基本上实现了一些论文中的可视化效果

3. NTU RGB-D 60数据集的3D可视化代码

话不多说,直接上代码:

编写不易,如果对你有帮助的话可以关注、点赞、收藏支持一波,有问题欢迎评论,一定会回复你的

有的人显示不出来可能是版本问题,贴一下我运行的版本:

  • python: 3.8.12
  • pillow(即PIL): 8.4.0
  • matplotlib:3.4.3
  • numpy:·1.21.3
from PIL import Image
import os
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.animation as animation
matplotlib.use('TkAgg')


def create_pose(ax,plots,vals, update=False):
    connect = [
        (1,2),(2,21),(21,3),(3,4), (9,21),
        (9,10),(10,11),(11,12),(12,24),(12,25),
         (1,17), (17,18), (18,19), (19,20), (5, 21),
        (5,6), (6,7), (7,8), (8,22),(8,23),
         (1,13), (13,14),(14,15),(15,16)
        ]
    connect = [(i - 1, j - 1) for (i, j) in connect]

    LR =[
        False, False, False, False, True,
        True, True, True, True, True,
        True, True, True, True, False,
         False, False, False, False, False,
        False,False,False,False
] #这里可以设置哪些骨架是左边,哪些是右边,有时候不准可以全设置为True

# Start and endpoints of our representation
    I   = np.array([touple[0] for touple in connect])
    J   = np.array([touple[1] for touple in connect])

    lcolor = "#9b59b6" #设置骨架颜色,左右颜色
    rcolor = "#2ecc71"

    for i in np.arange( len(I) ):
        x = np.array( [vals[I[i], 0], vals[J[i], 0]] )
        z = np.array( [vals[I[i], 1], vals[J[i], 1]] )
        y = np.array( [vals[I[i], 2], vals[J[i], 2]] )
        if not update:
            plots.append(ax.plot(x, y, z, lw=2,linestyle='-' ,c=lcolor if LR[i] else rcolor))

        elif update:
            plots[i][0].set_xdata(x)
            plots[i][0].set_ydata(y)
            plots[i][0].set_3d_properties(z)
            plots[i][0].set_color(lcolor if LR[i] else rcolor)
    
    return plots
   # ax.legend(loc='lower left')

def update_gt(num, data_gt, plots_gt, fig, ax):
    gt_vals = data_gt[num]
    plots_gt = create_pose(ax, plots_gt, gt_vals, update=True)

    r = 0.75
    xroot, zroot, yroot = gt_vals[0, 0], gt_vals[0, 1], gt_vals[0, 2]
    ax.set_xlim3d([-r + xroot, r + xroot])
    ax.set_ylim3d([-r + yroot, r + yroot])
    ax.set_zlim3d([-r + zroot, r + zroot])

    return plots_gt


def visualize(input ,vision_num, save_path):
    # input dim : t, v, c
    data_gt = input
    print(data_gt.shape)
    fig = plt.figure()
    ax = Axes3D(fig)
    ax.view_init(elev=20, azim=-40) #视角转换

    vals = np.zeros((25, 3)) # or joints_to_consider
    gt_plots=[]

    gt_plots=create_pose(ax,gt_plots,vals,update=False)

    #以下是关于坐标轴的设置,如果需要可以打开
    # ax.set_xlabel("x")
    # ax.set_ylabel("y")
    # ax.set_zlabel("z")
    # ax.legend(loc='lower left')
    # ax.set_xlim3d([-1, 1.5])
    # ax.set_xlabel('X')
    # ax.set_ylim3d([-1, 1.5])
    # ax.set_ylabel('Y')
    # ax.set_zlim3d([0.0, 1.5])
    # ax.set_zlabel('Z')
    # ax.set_title('设置标题')

    line_anim_gt = animation.FuncAnimation(fig, update_gt,vision_num,  fargs=(data_gt,gt_plots,fig,ax),interval=70, blit=False)

    #下面是关闭坐标轴和网格,如果需要可以取消注释,即可去掉坐标轴和网格
    # ax.axis('off') # 关闭坐标轴
    # ax.grid(b=None) #关闭网格

    plt.show()

    gt_name = 'test.gif' #保存名称

    line_anim_gt.save(save_path + '/' + gt_name,writer='pillow')

def get_data(file_name):
    max_V = 25 #节点数
    max_M = 2 #骨架数量
    with open(file_name, 'r') as fr:
        frame_num = int(fr.readline())
        point = np.zeros((3, frame_num, 25, 2))
        for frame in range(frame_num):
            person_num = int(fr.readline())
            for person in range(person_num):
                fr.readline()
                joint_num = int(fr.readline())
                for joint in range(joint_num):
                    v = fr.readline().split(' ')
                    if joint < max_V and person < max_M:
                        point[0,frame,joint,person] = float(v[0])#一个关节的一个坐标
                        point[1,frame,joint,person] = float(v[1])
                        point[2,frame,joint,person] = float(v[2])
    point = point[:,:,:,0] #只取一个人
    # point = np.expand_dims(point, -1)
    return point

def get_gif_imgs(gif_path, save_path):
    """
    提取动图中的每一帧图片,并保存到文件夹中
    """
    new_path = save_path
    gif = Image.open(gif_path)
    try:
        gif.save(f"{new_path}/{gif.tell()}"+"_frame.png")
        while True:
            gif.seek(gif.tell() + 1)
            gif.save(f'{new_path}/{gif.tell()}'+"_frame.png")
    except Exception as e:
        print("处理结束")

if __name__ == '__main__':
    file_name = 'S018C001P008R002A062.skeleton' #设置文件名
    input = get_data(file_name).transpose(1,2,0)
    vision_num = 70 #要可视化多少帧
    print('视频帧数共{}帧,需要可视化{}帧'.format(input.shape[0], vision_num))
    if vision_num > input.shape[0]:
        print('要可视化的帧数大于视频总帧数!')

    save_path = './result'
    if not os.path.exists(save_path):
        os.makedirs(save_path)
    visualize(input, vision_num, save_path)

    #解析gif
    gif_path = save_path + '/' + 'test.gif'
    get_gif_imgs(gif_path, save_path) #将gif解析成每一帧图片

编写不易,转载请注明出处

4. NTU RGB-D 60的 2D简单可视化

请查看我的上一篇博客:如何用Matplotlib优雅地实现NTU-RGB D骨架可视化

5. 联系方式

有问题欢迎邮件联系:
1759412770@qq,com

  • 10
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 20
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

锌a

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值