Skip to content

Commit 472caac

Browse files
authored
Merge branch 'main' into arash_and_jaap/uv_packaging
2 parents becf03a + 3d4da2e commit 472caac

8 files changed

Lines changed: 677 additions & 4 deletions

File tree

_toc.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ parts:
7777
- file: docs/recipes/OpenVINO
7878
- file: docs/recipes/flip_and_rotate
7979
- file: docs/recipes/pose_cfg_file_breakdown
80+
- file: docs/recipes/fmpose3d
8081
- file: docs/recipes/publishing_notebooks_into_the_DLC_main_cookbook
8182

8283
- caption: Hardware Tips
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# FMPose3D
2+
3+
## Overview
4+
5+
**FMPose3D** is a monocular 3D pose estimation library that lifts 2D keypoints from images into 3D poses using *flow matching* — a generative modeling technique based on ODE sampling. It supports two pipelines:
6+
7+
- **Human pose estimation** — Uses HRNet + YOLO for 2D detection (17 H36M joints), then a flow-matching 3D lifter with optional flip test-time augmentation and camera-to-world transformation.
8+
- **Animal pose estimation** — Uses DeepLabCut SuperAnimal for 2D detection (26 Animal3D joints), then a flow-matching 3D lifter with limb regularization post-processing.
9+
10+
Model weights are hosted on HuggingFace Hub and are downloaded automatically when no local path is provided. The library is installable via `pip install fmpose3d` and requires Python >= 3.8.
11+
12+
For a full overview and documentation on the API, see https://github.com/AdaptiveMotorControlLab/FMPose3D.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
"""
2+
DeepLabCut2.0-3.0 Toolbox (deeplabcut.org)
3+
© A. & M. Mathis Labs
4+
https://github.com/DeepLabCut/DeepLabCut
5+
Please see AUTHORS for contributors.
6+
https://github.com/DeepLabCut/DeepLabCut/blob/main/AUTHORS
7+
Licensed under GNU Lesser General Public License v3.0
8+
"""
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"""
2+
DeepLabCut2.0-3.0 Toolbox (deeplabcut.org)
3+
© A. & M. Mathis Labs
4+
https://github.com/DeepLabCut/DeepLabCut
5+
Please see AUTHORS for contributors.
6+
https://github.com/DeepLabCut/DeepLabCut/blob/main/AUTHORS
7+
Licensed under GNU Lesser General Public License v3.0
8+
"""
9+
10+
from fmpose3d import (
11+
FMPose3DInference,
12+
FMPose3DConfig,
13+
SupportedModel,
14+
)
15+
16+
17+
def get_fmpose3d_inference_api(
18+
model_type: SupportedModel = "fmpose3d_humans",
19+
snapshot_path: str | None = None,
20+
device: str | None = None,
21+
config_kwargs: dict = {},
22+
) -> FMPose3DInference:
23+
"""
24+
Get a FMPose3DInference API for a given model type and snapshot path.
25+
26+
Args:
27+
model_type: one of the supported model types: "fmpose3d_humans", "fmpose3d_animals",
28+
snapshot_path: The path to the snapshot file. If None, FMPose3D will download the default snapshot.
29+
device: The device to use. If None, the device will be inferred from the environment.
30+
config_kwargs: Additional keyword arguments to pass to the FMPose3DConfig.
31+
Returns:
32+
FMPose3DInference: An FMPose3DInference API runner.
33+
34+
Example Usages
35+
```python
36+
# Initialize the API (downloads the default weights automatically from huggingface)
37+
fmpose = get_fmpose3d_inference_api(
38+
model_type="fmpose3d_animals",
39+
device="cuda:0",
40+
)
41+
42+
# Run inference on an image
43+
predictions_3d = fmpose.predict(source="path/to/image.jpg") # or (H, W, 3) numpy array
44+
45+
# Lift 2d predictions to 3d
46+
keypoints_2d = np.random.rand(num_frames, num_joints, 2)
47+
predictions_3d = fmpose.pose_3d(keypoints_2d=keypoints_2d)
48+
```
49+
"""
50+
model_config = FMPose3DConfig(model_type=model_type, **config_kwargs)
51+
fmpose3d_api = FMPose3DInference(
52+
model_config,
53+
model_weights_path=snapshot_path,
54+
device=device
55+
)
56+
return fmpose3d_api

deeplabcut/pose_estimation_pytorch/runners/shelving.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,15 +124,13 @@ def add_prediction(
124124
scores = [bpt[:, 2:3] for bpt in bodyparts]
125125

126126
# full pickle has bodyparts and unique bodyparts in same array
127-
unique_bodyparts = kwargs.get("unique_bodyparts", None)
128127
if unique_bodyparts is not None:
129128
unique_bpts = unique_bodyparts.transpose((1, 0, 2))
130129
coordinates += [bpt[:, :2] for bpt in unique_bpts]
131130
scores += [bpt[:, 2:] for bpt in unique_bpts]
132131

133132
output = dict(coordinates=(coordinates,), confidence=scores, costs=None)
134133

135-
identity_scores = kwargs.get("identity_scores", None)
136134
if identity_scores is not None:
137135
# Reshape id scores from (num_assemblies, num_bpts, num_individuals)
138136
# to the original DLC full pickle format: (num_bpts, num_assem, num_ind)
@@ -151,9 +149,12 @@ def add_prediction(
151149
self._frame_index += 1
152150

153151
def close(self) -> None:
154-
"""Opens the shelf"""
152+
"""Closes the shelf and writes the updated metadata"""
155153
if self._open and self._frame_index > 0:
156-
self._db["metadata"]["nframes"] = self._frame_index
154+
# Write updated metadata to shelf (top-level indexing required for shelve)
155+
metadata = self._db["metadata"]
156+
metadata["nframes"] = self._frame_index
157+
self._db["metadata"] = metadata
157158

158159
super().close()
159160

0 commit comments

Comments
 (0)