Visitar URL original
Skip tracklet stitching when no animals were detected by C-Achard · Pull Request #3504 · DeepLabCut/DeepLabCut · GitHub
Skip to content
Draft
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
64a2f4e
fix _generate_output_data crash on empty predictions
deruyter92 Sep 8, 2026
510090e
Allow create_df_from_prediction() to handle an empty predictions list.
deruyter92 Sep 8, 2026
4b45fb9
Treat zero predictions as a distinct warning case in `video_inference()`
deruyter92 Sep 8, 2026
c78f439
Don't write dataframe for empty predictions
deruyter92 Sep 9, 2026
16a2977
update test_videos: pop `"PAFinds"` before comparison
deruyter92 Sep 9, 2026
f534de6
update test_videos: assert no DF is written for empty predictions
deruyter92 Sep 9, 2026
624b1b1
Return empty-detection inference results
C-Achard Sep 9, 2026
c57dd35
Use CTD predictions for video output
C-Achard Sep 9, 2026
4e4dab7
Handle empty prediction outputs gracefully
C-Achard Sep 9, 2026
42098ac
Reuse shared frame key width helper
C-Achard Sep 9, 2026
292d068
Clarify video inference warnings
C-Achard Sep 9, 2026
d5ba290
Go back to ValueError for empty predictions
C-Achard Sep 9, 2026
bff4fea
Remove NaN fallback for empty video predictions
C-Achard Sep 9, 2026
06486de
Fix CTD export guard for empty predictions
C-Achard Sep 9, 2026
e456aeb
Clarify empty CTD prediction handling
C-Achard Sep 9, 2026
a162439
Centralize test fakes
C-Achard Sep 9, 2026
11ff4fd
Add test for async with no images
C-Achard Sep 9, 2026
a210b69
Clarify async inference test comment
C-Achard Sep 9, 2026
c7a8c34
Use shared frame key width helper
C-Achard Sep 9, 2026
8c6311e
Skip empty tracklet stitching
C-Achard Sep 9, 2026
5c5c566
Add empty-tracklet regression tests
C-Achard Sep 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Remove NaN fallback for empty video predictions
Simplifies `analyze_videos` by always passing the inference `predictions` directly to `create_df_from_prediction` when `save_as_df` is enabled, and removes the special-case branch that generated all-NaN placeholder rows when no predictions were produced. The unused `_nan_predictions` helper and its warning/error handling were also deleted.
  • Loading branch information
C-Achard committed Sep 9, 2026
commit bff4fea56b11101e9bf4e58ab8af140c087ef022
60 changes: 11 additions & 49 deletions deeplabcut/pose_estimation_pytorch/apis/videos.py
Original file line number Diff line number Diff line change
Expand Up @@ -614,37 +614,21 @@ def analyze_videos(
print("Can't ``save_as_df`` as ``use_shelve=True``. Skipping.")

if not use_shelve:
output_data = _generate_output_data(pose_cfg, predictions) # this should not consume full-NaN frames
output_data = _generate_output_data(pose_cfg, predictions)
with Path(output_pkl).open("wb") as f:
pickle.dump(output_data, f, pickle.HIGHEST_PROTOCOL)

if save_as_df:
df_predictions = predictions
if not df_predictions:
n_frames = video_iterator.get_n_frames(robust=robust_nframes)
logging.warning(
f"No predictions were produced for {video}: writing an "
f"all-NaN results file with {n_frames} row(s) so that "
"downstream steps proceed."
)
df_predictions = _nan_predictions(n_frames, loader.model_cfg)

if not df_predictions:
logging.error(
f"Cannot write a results file for {video}: no predictions "
"were produced and the video reports 0 frames."
)
else:
create_df_from_prediction(
predictions=df_predictions,
multi_animal=multi_animal,
model_cfg=loader.model_cfg,
dlc_scorer=dlc_scorer,
output_path=output_path,
output_prefix=output_prefix,
save_as_csv=save_as_csv,
)
h5_files_created = True
create_df_from_prediction(
predictions=predictions,
multi_animal=multi_animal,
model_cfg=loader.model_cfg,
dlc_scorer=dlc_scorer,
output_path=output_path,
output_prefix=output_prefix,
save_as_csv=save_as_csv,
)
h5_files_created = True # .h5 file was created

if multi_animal:
assemblies_path = output_path / f"{output_prefix}_assemblies.pickle"
Expand Down Expand Up @@ -804,28 +788,6 @@ def create_df_from_prediction(
return df


def _nan_predictions(n_frames: int, model_cfg: dict) -> list[dict[str, np.ndarray]]:
"""Returns placeholder all-NaN predictions, one per frame.

Used when inference produced no predictions at all, so a well-formed results
file with one row per frame is still written and downstream steps (filtering,
labeled videos) keep working.
"""
metadata = model_cfg["metadata"]
num_idv = len(metadata["individuals"])
num_bpts = len(metadata["bodyparts"])
num_unique = len(metadata["unique_bodyparts"])

predictions = []
for _ in range(n_frames):
prediction = dict(bodyparts=np.full((num_idv, num_bpts, 3), np.nan))
if num_unique > 0:
prediction["unique_bodyparts"] = np.full((1, num_unique, 3), np.nan)
predictions.append(prediction)

return predictions


def _generate_assemblies_file(
full_data_path: Path,
output_path: Path,
Expand Down