2

I am working on a human pose prediction project, and I need to plot a human 3D pose skeleton from a numerical dataset, to compare ground truth and predicted values. like this image:

enter image description here

Already I am using this simple code:

ax = plt.axes(projection='3d')
fig = plt.figure()
xdata = np.array(data[values])
ydata = np.array(data[values])
zdata = np.array(data[values])
ax.scatter3D(xdata, ydata, zdata, c=zdata)
plt.show()

but it shows me the points in a 3D plot, I know it isn't correct, So here is the question :

Is there any library or function to call? (Since already I use scatter, and I know it is wrong)

My dataset has 6395 rows and 54 columns, And I am searching for a method to show for example 10 different poses every time or less.

Bilal
  • 3,191
  • 4
  • 21
  • 49
Wishii
  • 43
  • 2
  • 7
  • Please, clarify: 1) have you pairs of dots for each bone? 2) you want 10 3d-plots or 2d projections (without 3d-grid/axes/perspective/interactive...)? 3) you want i.e. 2x5 'table' of subplots or 10 non-overlapping skeletons on one scene? – Daniel Konstantinov Apr 27 '21 at 07:20
  • 1)yes, I have. 2) I want 10 3d-plots. 3) I prefer to have subplots, something similar to 2x5 of subplots, as you said. @DanielKonstantinov – Wishii Apr 27 '21 at 07:25

1 Answers1

1
import typing as tp
import numpy as np
import matplotlib.pyplot as plt


def get_chain_dots(
        dots: np.ndarray,   # shape == (n_dots, 3)
        chain_dots_indexes: tp.List[int], # length == n_dots_in_chain
                                          # in continuous order, i.e. 
                                          # left_hand_ix >>> chest_ix >>> right_hand_ix
        ) -> np.ndarray:    # chain of dots
    """Get continuous chain of dots
    
    chain_dots_indexes - 
        indexes of points forming a continuous chain;
        example of chain: [hand_l, elbow_l, shoulder_l, chest, shoulder_r, elbow_r, hand_r]
    """
    return dots[chain_dots_indexes]


def get_chains(
        dots: np.ndarray,   # shape == (n_dots, 3)
        spine_chain_ixs: tp.List[int], # pelvis >>> chest >>> head
        hands_chain_ixs: tp.List[int], # left_hand >>> chest >>> right_hand
        legs_chain_ixs: tp.List[int]   # left_leg >>> pelvis >>> right_leg
        ):
    return (get_chain_dots(dots, spine_chain_ixs),
            get_chain_dots(dots, hands_chain_ixs),
            get_chain_dots(dots, legs_chain_ixs))


def subplot_nodes(dots: np.ndarray, # shape == (n_dots, 3)
                  ax):
    return ax.scatter3D(*dots.T, c=dots[:, -1])


def subplot_bones(chains: tp.Tuple[np.ndarray, ...], ax):
    return [ax.plot(*chain.T) for chain in chains]


def plot_skeletons(
        skeletons: tp.Sequence[np.ndarray], 
        chains_ixs: tp.Tuple[tp.List[int], tp.List[int], tp.List[int]]):
    fig = plt.figure()
    for i, dots in enumerate(skeletons, start=1):
        chains = get_chains(dots, *chains_ixs)
        ax = fig.add_subplot(2, 5, i, projection='3d')
        subplot_nodes(dots, ax)
        subplot_bones(chains, ax)
    plt.show()


def test():
    """Plot random poses of simplest skeleton"""
    skeletons = np.random.standard_normal(size=(10, 11, 3))
    chains_ixs = ([0, 1, 2, 3, 4],  # hand_l, elbow_l, chest, elbow_r, hand_r
                  [5, 2, 6],        # pelvis, chest, head
                  [7, 8, 5, 9, 10]) # foot_l, knee_l, pelvis, knee_r, foot_r
    plot_skeletons(skeletons, chains_ixs)


if __name__ == '__main__':
    test()

To plot gradient color lines see. And additionally docs.

  • Thank you for the code, I did try to adopt the code with my own dataset. Could you please a little explain about it ? – Wishii Apr 30 '21 at 06:32
  • especially about the value and shape you consider for chains_ixs? – Wishii Apr 30 '21 at 07:26
  • Edited answer for clarity – Daniel Konstantinov Apr 30 '21 at 13:00
  • 1
    @Wishii, plotting chains of bones instead of each separately decreases time of execution and memory utilization, but I suppose it will be difficult to colorize each bone. Of course, you may not use chains, or use Plotly for this purpose, but it's generally resource-intensive (to render 10 3d-scenes), so make sure you want this additional functionality indeed. – Daniel Konstantinov Apr 30 '21 at 13:18