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.

        Parameter
        ----------
        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 ('short' by default).

        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.

        Parameters
        ----------
        n_splits : int
            Number of shorter videos to produce

        suffix: str, optional
            String added to the name of the splits ('short' by default).

        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 os.path.join(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.

Parameter

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

str

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

str, optional

String added to the name of the shortened video ('short' by default).

str, optional

Folder the video is saved into (by default, same as the original video)

Returns

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.

    Parameter
    ----------
    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 ('short' by default).

    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

n_splits : int Number of shorter videos to produce

str, optional

String added to the name of the splits ('short' by default).

str, optional

Folder the video splits are saved into (by default, same as the original video)

Returns

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.

    Parameters
    ----------
    n_splits : int
        Number of shorter videos to produce

    suffix: str, optional
        String added to the name of the splits ('short' by default).

    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.

Returns the full path to the downsampled video!

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

Parameter

vname : string A string containing the full path of the video.

int

width of output video

int

height of output video.

origin_x, origin_y: int x- and y- axis origin of bounding box for cropping.

str

Suffix for output videoname (see example).

str

Output path for saving video to (by default will be the same folder as the 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.

    Returns the full path to the downsampled video!

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

    Parameter
    ----------
    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, origin_y: int
        x- and 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 will be the same folder as the 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.

Returns the full path to the downsampled video!

Parameter

vname : string A string containing the full path of the video.

int

width of output video

int

height of output video.

str

Suffix for output videoname (see example).

str

Output path for saving video to (by default will be the same folder as the video)

str

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

float

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

Examples

Linux/MacOs

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

Downsamples the video using default values and saves it in /data/videos as mouse1cropped.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.

    Returns the full path to the downsampled video!

    Parameter
    ----------
    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 will be the 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

    Examples
    ----------

    Linux/MacOs
    >>> deeplabcut.DownSampleVideo('/data/videos/mouse1.avi')

    Downsamples the video using default values and saves it in /data/videos as mouse1cropped.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).

Returns the full path to the shortened video!

Parameter

videos : string A string containing the full paths of the video.

hours:minutes:seconds

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

hours:minutes:seconds

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

str

Suffix for output videoname (see example).

str

Output path for saving video to (by default will be the same folder as the 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 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).

    Returns the full path to the shortened video!

    Parameter
    ----------
    videos : string
        A string containing the full paths of the video.

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

    stop: hours:minutes:seconds
        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 will be the same folder as the 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 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.resolve() 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(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.

Returns the full path to the rotated video!

Parameter

vname : string A string containing the full path of the video.

float

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

str

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

str

Suffix for output videoname (see example).

str

Output path for saving video to (by default will be the same folder as the 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.

    Returns the full path to the rotated video!

    Parameter
    ----------
    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 will be the same folder as the 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)