11.2. Reconstructing occluded markers#

Often in kinematic acquisitions, we affix rigid bodies containing several markers on the person’s segments. These bodies have a minimum of three markers and allows reconstructing a complete local coordinate system for a given body segment. The importance of these rigid bodies will become clearer in the next sections.

It is often useful to have more than three markers on each rigid body, so that in case of occlusion (one marker is hidden and not recorded by the cameras) we can reconstruct its position using the position of every other marker.

Kinetics Toolkit provides an easy way to reconstruct missing markers based on the position of the remaining ones. This is the contents of this section.

11.2.1. Loading sample data#

For this example, we will use a sample of wheelchair propulsion in a moving wheelchair. We will only use the markers of the rigid body called ‘ArmL’.

import matplotlib.pyplot as plt
import numpy as np
import kineticstoolkit.lab as ktk

markers = ktk.read_c3d(
    ktk.doc.download("kinematics_basket_sprint.c3d")
)["Points"]

markers = markers.get_subset(
    ["ArmL:Marker1", "ArmL:Marker2", "ArmL:Marker3", "ArmL:Marker4"]
)

markers = markers.get_ts_between_times(13, 17)

# Plot the markers trajectories

plt.subplot(2, 2, 1)
markers.plot("ArmL:Marker1")
plt.subplot(2, 2, 2)
markers.plot("ArmL:Marker2")
plt.subplot(2, 2, 3)
markers.plot("ArmL:Marker3")
plt.subplot(2, 2, 4)
markers.plot("ArmL:Marker4")
plt.tight_layout()
_images/555b39c0bb2d3ae6a496e6999a938d18a571470dacf5d17cec2d80cf7292872e.png

11.2.2. Marker occlusion#

These data do not have occlusion, and therefore we will fake some. Let simulate that we lost Marker2 from 14.0 to 15.0 seconds, and Marker4 from 14.8 to 15.8 seconds.

markers.data["ArmL:Marker2"][
    (markers.time >= 14.0) & (markers.time <= 15.0)
] = np.nan
markers.data["ArmL:Marker4"][
    (markers.time >= 14.8) & (markers.time <= 15.8)
] = np.nan

# Plot the markers trajectories
plt.subplot(2, 2, 1)
markers.plot("ArmL:Marker1")
plt.subplot(2, 2, 2)
markers.plot("ArmL:Marker2")
plt.subplot(2, 2, 3)
markers.plot("ArmL:Marker3")
plt.subplot(2, 2, 4)
markers.plot("ArmL:Marker4")
plt.tight_layout()
_images/06e7ae12a09aa2c0575f85bbcf48d8d71236b1290b9233b053f1748e89b540b5.png

11.2.3. Create a cluster of markers#

To reconstruct the most that we can from these data, we begin by creating a cluster of markers. A cluster is the fixed, local position of every provided markers expressed in an abritrary, local coordinate system. The ktk.kinematics.create_cluster function is used to create such a cluster. Note that for this function to work, all markers must be visible at the same time at least once.

cluster = ktk.kinematics.create_cluster(
    markers,
    ["ArmL:Marker1", "ArmL:Marker2", "ArmL:Marker3", "ArmL:Marker4"],
)

# Print the contents of the cluster
print(cluster["ArmL:Marker1"])
print(cluster["ArmL:Marker2"])
print(cluster["ArmL:Marker3"])
print(cluster["ArmL:Marker4"])
[[-0.  0.  0.  1.]]
[[ 0.08192236 -0.         -0.          1.        ]]
[[ 0.04729033  0.03960755 -0.          1.        ]]
[[ 0.04756577 -0.03164345 -0.00904679  1.        ]]

11.2.4. Track the cluster to reconstruct the missing markers#

Now that we know how each marker is positioned relative to each other, we can use this cluster to reconstruct the missing marker positions.

reconstructed_markers = ktk.kinematics.track_cluster(markers, cluster)

# Plot the markers trajectories
plt.subplot(2, 2, 1)
reconstructed_markers.plot("ArmL:Marker1")
plt.subplot(2, 2, 2)
reconstructed_markers.plot("ArmL:Marker2")
plt.subplot(2, 2, 3)
reconstructed_markers.plot("ArmL:Marker3")
plt.subplot(2, 2, 4)
reconstructed_markers.plot("ArmL:Marker4")
plt.tight_layout()
_images/1059706812d83a47d43cd1658f9ad311d054d4911e888f21d6d8e2fe3744980f.png

As we see, most of the missing data from Marker2 and Marker4 were reconstructed. Only the zone between 14.8 and 15.0 seconds could not, because only two markers were visible at that time. We also note that missing data appeared in the reconstructed markers 1 and 3, whereas no data was missing before. It is important to understand that the reconstructed marker positions are not the original marker positions, plus the reconstructed data. They are all new data, generated by the process of fitting a rigid cluster on available marker positions. Since only two markers were available between 14.8 and 15.0 seconds, then the cluster could not be fitted and therefore, no reconstructed marker can be obtained.