Team Ai
Apppublic

OpenMotionLab/MotionGPT

sourceHugging Facemitupdated 1y agoView on Hugging Face
118likes
anim.py156 linesDownload Raw Back to render
1# Inspired by2# - https://github.com/anindita127/Complextext2animation/blob/main/src/utils/visualization.py3# - https://github.com/facebookresearch/QuaterNet/blob/main/common/visualization.py4 5from typing import List, Tuple6import numpy as np7from mGPT.utils.joints import mmm_kinematic_tree, mmm_to_smplh_scaling_factor8 9mmm_colors = ['black', 'magenta', 'red', 'green', 'blue']10 11 12def init_axis(fig, title, radius=1.5, dist=10):13    ax = fig.add_subplot(1, 1, 1, projection='3d')14    ax.view_init(elev=20., azim=-60)15 16    fact = 217    ax.set_xlim3d([-radius / fact, radius / fact])18    ax.set_ylim3d([-radius / fact, radius / fact])19    ax.set_zlim3d([0, radius])20 21    ax.set_aspect('auto')22    ax.set_xticklabels([])23    ax.set_yticklabels([])24    ax.set_zticklabels([])25 26    ax.set_axis_off()27 28    ax.dist = dist29    ax.grid(b=False)30 31    ax.set_title(title, loc='center', wrap=True)32    return ax33 34 35def plot_floor(ax, minx, maxx, miny, maxy, minz):36    from mpl_toolkits.mplot3d.art3d import Poly3DCollection37    # Plot a plane XZ38    verts = [39        [minx, miny, minz],40        [minx, maxy, minz],41        [maxx, maxy, minz],42        [maxx, miny, minz]43    ]44    xz_plane = Poly3DCollection([verts], zorder=1)45    xz_plane.set_facecolor((0.5, 0.5, 0.5, 1))46    ax.add_collection3d(xz_plane)47 48    # Plot a bigger square plane XZ49    radius = max((maxx - minx), (maxy - miny))50 51    # center +- radius52    minx_all = (maxx + minx) / 2 - radius53    maxx_all = (maxx + minx) / 2 + radius54 55    miny_all = (maxy + miny) / 2 - radius56    maxy_all = (maxy + miny) / 2 + radius57 58    verts = [59        [minx_all, miny_all, minz],60        [minx_all, maxy_all, minz],61        [maxx_all, maxy_all, minz],62        [maxx_all, miny_all, minz]63    ]64    xz_plane = Poly3DCollection([verts], zorder=1)65    xz_plane.set_facecolor((0.5, 0.5, 0.5, 0.5))66    ax.add_collection3d(xz_plane)67    return ax68 69 70def update_camera(ax, root, radius=1.5):71    fact = 272    ax.set_xlim3d([-radius / fact + root[0], radius / fact + root[0]])73    ax.set_ylim3d([-radius / fact + root[1], radius / fact + root[1]])74 75 76def render_animation(joints: np.ndarray, output: str = "notebook", title: str = "",77                     fps: float = 12.5,78                     kinematic_tree: List[List[int]] = mmm_kinematic_tree,79                     colors: List[str] = mmm_colors,80                     figsize: Tuple[int] = (4, 4),81                     fontsize: int = 15):82    import matplotlib.pyplot as plt83    from matplotlib.animation import FuncAnimation84    import matplotlib.patheffects as pe85    plt.rcParams.update({'font.size': fontsize})86 87    # Z is gravity here88    x, y, z = 0, 1, 289 90    # Convert mmm joints for visualization91    # into smpl-h "scale" and axis92    joints = joints.copy()[..., [2, 0, 1]] * mmm_to_smplh_scaling_factor93 94    # Create a figure and initialize 3d plot95    fig = plt.figure(figsize=figsize)96    ax = init_axis(fig, title)97 98    # Create spline line99    trajectory = joints[:, 0, [x, y]]100    avg_segment_length = np.mean(np.linalg.norm(np.diff(trajectory, axis=0), axis=1)) + 1e-3101    draw_offset = int(25 / avg_segment_length)102    spline_line, = ax.plot(*trajectory.T, zorder=10, color="white")103 104    # Create a floor105    minx, miny, _ = joints.min(axis=(0, 1))106    maxx, maxy, _ = joints.max(axis=(0, 1))107    plot_floor(ax, minx, maxx, miny, maxy, 0)108 109    # Put the character on the floor110    height_offset = np.min(joints[:, :, z])  # Min height111    joints = joints.copy()112    joints[:, :, z] -= height_offset113 114    # Initialization for redrawing115    lines = []116    initialized = False117 118    def update(frame):119        nonlocal initialized120        skeleton = joints[frame]121 122        root = skeleton[0]123        update_camera(ax, root)124 125        for index, (chain, color) in enumerate(zip(reversed(kinematic_tree), reversed(colors))):126            if not initialized:127                lines.append(ax.plot(skeleton[chain, x],128                                     skeleton[chain, y],129                                     skeleton[chain, z], linewidth=8.0, color=color, zorder=20,130                                     path_effects=[pe.SimpleLineShadow(), pe.Normal()]))131 132            else:133                lines[index][0].set_xdata(skeleton[chain, x])134                lines[index][0].set_ydata(skeleton[chain, y])135                lines[index][0].set_3d_properties(skeleton[chain, z])136 137        left = max(frame - draw_offset, 0)138        right = min(frame + draw_offset, trajectory.shape[0])139 140        spline_line.set_xdata(trajectory[left:right, 0])141        spline_line.set_ydata(trajectory[left:right, 1])142        spline_line.set_3d_properties(np.zeros_like(trajectory[left:right, 0]))143        initialized = True144 145    fig.tight_layout()146    frames = joints.shape[0]147    anim = FuncAnimation(fig, update, frames=frames, interval=1000 / fps, repeat=False)148 149    if output == "notebook":150        from IPython.display import HTML151        HTML(anim.to_jshtml())152    else:153        anim.save(output, writer='ffmpeg', fps=fps)154 155    plt.close()156