Visitar URL original
update `list_videos_in_folder` by deruyter92 · Pull Request #3303 · DeepLabCut/DeepLabCut · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
2d41bee
Update `list_video_files_in_folder` only filter explicitly provided f…
deruyter92 May 4, 2026
96e31be
add test for list_videos_in_folder
deruyter92 May 4, 2026
3c63e90
Add deprecation utils: decorator for deprecated functions
deruyter92 May 7, 2026
b92103e
move `list_videos_in_folder` to `collect_video_paths` in auxfun_video…
deruyter92 May 7, 2026
ee4d9b1
export `deeplabcut.collect_video_paths(..)` from auxfun_videos.py
deruyter92 May 8, 2026
2014a59
update `collect_video_paths`: add exclude patterns
deruyter92 May 8, 2026
f6f1ee5
deprecate auxfun `get_list_of_videos` in favor of `collect_video_paths`
deruyter92 May 8, 2026
f6b33d2
add pytest deprecation marker `test_get_list_of_videos`
deruyter92 May 8, 2026
659bf7d
Mark `get_video_list` as deprecated (keep for now for backward compat…
deruyter92 May 8, 2026
983951d
fix test_collect_video_paths: rename keyword -> extensions
deruyter92 May 8, 2026
7d71306
Adjust `extensions` parameter: flexibly coerce str / list / tuple ->…
deruyter92 May 8, 2026
bce0ba9
Merge branch 'main' into jaap/update_list_videos_in_folder
C-Achard May 12, 2026
adadf08
`collect_video_paths`: sort videos if shuffle=False
deruyter92 May 12, 2026
ce8bcf5
update docstring non-recursive directory scanning.
deruyter92 May 12, 2026
75a4d0a
update collect_video_paths: DEFAULT_EXCLUDE_PATTERNS
deruyter92 May 12, 2026
481d3fa
update _coerce_extensions: only "" and None normalize to None
deruyter92 May 12, 2026
8ca9b49
fix instance check in _coerce_video_extensions
deruyter92 May 12, 2026
39557ec
fix pytest: assert alphabetic ordering if shuffle=False
deruyter92 May 12, 2026
39cfd94
fix empty string case in _coerce_extensions
deruyter92 May 12, 2026
77a05dc
Add structured deprecation info and warnings (#3326)
C-Achard May 12, 2026
5610a49
Merge branch 'main' into jaap/update_list_videos_in_folder
C-Achard May 13, 2026
792d35d
guarantee unchanged behavior for deprecated `get_list_of_videos` and …
deruyter92 May 13, 2026
fe38152
add warning if still unsupported extensions encountered
deruyter92 May 13, 2026
69981f1
Consequently adjust `videotype` signatures of collect_video_path callers
deruyter92 May 15, 2026
096973e
refactor collect_video_paths: add warnings, raise for empty sequence.
deruyter92 May 15, 2026
0929e7b
update tests for collect_video_paths
deruyter92 May 15, 2026
996b220
Merge branch 'main' into jaap/update_list_videos_in_folder
MMathisLab May 15, 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
1 change: 1 addition & 0 deletions deeplabcut/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
DownSampleVideo,
ShortenVideo,
check_video_integrity,
collect_video_paths,
)

# -----------------------------------------------------------------------------
Expand Down
44 changes: 28 additions & 16 deletions deeplabcut/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

from __future__ import annotations

from collections.abc import Iterable
from collections.abc import Iterable, Sequence
from pathlib import Path

import numpy as np
Expand Down Expand Up @@ -664,7 +664,7 @@ def return_evaluate_network_data(
def analyze_videos(
config: str,
videos: list[str],
videotype: str = "",
videotype: str | Sequence[str] | None = None,
shuffle: int = 1,
trainingsetindex: int = 0,
gputouse: str | None = None,
Expand Down Expand Up @@ -710,10 +710,14 @@ def analyze_videos(
A list of strings containing the full paths to videos for analysis or a path to
the directory, where all the videos with same extension are stored.

videotype: str, optional, default=""
Checks for the extension of the video in case the input to the video is a
directory. Only videos with this extension are analyzed. If left unspecified,
videos with common extensions ('avi', 'mp4', 'mov', 'mpeg', 'mkv') are kept.
videotype : str | Sequence[str] | None, optional, default=None
Controls how ``videos`` are filtered, based on file extension.
File paths and directory contents are treated differently:
- ``None`` (default): file paths are accepted as-is; directories are
scanned for files with a recognized video extension.
- ``str`` or ``Sequence[str]`` (e.g. ``"mp4"`` or ``["mp4", "avi"]``):
both file paths and directory contents are filtered by the given
extension(s).

shuffle: int, optional, default=1
An integer specifying the shuffle index of the training dataset used for
Expand Down Expand Up @@ -986,7 +990,7 @@ def create_tracking_dataset(
config: str,
videos: list[str],
track_method: str,
videotype: str = "",
videotype: str | Sequence[str] | None = None,
shuffle: int = 1,
trainingsetindex: int = 0,
gputouse: int | None = None,
Expand Down Expand Up @@ -1015,10 +1019,14 @@ def create_tracking_dataset(
Specifies the tracker used to generate the pose estimation data. Must be either
'box', 'skeleton', or 'ellipse'.

videotype: str, optional, default=""
Checks for the extension of the video in case the input to the video is a
directory. Only videos with this extension are analyzed. If left unspecified,
videos with common extensions ('avi', 'mp4', 'mov', 'mpeg', 'mkv') are kept.
videotype : str | Sequence[str] | None, optional, default=None
Controls how ``videos`` are filtered, based on file extension.
File paths and directory contents are treated differently:
- ``None`` (default): file paths are accepted as-is; directories are
scanned for files with a recognized video extension.
- ``str`` or ``Sequence[str]`` (e.g. ``"mp4"`` or ``["mp4", "avi"]``):
both file paths and directory contents are filtered by the given
extension(s).

shuffle: int, optional, default=1
An integer specifying the shuffle index of the training dataset used for
Expand Down Expand Up @@ -1408,7 +1416,7 @@ def analyze_time_lapse_frames(
def convert_detections2tracklets(
config: str,
videos: list[str],
videotype: str = "",
videotype: str | Sequence[str] | None = None,
shuffle: int = 1,
trainingsetindex: int = 0,
overwrite: bool = False,
Expand All @@ -1435,10 +1443,14 @@ def convert_detections2tracklets(
A list of strings containing the full paths to videos for analysis or a path to the directory,
where all the videos with same extension are stored.

videotype: string, optional
Checks for the extension of the video in case the input to the video is a directory.\n
Only videos with this extension are analyzed.
If left unspecified, videos with common extensions ('avi', 'mp4', 'mov', 'mpeg', 'mkv') are kept.
videotype : str | Sequence[str] | None, optional, default=None
Controls how ``videos`` are filtered, based on file extension.
File paths and directory contents are treated differently:
- ``None`` (default): file paths are accepted as-is; directories are
scanned for files with a recognized video extension.
- ``str`` or ``Sequence[str]`` (e.g. ``"mp4"`` or ``["mp4", "avi"]``):
both file paths and directory contents are filtered by the given
extension(s).

shuffle: int, optional
An integer specifying the shuffle index of the training dataset used for training the network. T
Expand Down
17 changes: 11 additions & 6 deletions deeplabcut/pose_estimation_pytorch/apis/tracking_dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#
"""Code to create tracking datasets for ReID model training."""

from collections.abc import Sequence
from pathlib import Path

from tqdm import tqdm
Expand All @@ -24,6 +25,7 @@
from deeplabcut.pose_estimation_pytorch.apis.videos import VideoIterator
from deeplabcut.pose_estimation_pytorch.task import Task
from deeplabcut.pose_tracking_pytorch import create_triplets_dataset
from deeplabcut.utils.auxfun_videos import collect_video_paths


def build_feature_extraction_runner(
Expand Down Expand Up @@ -127,7 +129,7 @@ def create_tracking_dataset(
config: str,
videos: list[str] | list[Path],
track_method: str,
videotype: str = "",
videotype: str | Sequence[str] | None = None,
shuffle: int = 1,
trainingsetindex: int = 0,
destfolder: str | None = None,
Expand All @@ -147,10 +149,13 @@ def create_tracking_dataset(
the videos with same extension are stored.
track_method: Specifies the tracker used to generate the pose estimation data.
Must be either 'box', 'skeleton', or 'ellipse'.
videotype: Checks for the extension of the video in case the input to the video
is a directory. Only videos with this extension are analyzed. If left
unspecified, keeps videos with extensions ('avi', 'mp4', 'mov', 'mpeg',
'mkv').
videotype: Controls how ``videos`` are filtered, based on file extension.
File paths and directory contents are treated differently:
- ``None`` (default): file paths are accepted as-is; directories are
scanned for files with a recognized video extension.
- ``str`` or ``Sequence[str]`` (e.g. ``"mp4"`` or ``["mp4", "avi"]``):
both file paths and directory contents are filtered by the given
extension(s).
shuffle: An integer specifying the shuffle index of the training dataset used
for training the network.
trainingsetindex: Integer specifying which TrainingsetFraction to use.
Expand Down Expand Up @@ -240,7 +245,7 @@ def create_tracking_dataset(
modelprefix=modelprefix,
)

videos = utils.list_videos_in_folder(videos, videotype)
videos = collect_video_paths(videos, extensions=videotype)
for video_path in videos:
print(f"Loading {video_path}")
video = VideoIterator(video_path, cropping=cropping)
Expand Down
10 changes: 6 additions & 4 deletions deeplabcut/pose_estimation_pytorch/apis/tracklets.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import os
import pickle
import warnings
from collections.abc import Sequence
from pathlib import Path

import numpy as np
Expand All @@ -26,16 +27,16 @@
from deeplabcut.core.inferenceutils import Assembly
from deeplabcut.pose_estimation_pytorch.apis.utils import (
get_scorer_name,
list_videos_in_folder,
parse_snapshot_index_for_analysis,
)
from deeplabcut.pose_estimation_pytorch.data.dlcloader import DLCLoader
from deeplabcut.utils.auxfun_videos import collect_video_paths


def convert_detections2tracklets(
config: str,
videos: str | list[str],
videotype: str | None = None,
videotype: str | Sequence[str] | None = None,
shuffle: int = 1,
trainingsetindex: int = 0,
overwrite: bool = False,
Expand Down Expand Up @@ -124,9 +125,10 @@ def convert_detections2tracklets(
modelprefix=modelprefix,
)

videos = list_videos_in_folder(videos, videotype)
paths_input = videos
videos = collect_video_paths(videos, extensions=videotype)
if len(videos) == 0:
print(f"No videos were found in {videos}")
print(f"No videos were found in {paths_input}")
return

for video in videos:
Expand Down
53 changes: 11 additions & 42 deletions deeplabcut/pose_estimation_pytorch/apis/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
from __future__ import annotations

import logging
import random
from collections.abc import Callable
from collections.abc import Callable, Sequence
from pathlib import Path

import albumentations as A
Expand Down Expand Up @@ -65,7 +64,9 @@
)
from deeplabcut.pose_estimation_pytorch.task import Task
from deeplabcut.pose_estimation_pytorch.utils import resolve_device
from deeplabcut.utils import auxfun_videos, auxiliaryfunctions
from deeplabcut.utils import auxiliaryfunctions
from deeplabcut.utils.auxfun_videos import SUPPORTED_VIDEOS, collect_video_paths
from deeplabcut.utils.deprecation import deprecated


def parse_snapshot_index_for_analysis(
Expand Down Expand Up @@ -293,49 +294,17 @@ def get_scorer_name(
return f"DLC_{name}_{task}{date}shuffle{shuffle}_{snapshot_uid}"


@deprecated(replacement="deeplabcut.collect_video_paths", since="3.0.0")
def list_videos_in_folder(
data_path: str | Path | list[str | Path],
video_type: str | None = None,
video_type: str | Sequence[str] | None = SUPPORTED_VIDEOS,
shuffle: bool = False,
) -> list[Path]:
"""
Args:
data_path: Path or list of paths to folders containing videos, or individual
video files. Can be a mix of directories and files.
video_type: The type of video to filter for (e.g., "mp4", ".mp4"). If None,
all supported video types are included.
shuffle: Whether to shuffle the order of videos. If False, videos are returned
in sorted order for deterministic behavior.

Returns:
The paths of videos to analyze. Duplicate paths are removed.

Raises:
FileNotFoundError: If any path in data_path does not exist.
"""
if isinstance(data_path, (str, Path)):
data_path = [data_path]

if not video_type:
video_suffixes = {f".{ext.lower()}" for ext in auxfun_videos.SUPPORTED_VIDEOS}
else:
video_suffixes = {f".{video_type.lstrip('.').lower()}"}

videos = []
for path in map(Path, data_path):
if not path.exists():
raise FileNotFoundError(f"Could not find: {path}. Check access rights.")

if path.is_dir():
videos.extend(f for f in path.iterdir() if f.is_file() and f.suffix.lower() in video_suffixes)
elif path.is_file() and path.suffix.lower() in video_suffixes:
videos.append(path)

# Resolve video paths and remove duplicates
unique_videos = list(dict.fromkeys(v.resolve() for v in videos))
if shuffle:
random.shuffle(unique_videos)
return unique_videos
return collect_video_paths(
data_path=data_path,
extensions=video_type,
shuffle=shuffle,
)


def ensure_multianimal_df_format(df_predictions: pd.DataFrame) -> pd.DataFrame:
Expand Down
16 changes: 11 additions & 5 deletions deeplabcut/pose_estimation_pytorch/apis/videos.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import logging
import pickle
import time
from collections.abc import Sequence
from pathlib import Path
from typing import Any

Expand Down Expand Up @@ -44,6 +45,7 @@
from deeplabcut.pose_estimation_pytorch.task import Task
from deeplabcut.refine_training_dataset.stitch import stitch_tracklets
from deeplabcut.utils import VideoReader, auxiliaryfunctions
from deeplabcut.utils.auxfun_videos import collect_video_paths


class VideoIterator(VideoReader):
Expand Down Expand Up @@ -242,7 +244,7 @@ def video_inference(
def analyze_videos(
config: str,
videos: str | list[str],
videotype: str | None = None,
videotype: str | Sequence[str] | None = None,
shuffle: int = 1,
trainingsetindex: int = 0,
save_as_csv: bool = False,
Expand Down Expand Up @@ -282,9 +284,13 @@ def analyze_videos(
videos: a str (or list of strings) containing the full paths to videos for
analysis or a path to the directory, where all the videos with same
extension are stored.
videotype: checks for the extension of the video in case the input to the video
is a directory. Only videos with this extension are analyzed. If left
unspecified, keeps videos with extensions ('avi', 'mp4', 'mov', 'mpeg', 'mkv').
videotype: Controls how ``videos`` are filtered, based on file extension.
File paths and directory contents are treated differently:
- ``None`` (default): file paths are accepted as-is; directories are
scanned for files with a recognized video extension.
- ``str`` or ``Sequence[str]`` (e.g. ``"mp4"`` or ``["mp4", "avi"]``):
both file paths and directory contents are filtered by the given
extension(s).
shuffle: An integer specifying the shuffle index of the training dataset used for
training the network.
trainingsetindex: Integer specifying which TrainingsetFraction to use.
Expand Down Expand Up @@ -540,7 +546,7 @@ def analyze_videos(
print(f"Using scorer: {dlc_scorer}")

# Reading video and init variables
videos = utils.list_videos_in_folder(videos, videotype, shuffle=in_random_order)
videos = collect_video_paths(videos, extensions=videotype, shuffle=in_random_order)
h5_files_created = False # Track if any .h5 files were created

for video in videos:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import pickle
import time
import warnings
from collections.abc import Sequence
from pathlib import Path

import imgaug.augmenters as iaa
Expand All @@ -26,7 +27,7 @@
from deeplabcut.pose_estimation_tensorflow.core import predict as single_predict
from deeplabcut.pose_estimation_tensorflow.core import predict_multianimal as predict
from deeplabcut.utils import auxiliaryfunctions
from deeplabcut.utils.auxfun_videos import VideoWriter
from deeplabcut.utils.auxfun_videos import VideoWriter, collect_video_paths

warnings.simplefilter("ignore", category=RuntimeWarning)

Expand Down Expand Up @@ -247,7 +248,7 @@ def video_inference(
project_name,
model_name,
scale_list=None,
videotype="avi",
videotype: str | Sequence[str] | None = None,
destfolder=None,
batchsize=1,
robust_nframes=False,
Expand Down Expand Up @@ -306,7 +307,7 @@ def video_inference(

sess, inputs, outputs = single_predict.setup_pose_prediction(test_cfg, allow_growth=allow_growth)
DLCscorer = "DLC_" + Path(test_cfg["init_weights"]).stem
videos = auxiliaryfunctions.get_list_of_videos(videos, videotype)
videos = collect_video_paths(videos, extensions=videotype)

datafiles = []
for video in videos:
Expand Down
Loading
Loading