Skip to content

deeplabcut.utils.make_labeled_video

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

Hao Wu, hwu01@g.harvard.edu contributed the original OpenCV class. Thanks! You can find the directory for your ffmpeg bindings by: "find / | grep ffmpeg" and then setting it.

Functions:

Name Description
CreateVideo

Creating individual frames with labeled body parts and making a video.

CreateVideoSlow

Creating individual frames with labeled body parts and making a video.

create_labeled_video

Labels the bodyparts in a video.

create_video_with_all_detections

Create a video labeled with all the detections stored in a '*_full.pickle' file.

proc_video

Helper function for create_labeled_video.

CreateVideo

CreateVideo(
    clip,
    Dataframe,
    pcutoff,
    dotsize,
    colormap,
    bodyparts2plot,
    trailpoints,
    cropping,
    x1,
    x2,
    y1,
    y2,
    bodyparts2connect,
    skeleton_color,
    draw_skeleton,
    displaycropped,
    color_by,
    confidence_to_alpha=None,
    plot_bboxes=True,
    bboxes_list=None,
    bboxes_pcutoff=0.6,
    bboxes_color: tuple | None = None,
)

Creating individual frames with labeled body parts and making a video.

Source code in deeplabcut/utils/make_labeled_video.py
def CreateVideo(
    clip,
    Dataframe,
    pcutoff,
    dotsize,
    colormap,
    bodyparts2plot,
    trailpoints,
    cropping,
    x1,
    x2,
    y1,
    y2,
    bodyparts2connect,
    skeleton_color,
    draw_skeleton,
    displaycropped,
    color_by,
    confidence_to_alpha=None,
    plot_bboxes=True,
    bboxes_list=None,
    bboxes_pcutoff=0.6,
    bboxes_color: tuple | None = None,
):
    """Creating individual frames with labeled body parts and making a video."""
    bpts = Dataframe.columns.get_level_values("bodyparts")
    all_bpts = bpts.values[::3]
    if draw_skeleton:
        color_for_skeleton = (np.array(mcolors.to_rgba(skeleton_color))[:3] * 255).astype(np.uint8)
        # recode the bodyparts2connect into indices for df_x and df_y for speed
        bpts2connect = get_segment_indices(bodyparts2connect, all_bpts)

    if displaycropped:
        ny, nx = y2 - y1, x2 - x1
    else:
        ny, nx = clip.height, clip.width

    fps = clip.fps
    if isinstance(fps, float):
        if fps * 1000 > 65535:
            fps = round(fps)
    nframes = clip.nframes
    duration = nframes / fps

    print(f"Duration of video [s]: {round(duration, 2)}, recorded with {round(fps, 2)} fps!")
    print(f"Overall # of frames: {nframes} with cropped frame dimensions: {nx} {ny}")
    print("Generating frames and creating video.")

    df_x, df_y, df_likelihood = Dataframe.values.reshape((len(Dataframe), -1, 3)).T

    if cropping and not displaycropped:
        df_x += x1
        df_y += y1
    colorclass = plt.cm.ScalarMappable(cmap=colormap)

    bplist = bpts.unique().to_list()
    nbodyparts = len(bplist)
    if Dataframe.columns.nlevels == 3:
        nindividuals = int(len(all_bpts) / len(set(all_bpts)))
        map2bp = list(np.repeat(list(range(len(set(all_bpts)))), nindividuals))
        map2id = list(range(nindividuals)) * len(set(all_bpts))
    else:
        nindividuals = len(Dataframe.columns.get_level_values("individuals").unique())
        map2bp = [bplist.index(bp) for bp in all_bpts]
        nbpts_per_ind = Dataframe.T.groupby(level="individuals").size().values // 3
        map2id = []
        for i, j in enumerate(nbpts_per_ind):
            map2id.extend([i] * j)
    keep = np.flatnonzero(np.isin(all_bpts, bodyparts2plot))
    bpts2color = [(ind, map2bp[ind], map2id[ind]) for ind in keep]

    if color_by == "bodypart":
        C = colorclass.to_rgba(np.linspace(0, 1, nbodyparts))
    else:
        C = colorclass.to_rgba(np.linspace(0, 1, nindividuals))
    colors = (C[:, :3] * 255).astype(np.uint8)

    if bboxes_color is None:
        bboxes_color = (255, 0, 0)

    with np.errstate(invalid="ignore"):
        for index in trange(min(nframes, len(Dataframe))):
            image = clip.load_frame()
            if displaycropped:
                image = image[y1:y2, x1:x2]

            # Draw bounding boxes if required and present
            if plot_bboxes and bboxes_list:
                bboxes = bboxes_list[index]["bboxes"]
                bbox_scores = bboxes_list[index].get("bbox_scores")
                n_bboxes = len(bboxes)
                for i in range(n_bboxes):
                    bbox = bboxes[i]
                    x, y = bbox[0], bbox[1]
                    x += x1
                    y += y1
                    w, h = bbox[2], bbox[3]
                    if bbox_scores is not None and bbox_scores[i] < bboxes_pcutoff:
                        continue
                    rect_coords = rectangle_perimeter(start=(y, x), extent=(h, w))

                    set_color(
                        image,
                        rect_coords,
                        bboxes_color,
                    )

            # Draw the skeleton for specific bodyparts to be connected as
            # specified in the config file
            if draw_skeleton:
                for bpt1, bpt2 in bpts2connect:
                    if np.all(df_likelihood[[bpt1, bpt2], index] > pcutoff) and not (
                        np.any(np.isnan(df_x[[bpt1, bpt2], index])) or np.any(np.isnan(df_y[[bpt1, bpt2], index]))
                    ):
                        rr, cc, val = line_aa(
                            int(np.clip(df_y[bpt1, index], 0, ny - 1)),
                            int(np.clip(df_x[bpt1, index], 0, nx - 1)),
                            int(np.clip(df_y[bpt2, index], 1, ny - 1)),
                            int(np.clip(df_x[bpt2, index], 1, nx - 1)),
                        )
                        image[rr, cc] = color_for_skeleton

            for ind, num_bp, num_ind in bpts2color:
                if df_likelihood[ind, index] > pcutoff:
                    if color_by == "bodypart":
                        color = colors[num_bp]
                    else:
                        color = colors[num_ind]
                    if trailpoints > 0:
                        for k in range(1, min(trailpoints, index + 1)):
                            rr, cc = disk(
                                (df_y[ind, index - k], df_x[ind, index - k]),
                                dotsize,
                                shape=(ny, nx),
                            )
                            image[rr, cc] = color
                    rr, cc = disk((df_y[ind, index], df_x[ind, index]), dotsize, shape=(ny, nx))
                    alpha = 1
                    if confidence_to_alpha is not None:
                        alpha = confidence_to_alpha(df_likelihood[ind, index])

                    set_color(image, (rr, cc), color, alpha)

            clip.save_frame(image)
    clip.close()

CreateVideoSlow

CreateVideoSlow(
    videooutname,
    clip,
    Dataframe,
    tmpfolder,
    dotsize,
    colormap,
    alphavalue,
    pcutoff,
    trailpoints,
    cropping,
    x1,
    x2,
    y1,
    y2,
    save_frames,
    bodyparts2plot,
    outputframerate,
    Frames2plot,
    bodyparts2connect,
    skeleton_color,
    draw_skeleton,
    displaycropped,
    color_by,
    plot_bboxes=True,
    bboxes_list=None,
    bboxes_pcutoff=0.6,
    bboxes_color: str | None = None,
)

Creating individual frames with labeled body parts and making a video.

Source code in deeplabcut/utils/make_labeled_video.py
def CreateVideoSlow(
    videooutname,
    clip,
    Dataframe,
    tmpfolder,
    dotsize,
    colormap,
    alphavalue,
    pcutoff,
    trailpoints,
    cropping,
    x1,
    x2,
    y1,
    y2,
    save_frames,
    bodyparts2plot,
    outputframerate,
    Frames2plot,
    bodyparts2connect,
    skeleton_color,
    draw_skeleton,
    displaycropped,
    color_by,
    plot_bboxes=True,
    bboxes_list=None,
    bboxes_pcutoff=0.6,
    bboxes_color: str | None = None,
):
    """Creating individual frames with labeled body parts and making a video."""
    if displaycropped:
        ny, nx = y2 - y1, x2 - x1
    else:
        ny, nx = clip.height, clip.width

    fps = clip.fps
    if outputframerate is None:  # by def. same as input rate.
        outputframerate = fps

    nframes = clip.nframes
    duration = nframes / fps

    print(f"Duration of video [s]: {round(duration, 2)}, recorded with {round(fps, 2)} fps!")
    print(f"Overall # of frames: {nframes} with cropped frame dimensions: {nx} {ny}")
    print("Generating frames and creating video.")
    df_x, df_y, df_likelihood = Dataframe.values.reshape((len(Dataframe), -1, 3)).T
    if cropping and not displaycropped:
        df_x += x1
        df_y += y1

    bpts = Dataframe.columns.get_level_values("bodyparts")
    all_bpts = bpts.values[::3]
    if draw_skeleton:
        bpts2connect = get_segment_indices(bodyparts2connect, all_bpts)

    bplist = bpts.unique().to_list()
    nbodyparts = len(bplist)
    if Dataframe.columns.nlevels == 3:
        nindividuals = int(len(all_bpts) / len(set(all_bpts)))
        map2bp = list(np.repeat(list(range(len(set(all_bpts)))), nindividuals))
        map2id = list(range(nindividuals)) * len(set(all_bpts))
    else:
        nindividuals = len(Dataframe.columns.get_level_values("individuals").unique())
        map2bp = [bplist.index(bp) for bp in all_bpts]
        nbpts_per_ind = Dataframe.T.groupby(level="individuals").size().values // 3
        map2id = []
        for i, j in enumerate(nbpts_per_ind):
            map2id.extend([i] * j)
    keep = np.flatnonzero(np.isin(all_bpts, bodyparts2plot))
    bpts2color = [(ind, map2bp[ind], map2id[ind]) for ind in keep]
    if color_by == "individual":
        colors = visualization.get_cmap(nindividuals, name=colormap)
    else:
        colors = visualization.get_cmap(nbodyparts, name=colormap)

    if bboxes_color is None:
        bboxes_color = "red"

    nframes_digits = int(np.ceil(np.log10(nframes)))
    if nframes_digits > 9:
        raise Exception("Your video has more than 10**9 frames, we recommend chopping it up.")

    if Frames2plot is None:
        Index = set(range(nframes))
    else:
        Index = {int(k) for k in Frames2plot if 0 <= k < nframes}

    # Prepare figure
    prev_backend = plt.get_backend()
    plt.switch_backend("agg")
    dpi = 100
    fig = plt.figure(frameon=False, figsize=(nx / dpi, ny / dpi))
    ax = fig.add_subplot(111)

    writer = FFMpegWriter(fps=outputframerate, codec="h264")
    with writer.saving(fig, videooutname, dpi=dpi), np.errstate(invalid="ignore"):
        for index in trange(min(nframes, len(Dataframe))):
            imagename = Path(tmpfolder) / f"file{index:0{nframes_digits}d}.png"
            image = img_as_ubyte(clip.load_frame())
            if index in Index:  # then extract the frame!
                if cropping and displaycropped:
                    image = image[y1:y2, x1:x2]
                ax.imshow(image)

                # Draw bounding boxes of required and present
                if plot_bboxes and bboxes_list:
                    bboxes = bboxes_list[index]["bboxes"]
                    bbox_scores = bboxes_list[index].get("bbox_scores")
                    n_bboxes = len(bboxes)
                    for i in range(n_bboxes):
                        bbox = bboxes[i]
                        bbox_origin = (bbox[0], bbox[1])
                        (bbox_width, bbox_height) = (bbox[2], bbox[3])
                        if bbox_scores is not None and bbox_scores[i] < bboxes_pcutoff:
                            continue
                        rectangle = patches.Rectangle(
                            bbox_origin,
                            bbox_width,
                            bbox_height,
                            linewidth=1,
                            edgecolor=bboxes_color,
                            facecolor="none",
                        )
                        ax.add_patch(rectangle)

                # Draw skeleton
                if draw_skeleton:
                    for bpt1, bpt2 in bpts2connect:
                        if np.all(df_likelihood[[bpt1, bpt2], index] > pcutoff):
                            ax.plot(
                                [df_x[bpt1, index], df_x[bpt2, index]],
                                [df_y[bpt1, index], df_y[bpt2, index]],
                                color=skeleton_color,
                                alpha=alphavalue,
                            )

                # Draw bodyparts
                for ind, num_bp, num_ind in bpts2color:
                    if df_likelihood[ind, index] > pcutoff:
                        if color_by == "bodypart":
                            color = colors(num_bp)
                        else:
                            color = colors(num_ind)
                        if trailpoints > 0:
                            ax.scatter(
                                df_x[ind][max(0, index - trailpoints) : index],
                                df_y[ind][max(0, index - trailpoints) : index],
                                s=dotsize**2,
                                color=color,
                                alpha=alphavalue * 0.75,
                            )
                        ax.scatter(
                            df_x[ind, index],
                            df_y[ind, index],
                            s=dotsize**2,
                            color=color,
                            alpha=alphavalue,
                        )
                ax.set_xlim(0, nx)
                ax.set_ylim(0, ny)
                ax.axis("off")
                ax.invert_yaxis()
                fig.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=0, hspace=0)
                if save_frames:
                    fig.savefig(imagename)
                writer.grab_frame()
                ax.clear()

    print(f"Labeled video {videooutname} successfully created.")
    plt.switch_backend(prev_backend)

create_labeled_video

create_labeled_video(
    config: str | Path,
    videos: list[str | Path],
    video_extensions: str | Sequence[str] | None = None,
    shuffle: int = 1,
    trainingsetindex: int = 0,
    filtered: bool = False,
    fastmode: bool = True,
    save_frames: bool = False,
    keypoints_only: bool = False,
    Frames2plot: list[int] | None = None,
    displayedbodyparts: list[str] | str = "all",
    displayedindividuals: list[str] | str = "all",
    codec: str = "mp4v",
    outputframerate: int | None = None,
    destfolder: Path | str | None = None,
    draw_skeleton: bool = False,
    trailpoints: int = 0,
    displaycropped: bool = False,
    color_by: str = "bodypart",
    modelprefix: str = "",
    init_weights: str = "",
    track_method: str = "",
    superanimal_name: str = "",
    pcutoff: float | None = None,
    skeleton: list = None,
    skeleton_color: str = "white",
    dotsize: int = 8,
    colormap: str = "rainbow",
    alphavalue: float = 0.5,
    overwrite: bool = False,
    confidence_to_alpha: bool | Callable[[float], float] = False,
    plot_bboxes: bool = True,
    bboxes_pcutoff: float | None = None,
    max_workers: int | None = None,
    **kwargs
)

Labels the bodyparts in a video.

Make sure the video is already analyzed by the function deeplabcut.analyze_videos.

Parameters:

Name Type Description Default

config

str | Path

Full path of the config.yaml file.

required

videos

list[str | Path]

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.

required

video_extensions

str | Sequence[str] | 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). Defaults to None.

None

shuffle

int

Number of shuffles of training dataset. Defaults to 1.

1

trainingsetindex

int

Integer specifying which TrainingsetFraction to use. Note that TrainingFraction is a list in config.yaml. Defaults to 0.

0

filtered

bool

If True, plot filtered output rather than frame-by-frame predictions. Filtered version can be calculated with deeplabcut.filterpredictions. Defaults to False.

False

fastmode

bool

If True, uses openCV (much faster but less customization of video) instead of matplotlib if False. You can also "save_frames" individually or not in the matplotlib mode (if you set the "save_frames" variable accordingly). However, using matplotlib to create the frames it therefore allows much more flexible (one can set transparency of markers, crop, and easily customize). Defaults to True.

True

save_frames

bool

If True, creates each frame individual and then combines into a video. Setting this to True is relatively slow as it stores all individual frames. Defaults to False.

False

keypoints_only

bool

By default, both video frames and keypoints are visible. If True, only the keypoints are shown. These clips are an hommage to Johansson movies, see https://www.youtube.com/watch?v=1F5ICP9SYLU and of course his seminal paper: "Visual perception of biological motion and a model for its analysis" by Gunnar Johansson in Perception & Psychophysics 1973. Defaults to False.

False

Frames2plot

List[int] or None

If not None and save_frames=True, plot frames at the given indices. E.g. Frames2plot=[0,11] plots the first and 12th frame. Defaults to None.

None

displayedbodyparts

list[str] or str

Body parts plotted in the video. If all, then all body parts from config.yaml are used. If a list of strings that are a subset of the full list. E.g. ['hand','Joystick'] for the demo Reaching-Mackenzie-2018-08-30/config.yaml to select only these body parts. Defaults to "all".

'all'

displayedindividuals

list[str] or str

Individuals plotted in the video. By default, all individuals present in the config will be shown. Defaults to "all".

'all'

codec

str

Codec for labeled video. For available options, see http://www.fourcc.org/codecs.php. Note that this depends on your ffmpeg installation. Defaults to "mp4v".

'mp4v'

outputframerate

int or None

Output frame rate for labeled video (only when saving frames). If None, uses the original video rate. Defaults to None.

None

destfolder

(Path, string or None)

Destination folder used for storing analysis data. If None, the path of the video file is used. Defaults to None.

None

draw_skeleton

bool

If True adds a line connecting the body parts making a skeleton on each frame. The body parts to be connected and the color of these connecting lines are specified in the config file. Defaults to False.

False

trailpoints

int

Number of previous frames whose body parts are plotted in a frame (for displaying history). Defaults to 0.

0

displaycropped

bool

Specifies whether only cropped frame is displayed (with labels analyzed therein), or the original frame with the labels analyzed in the cropped subset. Defaults to False.

False

color_by

string

Coloring rule. By default, each bodypart is colored differently. If set to 'individual', points belonging to a single individual are colored the same. Defaults to 'bodypart'.

'bodypart'

modelprefix

str

Directory containing the deeplabcut models to use when evaluating the network. By default, the models are assumed to exist in the project folder. Defaults to "".

''

init_weights

str

Checkpoint path to the super model. Defaults to "".

''

track_method

string

Tracker used to generate the data. Empty by default (corresponding to a single animal project). For multiple animals, must be either 'box', 'skeleton', or 'ellipse' and will be taken from the config.yaml file if none is given. Defaults to "".

''

superanimal_name

str

Name of the superanimal model. Defaults to "".

''

pcutoff

float

Overrides the pcutoff set in the project configuration to plot the trajectories. Defaults to None.

None

skeleton

list

Skeleton definition for drawing. Defaults to None.

None

skeleton_color

string

Color for the skeleton. Defaults to "white".

'white'

dotsize

int

Size of label dots to use. Defaults to 8.

8

colormap

str

Colormap to use for the labels. Defaults to "rainbow".

'rainbow'

alphavalue

float

Transparency of markers. Defaults to 0.5.

0.5

overwrite

bool

If True overwrites existing labeled videos. Defaults to False.

False

confidence_to_alpha

bool | Callable[[float], float]

If False, all keypoints use alpha=1. Otherwise, a function f: [0, 1] -> [0, 1] maps score to alpha. When True, f(x) = max(0, (x - pcutoff)/(1 - pcutoff)). Defaults to False.

False

plot_bboxes

bool

If using Pytorch and in Top-Down mode, setting this to true will also plot the bounding boxes. Defaults to True.

True

bboxes_pcutoff

float

If plotting bounding boxes, this overrides the bboxes_pcutoff set in the model configuration. Defaults to None.

None

max_workers

int | None

Maximum number of processes to use for multiprocessing. Set this parameter to limit the total RAM-usage of simultaneous processes. Default: no maximum (i.e. number of spawned processes is based on the number of cores and the number of input videos).

None

kwargs

dict

Additional arguments. For torch-based shuffles, can be used to specify: - snapshot_index - detector_snapshot_index

{}

Returns:

Type Description

list[bool]: True if the video is successfully created for each item in videos.

Examples:

Create the labeled video for a single video

deeplabcut.create_labeled_video(
    '/analysis/project/reaching-task/config.yaml',
    ['/analysis/project/videos/reachingvideo1.avi'],
)

Create the labeled video for a single video and store the individual frames

deeplabcut.create_labeled_video(
    '/analysis/project/reaching-task/config.yaml',
    ['/analysis/project/videos/reachingvideo1.avi'],
    fastmode=True,
    save_frames=True,
)

Create the labeled video for multiple videos

deeplabcut.create_labeled_video(
    '/analysis/project/reaching-task/config.yaml',
    [
        '/analysis/project/videos/reachingvideo1.avi',
        '/analysis/project/videos/reachingvideo2.avi',
    ],
)

Create the labeled video for all the videos with an .avi extension in a directory.

deeplabcut.create_labeled_video(
    '/analysis/project/reaching-task/config.yaml',
    ['/analysis/project/videos/'],
)

Create the labeled video for all the videos with an .mp4 extension in a directory.

deeplabcut.create_labeled_video(
    '/analysis/project/reaching-task/config.yaml',
    ['/analysis/project/videos/'],
    video_extensions='mp4',
)
Source code in deeplabcut/utils/make_labeled_video.py
@renamed_parameter(old="videotype", new="video_extensions", since="3.0.0")
def create_labeled_video(
    config: str | Path,
    videos: list[str | Path],
    video_extensions: str | Sequence[str] | None = None,
    shuffle: int = 1,
    trainingsetindex: int = 0,
    filtered: bool = False,
    fastmode: bool = True,
    save_frames: bool = False,
    keypoints_only: bool = False,
    Frames2plot: list[int] | None = None,
    displayedbodyparts: list[str] | str = "all",
    displayedindividuals: list[str] | str = "all",
    codec: str = "mp4v",
    outputframerate: int | None = None,
    destfolder: Path | str | None = None,
    draw_skeleton: bool = False,
    trailpoints: int = 0,
    displaycropped: bool = False,
    color_by: str = "bodypart",
    modelprefix: str = "",
    init_weights: str = "",
    track_method: str = "",
    superanimal_name: str = "",
    pcutoff: float | None = None,
    skeleton: list = None,
    skeleton_color: str = "white",
    dotsize: int = 8,
    colormap: str = "rainbow",
    alphavalue: float = 0.5,
    overwrite: bool = False,
    confidence_to_alpha: bool | Callable[[float], float] = False,
    plot_bboxes: bool = True,
    bboxes_pcutoff: float | None = None,
    max_workers: int | None = None,
    **kwargs,
):
    """Labels the bodyparts in a video.

    Make sure the video is already analyzed by the function
    ``deeplabcut.analyze_videos``.

    Args:
        config (str | Path): Full path of the config.yaml file.
        videos (list[str | Path]): 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.
        video_extensions (str | Sequence[str] | None, optional): 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). Defaults to None.
        shuffle (int, optional): Number of shuffles of training dataset. Defaults to 1.
        trainingsetindex (int, optional): Integer specifying which TrainingsetFraction to use.
            Note that TrainingFraction is a list in config.yaml. Defaults to 0.
        filtered (bool, optional): If True, plot filtered output rather than
            frame-by-frame predictions. Filtered version can be calculated with
            ``deeplabcut.filterpredictions``. Defaults to False.
        fastmode (bool, optional): If ``True``, uses openCV (much faster but less customization of video) instead
            of matplotlib if ``False``. You can also "save_frames" individually or not in
            the matplotlib mode (if you set the "save_frames" variable accordingly).
            However, using matplotlib to create the frames it therefore allows much more
            flexible (one can set transparency of markers, crop, and easily customize). Defaults to True.
        save_frames (bool, optional): If ``True``, creates each frame individual and then combines into a video.
            Setting this to ``True`` is relatively slow as it stores all individual frames. Defaults to False.
        keypoints_only (bool, optional): By default, both video frames and keypoints are visible. If ``True``, only the
            keypoints are shown. These clips are an hommage to Johansson movies,
            see https://www.youtube.com/watch?v=1F5ICP9SYLU and of course his seminal
            paper: "Visual perception of biological motion and a model for its analysis"
            by Gunnar Johansson in Perception & Psychophysics 1973. Defaults to False.
        Frames2plot (List[int] or None, optional): If not ``None`` and ``save_frames=True``,
            plot frames at the given indices. E.g. ``Frames2plot=[0,11]`` plots the first
            and 12th frame. Defaults to None.
        displayedbodyparts (list[str] or str, optional): Body parts plotted in the video. If ``all``, then all
            body parts from config.yaml are used. If a list of strings that are a subset of
            the full list. E.g. ['hand','Joystick'] for the demo
            Reaching-Mackenzie-2018-08-30/config.yaml to select only these body parts. Defaults to "all".
        displayedindividuals (list[str] or str, optional): Individuals plotted in the video.
            By default, all individuals present in the config will be shown. Defaults to "all".
        codec (str, optional): Codec for labeled video. For available options, see
            http://www.fourcc.org/codecs.php. Note that this depends on your ffmpeg
            installation. Defaults to "mp4v".
        outputframerate (int or None, optional): Output frame rate for labeled video (only
            when saving frames). If ``None``, uses the original video rate. Defaults to None.
        destfolder (Path, string or None, optional): Destination folder used for storing analysis data. If
            ``None``, the path of the video file is used. Defaults to None.
        draw_skeleton (bool, optional): If ``True`` adds a line connecting the body parts making a skeleton on each
            frame. The body parts to be connected and the color of these connecting lines
            are specified in the config file. Defaults to False.
        trailpoints (int, optional): Number of previous frames whose body parts are plotted in a frame
            (for displaying history). Defaults to 0.
        displaycropped (bool, optional): Specifies whether only cropped frame is displayed (with labels analyzed
            therein), or the original frame with the labels analyzed in the cropped subset. Defaults to False.
        color_by (string, optional): Coloring rule. By default, each bodypart is colored differently.
            If set to 'individual', points belonging to a single individual are colored the
            same. Defaults to 'bodypart'.
        modelprefix (str, optional): Directory containing the deeplabcut models to use when evaluating the network.
            By default, the models are assumed to exist in the project folder. Defaults to "".
        init_weights (str, optional): Checkpoint path to the super model. Defaults to "".
        track_method (string, optional): Tracker used to generate the data.
            Empty by default (corresponding to a single animal project).
            For multiple animals, must be either 'box', 'skeleton', or 'ellipse' and will
            be taken from the config.yaml file if none is given. Defaults to "".
        superanimal_name (str, optional): Name of the superanimal model. Defaults to "".
        pcutoff (float, optional): Overrides the pcutoff set in the project configuration to plot the trajectories.
            Defaults to None.
        skeleton (list, optional): Skeleton definition for drawing. Defaults to None.
        skeleton_color (string, optional): Color for the skeleton. Defaults to "white".
        dotsize (int, optional): Size of label dots to use. Defaults to 8.
        colormap (str, optional): Colormap to use for the labels. Defaults to "rainbow".
        alphavalue (float, optional): Transparency of markers. Defaults to 0.5.
        overwrite (bool, optional): If ``True`` overwrites existing labeled videos. Defaults to False.
        confidence_to_alpha (bool | Callable[[float], float], optional): If False, all keypoints
            use alpha=1. Otherwise, a function f: [0, 1] -> [0, 1] maps score to alpha.
            When True, f(x) = max(0, (x - pcutoff)/(1 - pcutoff)). Defaults to False.
        plot_bboxes (bool, optional): If using Pytorch and in Top-Down mode,
            setting this to true will also plot the bounding boxes. Defaults to True.
        bboxes_pcutoff (float, optional): If plotting bounding boxes, this overrides the bboxes_pcutoff
            set in the model configuration. Defaults to None.
        max_workers (int | None): Maximum number of processes to use for multiprocessing.
            Set this parameter to limit the total RAM-usage of simultaneous processes.
            Default: no maximum (i.e. number of spawned processes is based on the number of
            cores and the number of input videos).
        kwargs (dict, optional): Additional arguments.
            For torch-based shuffles, can be used to specify:
                - snapshot_index
                - detector_snapshot_index

    Returns:
        list[bool]: ``True`` if the video is successfully created for each item in ``videos``.

    Examples:
        Create the labeled video for a single video

            deeplabcut.create_labeled_video(
                '/analysis/project/reaching-task/config.yaml',
                ['/analysis/project/videos/reachingvideo1.avi'],
            )
        Create the labeled video for a single video and store the individual frames

            deeplabcut.create_labeled_video(
                '/analysis/project/reaching-task/config.yaml',
                ['/analysis/project/videos/reachingvideo1.avi'],
                fastmode=True,
                save_frames=True,
            )

        Create the labeled video for multiple videos

            deeplabcut.create_labeled_video(
                '/analysis/project/reaching-task/config.yaml',
                [
                    '/analysis/project/videos/reachingvideo1.avi',
                    '/analysis/project/videos/reachingvideo2.avi',
                ],
            )

        Create the labeled video for all the videos with an .avi extension in a directory.

            deeplabcut.create_labeled_video(
                '/analysis/project/reaching-task/config.yaml',
                ['/analysis/project/videos/'],
            )

        Create the labeled video for all the videos with an .mp4 extension in a directory.

            deeplabcut.create_labeled_video(
                '/analysis/project/reaching-task/config.yaml',
                ['/analysis/project/videos/'],
                video_extensions='mp4',
            )
    """
    if config != "":
        config = Path(config)
    if destfolder is not None:
        destfolder = Path(destfolder)
    if skeleton is None:
        skeleton = []
    if config == "":
        if pcutoff is None:
            pcutoff = 0.6
        if bboxes_pcutoff is None:
            bboxes_pcutoff = 0.6

        individuals = [""]
        uniquebodyparts = []
    else:
        cfg = auxiliaryfunctions.read_config(config)
        train_fraction = cfg["TrainingFraction"][trainingsetindex]
        track_method = auxfun_multianimal.get_track_method(cfg, track_method=track_method)
        if pcutoff is None:
            pcutoff = cfg["pcutoff"]

        # Get individuals from the config
        individuals = cfg.get("individuals", [""])
        uniquebodyparts = cfg.get("uniquebodyparts", [])

        # Only for PyTorch engine - check if the shuffle was fine-tuned from a
        #  SuperAnimal model with memory replay -> SuperAnimal bodyparts must be used
        model_folder = auxiliaryfunctions.get_model_folder(
            train_fraction,
            shuffle,
            cfg,
            modelprefix,
            engine=Engine.PYTORCH,
        )
        model_config_path = Path(config).parent / model_folder / "train" / Engine.PYTORCH.pose_cfg_name
        if model_config_path.exists():
            model_config = PoseConfig.from_yaml(model_config_path)
            if model_config.select("train_settings.weight_init.memory_replay"):
                superanimal_name = model_config["train_settings"]["weight_init"]["dataset"]
            if bboxes_pcutoff is None:
                bboxes_pcutoff = model_config.select("detector.model.box_score_thresh") or 0.6
        else:
            if bboxes_pcutoff is None:
                bboxes_pcutoff = 0.6

    if init_weights == "":
        DLCscorer, DLCscorerlegacy = auxiliaryfunctions.get_scorer_name(
            cfg,
            shuffle,
            train_fraction,
            modelprefix=modelprefix,
            **kwargs,
        )  # automatically loads corresponding model (even training iteration based on snapshot index)
    else:
        DLCscorer = "DLC_" + Path(init_weights).stem
        DLCscorerlegacy = "DLC_" + Path(init_weights).stem

    if save_frames:
        fastmode = False  # otherwise one cannot save frames
        keypoints_only = False

    # parse the alpha selection function
    if isinstance(confidence_to_alpha, bool):
        confidence_to_alpha = _get_default_conf_to_alpha(confidence_to_alpha, pcutoff)

    if superanimal_name != "":
        dlc_root_path = auxiliaryfunctions.get_deeplabcut_path()
        test_cfg = auxiliaryfunctions.read_plainconfig(
            dlc_root_path / "modelzoo" / "project_configs" / f"{superanimal_name}.yaml"
        )

        bodyparts = test_cfg["bodyparts"]
        cfg = {
            "skeleton": skeleton,
            "skeleton_color": skeleton_color,
            "pcutoff": pcutoff,
            "dotsize": dotsize,
            "alphavalue": alphavalue,
            "colormap": colormap,
            "bodyparts": bodyparts,
            "multianimalbodyparts": bodyparts,
            "individuals": individuals,
            "uniquebodyparts": uniquebodyparts,
        }
    else:
        bodyparts = auxiliaryfunctions.intersection_of_body_parts_and_ones_given_by_user(cfg, displayedbodyparts)

    if draw_skeleton:
        bodyparts2connect = cfg["skeleton"]
        if displayedbodyparts != "all":
            bodyparts2connect = [
                pair for pair in bodyparts2connect if all(element in displayedbodyparts for element in pair)
            ]
        skeleton_color = cfg["skeleton_color"]
    else:
        bodyparts2connect = None
        skeleton_color = None

    start_path = Path.cwd()
    Videos = collect_video_paths(videos, extensions=video_extensions)

    if not Videos:
        return []

    func = partial(
        proc_video,
        videos,
        destfolder,
        filtered,
        DLCscorer,
        DLCscorerlegacy,
        track_method,
        cfg,
        displayedindividuals,
        color_by,
        bodyparts,
        codec,
        bodyparts2connect,
        trailpoints,
        save_frames,
        outputframerate,
        Frames2plot,
        draw_skeleton,
        skeleton_color,
        displaycropped,
        fastmode,
        keypoints_only,
        overwrite,
        init_weights=init_weights,
        pcutoff=pcutoff,
        confidence_to_alpha=confidence_to_alpha,
        plot_bboxes=plot_bboxes,
        bboxes_pcutoff=bboxes_pcutoff,
    )

    if get_start_method() == "fork":
        n_workers = max_workers or min(os.cpu_count(), len(Videos))
        with Pool(n_workers) as pool:
            results = pool.map(func, Videos)
    else:
        results = []
        for video in Videos:
            results.append(func(video))

    os.chdir(start_path)
    return results

create_video_with_all_detections

create_video_with_all_detections(
    config: str | Path,
    videos: list[str | Path],
    video_extensions: str | Sequence[str] | None = None,
    shuffle=1,
    trainingsetindex=0,
    displayedbodyparts="all",
    cropping: list[int] | None = None,
    destfolder=None,
    modelprefix="",
    confidence_to_alpha: bool | Callable[[float], float] = False,
    plot_bboxes: bool = True,
    **kwargs
)

Create a video labeled with all the detections stored in a '*_full.pickle' file.

Parameters:

Name Type Description Default

config

str | Path

Absolute path to the config.yaml file.

required

videos

list[str | Path]

Full paths to videos for analysis, or a directory where all videos with the same extension are stored.

required

video_extensions

str | Sequence[str] | 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). Defaults to None.

None

shuffle

int

Number of shuffles of training dataset. Defaults to 1.

1

trainingsetindex

int

Integer specifying which TrainingsetFraction to use. By default the first (note that TrainingFraction is a list in config.yaml).

0

displayedbodyparts

list of strings

Body parts plotted in the video. Either all, then all body parts from config.yaml are used or a list of strings that are a subset of the full list. E.g. ['hand','Joystick'] for the demo Reaching-Mackenzie-2018-08-30/config.yaml to select only these two body parts.

'all'

cropping

list[int]

If passed in, [x1, x2, y1, y2] crop coordinates shift detections appropriately. Defaults to None.

None

destfolder

string

Destination folder used for storing analysis data (default is the path of the video).

None

confidence_to_alpha

bool | Callable[[float], float]

If False, all keypoints use alpha=1. Otherwise, a function f: [0, 1] -> [0, 1] maps score to alpha. When True, f(x) = x. Defaults to False.

False

plot_bboxes

bool

If detections were produced using a Pytorch Top-Down model, setting this parameter to True will also plot the bounding boxes generated by the detector. Defaults to True.

True

kwargs

dict

Additional arguments. For torch-based shuffles, can be used to specify: - snapshot_index - detector_snapshot_index

{}
Source code in deeplabcut/utils/make_labeled_video.py
@renamed_parameter(old="videotype", new="video_extensions", since="3.0.0")
def create_video_with_all_detections(
    config: str | Path,
    videos: list[str | Path],
    video_extensions: str | Sequence[str] | None = None,
    shuffle=1,
    trainingsetindex=0,
    displayedbodyparts="all",
    cropping: list[int] | None = None,
    destfolder=None,
    modelprefix="",
    confidence_to_alpha: bool | Callable[[float], float] = False,
    plot_bboxes: bool = True,
    **kwargs,
):
    """Create a video labeled with all the detections stored in a '*_full.pickle' file.

    Args:
        config (str | Path): Absolute path to the config.yaml file.
        videos (list[str | Path]): Full paths to videos for analysis, or a directory where all
            videos with the same extension are stored.
        video_extensions (str | Sequence[str] | None, optional): 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). Defaults to None.
        shuffle (int, optional): Number of shuffles of training dataset. Defaults to 1.
        trainingsetindex (int, optional): Integer specifying which TrainingsetFraction to use.
            By default the first (note that TrainingFraction is a list in config.yaml).
        displayedbodyparts (list of strings, optional): Body parts plotted in the video.
            Either ``all``, then all body parts from config.yaml are used or
            a list of strings that are a subset of the full list.
            E.g. ['hand','Joystick'] for the demo Reaching-Mackenzie-2018-08-30/config.yaml
            to select only these two body parts.
        cropping (list[int], optional): If passed in, [x1, x2, y1, y2] crop coordinates
            shift detections appropriately. Defaults to None.
        destfolder (string, optional): Destination folder used for storing analysis data
            (default is the path of the video).
        confidence_to_alpha (bool | Callable[[float], float], optional): If False, all keypoints
            use alpha=1. Otherwise, a function f: [0, 1] -> [0, 1] maps score to alpha.
            When True, f(x) = x. Defaults to False.
        plot_bboxes (bool, optional): If detections were produced using a Pytorch Top-Down model,
            setting this parameter to True will also plot
            the bounding boxes generated by the detector. Defaults to True.
        kwargs (dict, optional): Additional arguments.
            For torch-based shuffles, can be used to specify:
                - snapshot_index
                - detector_snapshot_index
    """
    import re

    from deeplabcut.core.inferenceutils import Assembler

    cfg = auxiliaryfunctions.read_config(config)
    trainFraction = cfg["TrainingFraction"][trainingsetindex]
    DLCscorername, _ = auxiliaryfunctions.get_scorer_name(
        cfg,
        shuffle,
        trainFraction,
        modelprefix=modelprefix,
        **kwargs,
    )

    videos = collect_video_paths(videos, extensions=video_extensions)
    if not videos:
        return

    if isinstance(confidence_to_alpha, bool):
        confidence_to_alpha = _get_default_conf_to_alpha(confidence_to_alpha, 0)

    for video in videos:
        videofolder = str(Path(video).with_suffix(""))

        if destfolder is None:
            outputname = f"{videofolder + DLCscorername}_full.mp4"
            full_pickle = videofolder + DLCscorername + "_full.pickle"
        else:
            auxiliaryfunctions.attempt_to_make_folder(destfolder)
            outputname = str(Path(destfolder) / (Path(video).stem + DLCscorername + "_full.mp4"))
            full_pickle = str(Path(destfolder) / (Path(video).stem + DLCscorername + "_full.pickle"))

        if not Path(outputname).is_file():
            video_name = str(Path(video).stem)
            print("Creating labeled video for ", video_name)
            h5file = full_pickle.replace("_full.pickle", ".h5")
            data, metadata = auxfun_multianimal.LoadFullMultiAnimalData(h5file)
            data = dict(data)  # Cast to dict (making a copy) so items can safely be popped

            x1, y1 = 0, 0
            if cropping is not None:
                x1, _, y1, _ = cropping
            # TODO @deruyter92: This pattern should be refactored throughout the codebase
            # it is reading a config value that is supposed to be missing / None.
            elif (metadata.get("data") or {}).get("cropping"):
                x1, _, y1, _ = metadata["data"]["cropping_parameters"]

            header = data.pop("metadata")
            all_jointnames = header["all_joints_names"]

            if displayedbodyparts == "all":
                numjoints = len(all_jointnames)
                bpts = range(numjoints)
            else:  # select only "displayedbodyparts"
                bpts = []
                for bptindex, bp in enumerate(all_jointnames):
                    if bp in displayedbodyparts:
                        bpts.append(bptindex)
                numjoints = len(bpts)
            frame_names = list(data)
            frames = [int(re.findall(r"\d+", name)[0]) for name in frame_names]
            colorclass = plt.cm.ScalarMappable(cmap=cfg["colormap"])
            C = colorclass.to_rgba(np.linspace(0, 1, numjoints))
            colors = (C[:, :3] * 255).astype(np.uint8)

            pcutoff = cfg["pcutoff"]
            dotsize = cfg["dotsize"]
            clip = vp(fname=video, sname=outputname, codec="mp4v")
            ny, nx = clip.height, clip.width

            bboxes_pcutoff = 0.6
            if pytorch_cfg := (metadata.get("data") or {}).get("pytorch-config"):
                bboxes_pcutoff = PoseConfig.from_any(pytorch_cfg).select("detector.model.box_score_thresh") or 0.6
            bboxes_color = (255, 0, 0)

            for n in trange(clip.nframes):
                frame = clip.load_frame()
                if frame is None:
                    continue
                try:
                    ind = frames.index(n)

                    # Draw bounding boxes of required and present
                    if plot_bboxes and "bboxes" in data[frame_names[ind]] and "bbox_scores" in data[frame_names[ind]]:
                        bboxes = data[frame_names[ind]]["bboxes"]
                        bbox_scores = data[frame_names[ind]]["bbox_scores"]
                        n_bboxes = bboxes.shape[0]
                        for i in range(n_bboxes):
                            bbox = bboxes[i, :]
                            x, y = bbox[0], bbox[1]
                            x += x1
                            y += y1
                            w, h = bbox[2], bbox[3]
                            confidence = bbox_scores[i]
                            if confidence < bboxes_pcutoff:
                                continue
                            rect_coords = rectangle_perimeter(start=(y, x), extent=(h, w))

                            set_color(
                                frame,
                                rect_coords,
                                bboxes_color,
                            )

                    # Draw detected bodyparts
                    dets = Assembler._flatten_detections(data[frame_names[ind]])
                    for det in dets:
                        if det.label not in bpts or det.confidence < pcutoff:
                            continue
                        x, y = det.pos
                        x += x1
                        y += y1
                        rr, cc = disk((y, x), dotsize, shape=(ny, nx))
                        alpha = 1
                        if confidence_to_alpha is not None:
                            alpha = confidence_to_alpha(det.confidence)

                        set_color(
                            frame,
                            (rr, cc),
                            colors[bpts.index(det.label)],
                            alpha,
                        )
                except ValueError as err:  # No data stored for that particular frame
                    print(n, f"no data: {err}")
                try:
                    clip.save_frame(frame)
                except Exception:
                    print(n, "frame writing error.")
            clip.close()
        else:
            print("Detections already plotted, ", outputname)

proc_video

proc_video(
    videos,
    destfolder,
    filtered,
    DLCscorer,
    DLCscorerlegacy,
    track_method,
    cfg,
    individuals,
    color_by,
    bodyparts,
    codec,
    bodyparts2connect,
    trailpoints,
    save_frames,
    outputframerate,
    Frames2plot,
    draw_skeleton,
    skeleton_color,
    displaycropped,
    fastmode,
    keypoints_only,
    overwrite,
    video,
    init_weights="",
    pcutoff: float | None = None,
    confidence_to_alpha: Callable[[float], float] | None = None,
    plot_bboxes: bool = True,
    bboxes_pcutoff: float = 0.6,
)

Helper function for create_labeled_video.

Returns:

Name Type Description
bool

True if a video is successfully created.

Source code in deeplabcut/utils/make_labeled_video.py
def proc_video(
    videos,
    destfolder,
    filtered,
    DLCscorer,
    DLCscorerlegacy,
    track_method,
    cfg,
    individuals,
    color_by,
    bodyparts,
    codec,
    bodyparts2connect,
    trailpoints,
    save_frames,
    outputframerate,
    Frames2plot,
    draw_skeleton,
    skeleton_color,
    displaycropped,
    fastmode,
    keypoints_only,
    overwrite,
    video,
    init_weights="",
    pcutoff: float | None = None,
    confidence_to_alpha: Callable[[float], float] | None = None,
    plot_bboxes: bool = True,
    bboxes_pcutoff: float = 0.6,
):
    """Helper function for create_labeled_video.

    Returns:
        bool: ``True`` if a video is successfully created.
    """
    videofolder = Path(video).parent
    if destfolder is None:
        destfolder = videofolder  # where your folder with videos is.
    else:
        destfolder = Path(destfolder)

    if pcutoff is None:
        pcutoff = cfg["pcutoff"]

    auxiliaryfunctions.attempt_to_make_folder(destfolder)

    os.chdir(destfolder)  # THE VIDEO IS STILL IN THE VIDEO FOLDER
    print(f"Starting to process video: {video}")
    vname = str(Path(video).stem)

    if init_weights != "":
        DLCscorer = "DLC_" + Path(init_weights).stem
        DLCscorerlegacy = "DLC_" + Path(init_weights).stem

    if filtered:
        videooutname1 = destfolder / f"{vname}{DLCscorer}filtered_labeled.mp4"
        videooutname2 = destfolder / f"{vname}{DLCscorerlegacy}filtered_labeled.mp4"
    else:
        videooutname1 = destfolder / f"{vname}{DLCscorer}_labeled.mp4"
        videooutname2 = destfolder / f"{vname}{DLCscorerlegacy}_labeled.mp4"

    if (videooutname1.is_file() or videooutname2.is_file()) and not overwrite:
        print(f"Labeled video {vname} already created.")
        return True
    else:
        print(f"Loading {video} and data.")
        try:
            df, filepath, _, _ = auxiliaryfunctions.load_analyzed_data(
                destfolder, vname, DLCscorer, filtered, track_method
            )
            metadata = auxiliaryfunctions.load_video_metadata(destfolder, vname, DLCscorer)
            if cfg.get("multianimalproject", False):
                s = "_id" if color_by == "individual" else "_bp"
            else:
                s = ""

            videooutname = filepath.replace(".h5", f"{s}_p{int(100 * pcutoff)}_labeled.mp4")
            if Path(videooutname).is_file() and not overwrite:
                print("Labeled video already created. Skipping...")
                return

            if individuals != "all":
                if isinstance(individuals, str):
                    individuals = [individuals]

                if all(individuals) and "individuals" in df.columns.names:
                    mask = df.columns.get_level_values("individuals").isin(individuals)
                    df = df.loc[:, mask]

            cropping = metadata["data"]["cropping"]
            [x1, x2, y1, y2] = metadata["data"]["cropping_parameters"]
            labeled_bpts = [bp for bp in df.columns.get_level_values("bodyparts").unique() if bp in bodyparts]

            # The full data file is not created for single-animal TensorFlow models
            try:
                full_data = auxiliaryfunctions.load_video_full_data(destfolder, vname, DLCscorer)
                frames_dict = {
                    int(key.replace("frame", "")): value
                    for key, value in full_data.items()
                    if key.startswith("frame") and key[5:].isdigit()
                }
                bboxes_list = None
                if "bboxes" in frames_dict.get(min(frames_dict.keys()), {}):
                    bboxes_list = [frames_dict[key] for key in sorted(frames_dict.keys())]
            except FileNotFoundError:
                bboxes_list = None

            if keypoints_only:
                # Mask rather than drop unwanted bodyparts to ensure consistent coloring
                mask = df.columns.get_level_values("bodyparts").isin(bodyparts)
                df.loc[:, ~mask] = np.nan
                inds = None
                if bodyparts2connect:
                    all_bpts = df.columns.get_level_values("bodyparts")[::3]
                    inds = get_segment_indices(bodyparts2connect, all_bpts)
                clip = vp(fname=video, fps=outputframerate)
                create_video_with_keypoints_only(
                    df,
                    videooutname,
                    inds,
                    pcutoff,
                    cfg["dotsize"],
                    cfg["alphavalue"],
                    skeleton_color=skeleton_color,
                    color_by=color_by,
                    colormap=cfg["colormap"],
                    fps=clip.fps,
                )
                clip.close()
            elif not fastmode:
                tmpfolder = str(Path(str(videofolder)) / ("temp-" + vname))
                if save_frames:
                    auxiliaryfunctions.attempt_to_make_folder(tmpfolder)
                clip = vp(video)
                CreateVideoSlow(
                    videooutname,
                    clip,
                    df,
                    tmpfolder,
                    cfg["dotsize"],
                    cfg["colormap"],
                    cfg["alphavalue"],
                    pcutoff,
                    trailpoints,
                    cropping,
                    x1,
                    x2,
                    y1,
                    y2,
                    save_frames,
                    labeled_bpts,
                    outputframerate,
                    Frames2plot,
                    bodyparts2connect,
                    skeleton_color,
                    draw_skeleton,
                    displaycropped,
                    color_by,
                    plot_bboxes=plot_bboxes,
                    bboxes_list=bboxes_list,
                    bboxes_pcutoff=bboxes_pcutoff,
                )
                clip.close()
            else:
                create_video(
                    video,
                    filepath,
                    keypoints2show=labeled_bpts,
                    animals2show=individuals,
                    bbox=(x1, x2, y1, y2),
                    codec=codec,
                    output_path=videooutname,
                    pcutoff=pcutoff,
                    dotsize=cfg["dotsize"],
                    cmap=cfg["colormap"],
                    color_by=color_by,
                    skeleton_edges=bodyparts2connect,
                    skeleton_color=skeleton_color,
                    trailpoints=trailpoints,
                    fps=outputframerate,
                    display_cropped=displaycropped,
                    confidence_to_alpha=confidence_to_alpha,
                    plot_bboxes=plot_bboxes,
                    bboxes_list=bboxes_list,
                    bboxes_pcutoff=bboxes_pcutoff,
                )

            return True

        except FileNotFoundError as e:
            print(e)
            return False