Skip to content

deeplabcut.utils.auxfun_videos

DeepLabCut2.0 Toolbox (deeplabcut.org) © A. & M. Mathis Labs https://github.com/DeepLabCut/DeepLabCut Please see AUTHORS for contributors.

https://github.com/DeepLabCut/DeepLabCut/blob/master/AUTHORS Licensed under GNU Lesser General Public License v3.0

Classes:

Name Description
VideoWriter

Functions:

Name Description
CropVideo

Auxiliary function to crop a video and output it to the same folder with

DownSampleVideo

Auxiliary function to downsample a video and output it to the same folder with

ShortenVideo

Auxiliary function to shorten video and output with outsuffix appended to the

collect_video_paths

Collects video paths from a given set of data paths: directories, files, or a mix

imread

Read image either with skimage or cv2.

rotate_video

Auxiliary function to rotate a video and output it to the same folder with

VideoWriter

Bases: VideoReader

Methods:

Name Description
shorten

Shorten the video from start to end.

split

Split a video into several shorter ones of equal duration.

Source code in deeplabcut/utils/auxfun_videos.py
class VideoWriter(VideoReader):
    def __init__(self, video_path, codec="h264", dpi=100, fps=None):
        super().__init__(video_path)
        self.codec = codec
        self.dpi = dpi
        if fps:
            self.fps = fps

    def shorten(self, start, end, suffix="short", dest_folder=None, validate_inputs=True):
        """Shorten the video from start to end.

        Args:
            start (str): Time formatted in hours:minutes:seconds, where shortened video
                shall start.
            end (str): Time formatted in hours:minutes:seconds, where shortened video
                shall end.
            suffix (str, optional): String added to the name of the shortened video.
                Defaults to 'short'.
            dest_folder (str, optional): Folder the video is saved into. By default,
                same as the original video.

        Returns:
            str: Full path to the shortened video.
        """

        def validate_timestamp(stamp):
            if not isinstance(stamp, str):
                raise ValueError("Timestamp should be a string formatted as hours:minutes:seconds.")
            time = datetime.datetime.strptime(stamp, "%H:%M:%S").time()
            # The above already raises a ValueError if formatting is wrong
            seconds = (time.hour * 60 + time.minute) * 60 + time.second
            if seconds > self.calc_duration():
                raise ValueError("Timestamps must not exceed the video duration.")

        if validate_inputs:
            for stamp in start, end:
                validate_timestamp(stamp)

        output_path = self.make_output_path(suffix, dest_folder)
        command = f'ffmpeg -n -i "{self.video_path}" -ss {start} -to {end} -c:a copy "{output_path}"'
        subprocess.call(command, shell=True)
        return output_path

    def split(self, n_splits, suffix="split", dest_folder=None):
        """Split a video into several shorter ones of equal duration.

        Args:
            n_splits (int): Number of shorter videos to produce.
            suffix (str, optional): String added to the name of the splits.
                Defaults to 'split'.
            dest_folder (str, optional): Folder the video splits are saved into. By
                default, same as the original video.

        Returns:
            list: Paths of the video splits.
        """
        if not n_splits > 1:
            raise ValueError("The video should at least be split in half.")
        chunk_dur = self.calc_duration() / n_splits
        splits = np.arange(n_splits + 1) * chunk_dur

        def time_formatter(val):
            return str(datetime.timedelta(seconds=val))

        clips = []
        for n, (start, end) in enumerate(zip(splits, splits[1:], strict=False), start=1):
            clips.append(
                self.shorten(
                    time_formatter(start),
                    time_formatter(end),
                    f"{suffix}{n}",
                    dest_folder,
                    validate_inputs=False,
                )
            )
        return clips

    def crop(self, suffix="crop", dest_folder=None):
        x1, _, y1, _ = self.get_bbox()
        output_path = self.make_output_path(suffix, dest_folder)
        command = (
            f'ffmpeg -n -i "{self.video_path}" '
            f"-filter:v crop={self.width}:{self.height}:{x1}:{y1} "
            f'-c:a copy "{output_path}"'
        )
        subprocess.call(command, shell=True)
        return output_path

    def rotate(self, angle, rotatecw="Arbitrary", suffix="rotated", dest_folder=None):
        output_path = self.make_output_path(suffix, dest_folder)
        command = f'ffmpeg -n -i "{self.video_path}" -vf '
        if rotatecw == "Arbitrary":
            angle = np.deg2rad(angle)
            command += f"rotate={angle} "
        elif rotatecw == "Yes":
            command += "transpose=1 "
        else:
            raise ValueError("Unknown rotation direction.")

        command += f'-c:a copy "{output_path}"'
        subprocess.call(command, shell=True)
        return output_path

    def rescale(
        self,
        width,
        height=-1,
        rotatecw="No",
        angle=0.0,
        suffix="rescale",
        dest_folder=None,
    ):
        output_path = self.make_output_path(suffix, dest_folder)
        command = f'ffmpeg -n -i "{self.video_path}" -filter:v "scale={width}:{height}{{}}" -c:a copy "{output_path}"'
        # Rotate, see: https://stackoverflow.com/questions/3937387/rotating-videos-with-ffmpeg
        # interesting option to just update metadata.
        if rotatecw == "Arbitrary":
            angle = np.deg2rad(angle)
            command = command.format(f", rotate={angle}")
        elif rotatecw == "Yes":
            command = command.format(", transpose=1")
        else:
            command = command.format("")
        subprocess.call(command, shell=True)
        return output_path

    @staticmethod
    def write_frame(frame, where):
        cv2.imwrite(where, frame[..., ::-1])

    def make_output_path(self, suffix, dest_folder):
        if not dest_folder:
            dest_folder = self.directory
        return str(Path(dest_folder) / f"{self.name}{suffix}{self.format}")

shorten

shorten(start, end, suffix='short', dest_folder=None, validate_inputs=True)

Shorten the video from start to end.

Parameters:

Name Type Description Default

start

str

Time formatted in hours:minutes:seconds, where shortened video shall start.

required

end

str

Time formatted in hours:minutes:seconds, where shortened video shall end.

required

suffix

str

String added to the name of the shortened video. Defaults to 'short'.

'short'

dest_folder

str

Folder the video is saved into. By default, same as the original video.

None

Returns:

Name Type Description
str

Full path to the shortened video.

Source code in deeplabcut/utils/auxfun_videos.py
def shorten(self, start, end, suffix="short", dest_folder=None, validate_inputs=True):
    """Shorten the video from start to end.

    Args:
        start (str): Time formatted in hours:minutes:seconds, where shortened video
            shall start.
        end (str): Time formatted in hours:minutes:seconds, where shortened video
            shall end.
        suffix (str, optional): String added to the name of the shortened video.
            Defaults to 'short'.
        dest_folder (str, optional): Folder the video is saved into. By default,
            same as the original video.

    Returns:
        str: Full path to the shortened video.
    """

    def validate_timestamp(stamp):
        if not isinstance(stamp, str):
            raise ValueError("Timestamp should be a string formatted as hours:minutes:seconds.")
        time = datetime.datetime.strptime(stamp, "%H:%M:%S").time()
        # The above already raises a ValueError if formatting is wrong
        seconds = (time.hour * 60 + time.minute) * 60 + time.second
        if seconds > self.calc_duration():
            raise ValueError("Timestamps must not exceed the video duration.")

    if validate_inputs:
        for stamp in start, end:
            validate_timestamp(stamp)

    output_path = self.make_output_path(suffix, dest_folder)
    command = f'ffmpeg -n -i "{self.video_path}" -ss {start} -to {end} -c:a copy "{output_path}"'
    subprocess.call(command, shell=True)
    return output_path

split

split(n_splits, suffix='split', dest_folder=None)

Split a video into several shorter ones of equal duration.

Parameters:

Name Type Description Default

n_splits

int

Number of shorter videos to produce.

required

suffix

str

String added to the name of the splits. Defaults to 'split'.

'split'

dest_folder

str

Folder the video splits are saved into. By default, same as the original video.

None

Returns:

Name Type Description
list

Paths of the video splits.

Source code in deeplabcut/utils/auxfun_videos.py
def split(self, n_splits, suffix="split", dest_folder=None):
    """Split a video into several shorter ones of equal duration.

    Args:
        n_splits (int): Number of shorter videos to produce.
        suffix (str, optional): String added to the name of the splits.
            Defaults to 'split'.
        dest_folder (str, optional): Folder the video splits are saved into. By
            default, same as the original video.

    Returns:
        list: Paths of the video splits.
    """
    if not n_splits > 1:
        raise ValueError("The video should at least be split in half.")
    chunk_dur = self.calc_duration() / n_splits
    splits = np.arange(n_splits + 1) * chunk_dur

    def time_formatter(val):
        return str(datetime.timedelta(seconds=val))

    clips = []
    for n, (start, end) in enumerate(zip(splits, splits[1:], strict=False), start=1):
        clips.append(
            self.shorten(
                time_formatter(start),
                time_formatter(end),
                f"{suffix}{n}",
                dest_folder,
                validate_inputs=False,
            )
        )
    return clips

CropVideo

CropVideo(vname, width=256, height=256, origin_x=0, origin_y=0, outsuffix='cropped', outpath=None, useGUI=False)

Auxiliary function to crop a video and output it to the same folder with "outsuffix" appended in its name. Width and height will control the new dimensions.

ffmpeg -i in.mp4 -filter:v "crop=out_w:out_h:x:y" out.mp4

Parameters:

Name Type Description Default

vname

string

A string containing the full path of the video.

required

width

int

Width of output video.

256

height

int

Height of output video.

256

origin_x

int

X-axis origin of bounding box for cropping.

0

origin_y

int

Y-axis origin of bounding box for cropping.

0

outsuffix

str

Suffix for output videoname (see example).

'cropped'

outpath

str

Output path for saving video to (by default, same folder as the video).

None

Returns:

Name Type Description
str

The full path to the cropped video.

Examples:

Linux/MacOs:

deeplabcut.CropVideo("/data/videos/mouse1.avi")

Crops the video using default values and saves it in /data/videos as mouse1cropped.avi

Windows:

deeplabcut.CropVideo(
    "C:\yourusername\rig-95\Videos\reachingvideo1.avi",
    width=220,
    height=320,
    outsuffix="cropped",
)

Crops the video to a width of 220 and height of 320 starting at the origin (top left) and saves it in C:\yourusername\rig-95\Videos as reachingvideo1cropped.avi

Source code in deeplabcut/utils/auxfun_videos.py
def CropVideo(
    vname,
    width=256,
    height=256,
    origin_x=0,
    origin_y=0,
    outsuffix="cropped",
    outpath=None,
    useGUI=False,
):
    """Auxiliary function to crop a video and output it to the same folder with
    "outsuffix" appended in its name. Width and height will control the new dimensions.

    ffmpeg -i in.mp4 -filter:v "crop=out_w:out_h:x:y" out.mp4

    Args:
        vname (string): A string containing the full path of the video.
        width (int): Width of output video.
        height (int): Height of output video.
        origin_x (int): X-axis origin of bounding box for cropping.
        origin_y (int): Y-axis origin of bounding box for cropping.
        outsuffix (str): Suffix for output videoname (see example).
        outpath (str): Output path for saving video to (by default, same folder as the
            video).

    Returns:
        str: The full path to the cropped video.

    Examples:
        Linux/MacOs:

            deeplabcut.CropVideo("/data/videos/mouse1.avi")

        Crops the video using default values and saves it in /data/videos as
        mouse1cropped.avi

        Windows:

            deeplabcut.CropVideo(
                "C:\\yourusername\\rig-95\\Videos\\reachingvideo1.avi",
                width=220,
                height=320,
                outsuffix="cropped",
            )

        Crops the video to a width of 220 and height of 320 starting at the origin (top
        left) and saves it in C:\\yourusername\\rig-95\\Videos as reachingvideo1cropped.avi
    """
    writer = VideoWriter(vname)

    if useGUI:
        print("Please, select your coordinates (draw from top left to bottom right ...)")
        coords = draw_bbox(vname)

        if not coords:
            return
        origin_x, origin_y = coords[:2]
        width = int(coords[2]) - int(coords[0])
        height = int(coords[3]) - int(coords[1])

    writer.set_bbox(origin_x, origin_x + width, origin_y, origin_y + height)
    return writer.crop(outsuffix, outpath)

DownSampleVideo

DownSampleVideo(vname, width=-1, height=200, outsuffix='downsampled', outpath=None, rotatecw='No', angle=0.0)

Auxiliary function to downsample a video and output it to the same folder with "outsuffix" appended in its name. Width and height will control the new dimensions. You can also pass only height or width and set the other one to -1, this will keep the aspect ratio identical.

Parameters:

Name Type Description Default

vname

string

A string containing the full path of the video.

required

width

int

Width of output video.

-1

height

int

Height of output video.

200

outsuffix

str

Suffix for output videoname (see example).

'downsampled'

outpath

str

Output path for saving video to (by default, same folder as the video).

None

rotatecw

str

Default "No", rotates clockwise if "Yes", "Arbitrary" for arbitrary rotation by specified angle.

'No'

angle

float

Angle to rotate by in degrees, default 0.0. Negative values rotate counter-clockwise.

0.0

Returns:

Name Type Description
str

The full path to the downsampled video.

Examples:

Linux/MacOs:

deeplabcut.DownSampleVideo("/data/videos/mouse1.avi")

Downsamples the video using default values and saves it in /data/videos as mouse1downsampled.avi

Windows:

shortenedvideoname = deeplabcut.DownSampleVideo(
    "C:\yourusername\rig-95\Videos\reachingvideo1.avi",
    width=220,
    height=320,
    outsuffix="cropped",
)

Downsamples the video to a width of 220 and height of 320 and saves it in C:\yourusername\rig-95\Videos as reachingvideo1cropped.avi

Source code in deeplabcut/utils/auxfun_videos.py
def DownSampleVideo(
    vname,
    width=-1,
    height=200,
    outsuffix="downsampled",
    outpath=None,
    rotatecw="No",
    angle=0.0,
):
    """Auxiliary function to downsample a video and output it to the same folder with
    "outsuffix" appended in its name. Width and height will control the new dimensions.
    You can also pass only height or width and set the other one to -1, this will keep
    the aspect ratio identical.

    Args:
        vname (string): A string containing the full path of the video.
        width (int): Width of output video.
        height (int): Height of output video.
        outsuffix (str): Suffix for output videoname (see example).
        outpath (str): Output path for saving video to (by default, same folder as the
            video).
        rotatecw (str): Default "No", rotates clockwise if "Yes", "Arbitrary" for
            arbitrary rotation by specified angle.
        angle (float): Angle to rotate by in degrees, default 0.0. Negative values
            rotate counter-clockwise.

    Returns:
        str: The full path to the downsampled video.

    Examples:
        Linux/MacOs:

            deeplabcut.DownSampleVideo("/data/videos/mouse1.avi")

        Downsamples the video using default values and saves it in /data/videos as
        mouse1downsampled.avi

        Windows:

            shortenedvideoname = deeplabcut.DownSampleVideo(
                "C:\\yourusername\\rig-95\\Videos\\reachingvideo1.avi",
                width=220,
                height=320,
                outsuffix="cropped",
            )

        Downsamples the video to a width of 220 and height of 320 and saves it in
        C:\\yourusername\\rig-95\\Videos as reachingvideo1cropped.avi
    """
    writer = VideoWriter(vname)
    return writer.rescale(width, height, rotatecw, angle, outsuffix, outpath)

ShortenVideo

ShortenVideo(vname, start='00:00:01', stop='00:01:00', outsuffix='short', outpath=None)

Auxiliary function to shorten video and output with outsuffix appended to the same folder from start (hours:minutes:seconds) to stop (hours:minutes:seconds).

Parameters:

Name Type Description Default

vname

string

A string containing the full path of the video.

required

start

str

Time formatted in hours:minutes:seconds, where shortened video shall start.

'00:00:01'

stop

str

Time formatted in hours:minutes:seconds, where shortened video shall end.

'00:01:00'

outsuffix

str

Suffix for output videoname (see example).

'short'

outpath

str

Output path for saving video to (by default, same folder as the video).

None

Returns:

Name Type Description
str

The full path to the shortened video.

Examples:

Linux/MacOs:

deeplabcut.ShortenVideo("/data/videos/mouse1.avi")

Extracts (sub)video from 1st second to 1st minutes (default values) and saves it in /data/videos as mouse1short.avi

Windows:

deeplabcut.ShortenVideo(
    "C:\yourusername\rig-95\Videos\reachingvideo1.avi",
    start="00:17:00",
    stop="00:22:00",
    outsuffix="brief",
)

Extracts (sub)video from minute 17 to 22 and saves it in C:\yourusername\rig-95\Videos as reachingvideo1brief.avi

Source code in deeplabcut/utils/auxfun_videos.py
def ShortenVideo(vname, start="00:00:01", stop="00:01:00", outsuffix="short", outpath=None):
    """Auxiliary function to shorten video and output with outsuffix appended to the
    same folder from start (hours:minutes:seconds) to stop (hours:minutes:seconds).

    Args:
        vname (string): A string containing the full path of the video.
        start (str): Time formatted in hours:minutes:seconds, where shortened video shall
            start.
        stop (str): Time formatted in hours:minutes:seconds, where shortened video shall
            end.
        outsuffix (str): Suffix for output videoname (see example).
        outpath (str): Output path for saving video to (by default, same folder as the
            video).

    Returns:
        str: The full path to the shortened video.

    Examples:
        Linux/MacOs:

            deeplabcut.ShortenVideo("/data/videos/mouse1.avi")

        Extracts (sub)video from 1st second to 1st minutes (default values) and saves
        it in /data/videos as mouse1short.avi

        Windows:

            deeplabcut.ShortenVideo(
                "C:\\yourusername\\rig-95\\Videos\\reachingvideo1.avi",
                start="00:17:00",
                stop="00:22:00",
                outsuffix="brief",
            )

        Extracts (sub)video from minute 17 to 22 and saves it in
        C:\\yourusername\\rig-95\\Videos as reachingvideo1brief.avi
    """
    writer = VideoWriter(vname)
    return writer.shorten(start, stop, outsuffix, outpath)

collect_video_paths

collect_video_paths(
    data_path: str | Path | list[str | Path],
    extensions: str | Sequence[str] | None = None,
    shuffle: bool = False,
    exclude_patterns: Sequence[str] = DEFAULT_EXCLUDE_PATTERNS,
) -> list[Path]

Collects video paths from a given set of data paths: directories, files, or a mix of both. Directories are scanned one level deep (non-recursively).

Files and directories are treated differently with respect to extension filtering: - File paths are accepted as-is when extensions is None; only filtered when extensions is explicitly set. - Directory contents are always filtered by extension: by SUPPORTED_VIDEOS when extensions is None, or by the given value(s) otherwise. - exclude_patterns are always applied to both files and directory contents.

Parameters:

Name Type Description Default

data_path

str | Path | list[str | Path]

Path or list of paths to folders containing videos, or individual video files. Can be a mix of directories and files.

required

extensions

str | Sequence[str] | None

Controls extension filtering for collected video files. - None (default): file paths are accepted without extension filtering; 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 to only include files matching the given extension(s). - Empty str "" is treated as None (deprecated, keep for backwards compatibility).

None

shuffle

bool

Whether to shuffle the order of videos. If False, videos are returned in sorted order for deterministic behavior.

False

exclude_patterns

Sequence[str]

Patterns to exclude from the collection. Defaults to DEFAULT_EXCLUDE_PATTERNS. Set to [] to disable pattern exclusion.

DEFAULT_EXCLUDE_PATTERNS

Returns:

Type Description
list[Path]

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

Raises:

Type Description
FileNotFoundError

If any path in data_path does not exist.

ValueError

If extensions is an empty sequence.

Source code in deeplabcut/utils/auxfun_videos.py
def collect_video_paths(
    data_path: str | Path | list[str | Path],
    extensions: str | Sequence[str] | None = None,
    shuffle: bool = False,
    exclude_patterns: Sequence[str] = DEFAULT_EXCLUDE_PATTERNS,
) -> list[Path]:
    """
    Collects video paths from a given set of data paths: directories, files, or a mix
    of both. Directories are scanned one level deep (non-recursively).

    Files and directories are treated differently with respect to extension filtering:
    - File paths are accepted as-is when ``extensions`` is ``None``; only filtered when
      ``extensions`` is explicitly set.
    - Directory contents are always filtered by extension: by ``SUPPORTED_VIDEOS`` when
      ``extensions`` is ``None``, or by the given value(s) otherwise.
    - ``exclude_patterns`` are always applied to both files and directory contents.

    Args:
        data_path: Path or list of paths to folders containing videos, or individual
            video files. Can be a mix of directories and files.
        extensions: Controls extension filtering for collected video files.
            - ``None`` (default): file paths are accepted without extension filtering;
              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 to only include files
              matching the given extension(s).
            - Empty ``str`` ``""`` is treated as ``None`` (deprecated, keep for backwards
              compatibility).
        shuffle: Whether to shuffle the order of videos. If ``False``, videos are
            returned in sorted order for deterministic behavior.
        exclude_patterns: Patterns to exclude from the collection. Defaults to
            ``DEFAULT_EXCLUDE_PATTERNS``. Set to ``[]`` to disable pattern exclusion.

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

    Raises:
        FileNotFoundError: If any path in ``data_path`` does not exist.
        ValueError: If ``extensions`` is an empty sequence.
    """
    if isinstance(data_path, (str, Path)):
        data_path = [data_path]

    def _coerce_extensions(extensions: str | Sequence[str] | None) -> set[str] | None:
        """Coerce the extensions argument to a set of dot-prefixed suffixes, or None."""
        if extensions is None:
            return None

        if extensions in ["", ("",), [""], {""}]:
            warnings.warn(
                "Passing an empty string for filtering video type extensions is deprecated; pass None instead.",
                DLCDeprecationWarning,
                stacklevel=3,
            )
            return None

        if isinstance(extensions, str):
            return {f".{extensions.lstrip('.').lower()}"}

        if not isinstance(extensions, Sequence):
            raise TypeError(f"extensions must be a string, a sequence or None, got {type(extensions)}")

        if len(extensions) == 0:
            raise ValueError("Video type extensions filter needs to be a non-empty sequence.")
        return {f".{e.lstrip('.').lower()}" for e in extensions}

    explicit_suffixes = _coerce_extensions(extensions)
    implicit_suffixes = {f".{ext.lower()}" for ext in SUPPORTED_VIDEOS}

    videos: list[Path] = []
    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():
            # Discriminate videos from other files; skip excluded patterns (e.g. prior DLC outputs).
            allowed = explicit_suffixes if explicit_suffixes else implicit_suffixes
            videos.extend(
                f
                for f in path.iterdir()
                if f.is_file()
                and f.suffix.lower() in allowed
                and not any(f.match(pattern) for pattern in exclude_patterns)
            )
        elif path.is_file():
            # Accept all caller-supplied files; ONLY filter extensions if set. ALWAYS filter exclude patterns.
            if explicit_suffixes is None or path.suffix.lower() in explicit_suffixes:
                if not any(path.match(pattern) for pattern in exclude_patterns):
                    videos.append(path)

    # Resolve video paths and remove duplicates
    unique_videos = list(dict.fromkeys(v.absolute() for v in videos))
    if shuffle:
        random.shuffle(unique_videos)
    else:
        unique_videos.sort()

    if any(fn.suffix.lower().lstrip(".") not in SUPPORTED_VIDEOS for fn in unique_videos if fn.suffix):
        warnings.warn(
            f"Some videos have unsupported extensions: {unique_videos} \nSupported extensions are: {SUPPORTED_VIDEOS}",
            stacklevel=2,
        )
    return unique_videos

imread

imread(image_path, mode='skimage')

Read image either with skimage or cv2.

Returns frame in uint with 3 color channels.

Source code in deeplabcut/utils/auxfun_videos.py
def imread(image_path, mode="skimage"):
    """Read image either with skimage or cv2.

    Returns frame in uint with 3 color channels.
    """
    if mode == "skimage":
        image = io.imread(image_path)
        if image.ndim == 2 or image.shape[-1] == 1:
            image = skimage.color.gray2rgb(image)
        elif image.shape[-1] == 4:
            image = skimage.color.rgba2rgb(image)

        return img_as_ubyte(image)

    elif mode == "cv2":
        return cv2.imread(str(image_path), cv2.IMREAD_UNCHANGED)[..., ::-1]  # ~10% faster than using cv2.cvtColor

rotate_video

rotate_video(vname, angle, rotatecw='Arbitrary', outsuffix='rotated', outpath=None)

Auxiliary function to rotate a video and output it to the same folder with "outsuffix" appended in its name. Angle is in degrees.

Parameters:

Name Type Description Default

vname

string

A string containing the full path of the video.

required

angle

float

Angle to rotate by in degrees. Negative values rotate counter-clockwise.

required

rotatecw

str

Default "Arbitrary", rotates clockwise if "Yes", "Arbitrary" for arbitrary rotation by specified angle.

'Arbitrary'

outsuffix

str

Suffix for output videoname (see example).

'rotated'

outpath

str

Output path for saving video to (by default, same folder as the video).

None

Returns:

Name Type Description
str

The full path to the rotated video.

Examples:

Linux/MacOs:

deeplabcut.rotate_video("/data/videos/mouse1.avi", angle=90)

Rotates the video by 90 degrees and saves it in /data/videos as mouse1rotated.avi

Windows:

shortenedvideoname = deeplabcut.rotate_video(
    "C:\yourusername\rig-95\Videos\reachingvideo1.avi",
    angle=180,
    rotatecw="Yes",
)

Rotates the video by 180 degrees and saves it in C:\yourusername\rig-95\Videos as reachingvideo1rotated.avi

Source code in deeplabcut/utils/auxfun_videos.py
def rotate_video(vname, angle, rotatecw="Arbitrary", outsuffix="rotated", outpath=None):
    """Auxiliary function to rotate a video and output it to the same folder with
    "outsuffix" appended in its name. Angle is in degrees.

    Args:
        vname (string): A string containing the full path of the video.
        angle (float): Angle to rotate by in degrees. Negative values rotate
            counter-clockwise.
        rotatecw (str): Default "Arbitrary", rotates clockwise if "Yes", "Arbitrary" for
            arbitrary rotation by specified angle.
        outsuffix (str): Suffix for output videoname (see example).
        outpath (str): Output path for saving video to (by default, same folder as the
            video).

    Returns:
        str: The full path to the rotated video.

    Examples:
        Linux/MacOs:

            deeplabcut.rotate_video("/data/videos/mouse1.avi", angle=90)

        Rotates the video by 90 degrees and saves it in /data/videos as mouse1rotated.avi

        Windows:

            shortenedvideoname = deeplabcut.rotate_video(
                "C:\\yourusername\\rig-95\\Videos\\reachingvideo1.avi",
                angle=180,
                rotatecw="Yes",
            )

        Rotates the video by 180 degrees and saves it in
        C:\\yourusername\\rig-95\\Videos as reachingvideo1rotated.avi
    """
    writer = VideoWriter(vname)
    return writer.rotate(angle, rotatecw, outsuffix, outpath)