Skip to content

abstract

Classes:

BoundingBox

BoundingBox(
    width: int,
    height: int,
    offset_x: int,
    offset_y: int,
    /,
    *,
    invert: bool = False,
)
BoundingBox(
    size: tuple[int, int] | Size,
    pos: tuple[int, int] | Position,
    /,
    *,
    invert: bool = False,
)
BoundingBox(*args: Any, invert: bool = False)

Bases: GeneralMask

Methods:

Attributes:

Source code
57
58
59
60
61
62
63
64
65
def __init__(self, *args: Any, invert: bool = False) -> None:
    if len(args) == 4:
        size, pos = (args[0], args[1]), (args[2], args[3])
    elif len(args) == 2:
        size, pos = args[0], args[1]
    else:
        raise CustomTypeError(None, self.__class__, args)

    self.size, self.pos, self.invert = Size(size), Position(pos), invert

invert instance-attribute

invert: bool

pos instance-attribute

pos: Position

size instance-attribute

size: Size

apply_mask

apply_mask(
    _clipa: VideoNode,
    _clipb: VideoNode,
    _ref: VideoNode | None = None,
    /,
    **kwargs: Any,
) -> ConstantFormatVideoNode
Source code
37
38
39
40
41
@inject_self.init_kwargs.clean
def apply_mask(
    self, _clipa: vs.VideoNode, _clipb: vs.VideoNode, _ref: vs.VideoNode | None = None, /, **kwargs: Any
) -> ConstantFormatVideoNode:
    return _clipa.std.MaskedMerge(_clipb, self.get_mask(_ref or _clipa, **kwargs))

get_mask

get_mask(
    ref: VideoNode, /, *args: Any, **kwargs: Any
) -> ConstantFormatVideoNode
Source code
67
68
69
70
def get_mask(self, ref: vs.VideoNode, /, *args: Any, **kwargs: Any) -> ConstantFormatVideoNode:
    from .utils import squaremask

    return squaremask(ref, self.size.x, self.size.y, self.pos.x, self.pos.y, self.invert, False, self.get_mask)

DeferredMask

DeferredMask(
    ranges: FrameRangeN | FrameRangesN | None = None,
    bound: BoundingBox | None = None,
    *,
    blur: bool = False,
    refframes: int | list[int | None] | None = None
)

Bases: GeneralMask

Abstract DeferredMask interface

Parameters:

  • ranges

    (FrameRangeN | FrameRangesN | None, default: None ) –

    The frame ranges that the mask should be applied to.

  • bound

    (BoundingBox | None, default: None ) –

    An optional bounding box that defines the area of the frame where the mask will be applied. If None, the mask applies to the whole frame.

  • blur

    (bool, default: False ) –

    Whether to apply a box blur effect to the mask.

  • refframes

    (int | list[int | None] | None, default: None ) –

    A list of reference frames used in building the final mask for each specified range. Must have the same length as ranges.

Methods:

Attributes:

Source code
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
def __init__(
    self,
    ranges: FrameRangeN | FrameRangesN | None = None,
    bound: BoundingBox | None = None,
    *,
    blur: bool = False,
    refframes: int | list[int | None] | None = None,
) -> None:
    """
    Args:
        ranges: The frame ranges that the mask should be applied to.
        bound: An optional bounding box that defines the area of the frame where the mask will be applied. If None,
            the mask applies to the whole frame.
        blur: Whether to apply a box blur effect to the mask.
        refframes: A list of reference frames used in building the final mask for each specified range. Must have
            the same length as `ranges`.
    """
    self.ranges = ranges if isinstance(ranges, Sequence) else [(0, None)] if ranges is None else [ranges]
    self.blur = blur
    self.bound = bound

    if refframes is None:
        self.refframes = []
    else:
        self.refframes = refframes if isinstance(refframes, list) else normalize_seq(refframes, len(self.ranges))

    if len(self.refframes) > 0 and len(self.refframes) != len(self.ranges):
        raise FramesLengthError(self.__class__, "", "Received reference frame and range list size mismatch!")

blur instance-attribute

blur: bool = blur

bound instance-attribute

bound: BoundingBox | None = bound

ranges instance-attribute

ranges: FrameRangesN = (
    ranges
    if isinstance(ranges, Sequence)
    else [(0, None)] if ranges is None else [ranges]
)

refframes instance-attribute

refframes: list[int | None]

apply_mask

apply_mask(
    _clipa: VideoNode,
    _clipb: VideoNode,
    _ref: VideoNode | None = None,
    /,
    **kwargs: Any,
) -> ConstantFormatVideoNode
Source code
37
38
39
40
41
@inject_self.init_kwargs.clean
def apply_mask(
    self, _clipa: vs.VideoNode, _clipb: vs.VideoNode, _ref: vs.VideoNode | None = None, /, **kwargs: Any
) -> ConstantFormatVideoNode:
    return _clipa.std.MaskedMerge(_clipb, self.get_mask(_ref or _clipa, **kwargs))

get_mask

get_mask(
    clip: VideoNode, /, ref: VideoNode, **kwargs: Any
) -> ConstantFormatVideoNode

Get the constructed mask

Parameters:

  • clip

    (VideoNode) –

    Source clip.

  • ref

    (VideoNode) –

    Reference clip.

  • **kwargs

    (Any, default: {} ) –

    Keyword arguments passed to the internal _mask method.

Returns:

  • ConstantFormatVideoNode

    Constructed mask

Source code
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
@limiter
def get_mask(self, clip: vs.VideoNode, /, ref: vs.VideoNode, **kwargs: Any) -> ConstantFormatVideoNode:
    """
    Get the constructed mask

    Args:
        clip: Source clip.
        ref: Reference clip.
        **kwargs: Keyword arguments passed to the internal `_mask` method.

    Returns:
        Constructed mask
    """
    assert check_variable(clip, self.get_mask)
    assert check_variable(ref, self.get_mask)

    if self.refframes:
        hm = vs.core.std.BlankClip(
            ref, format=ref.format.replace(color_family=vs.GRAY, subsampling_h=0, subsampling_w=0).id, keep=True
        )

        for ran, rf in zip(self.ranges, self.refframes):
            if rf is None:
                rf = ref.num_frames - 1
            elif rf < 0:
                rf = ref.num_frames - 1 + rf

            mask = depth(
                self._mask(clip[rf], ref[rf], **kwargs), clip, range_out=ColorRange.FULL, range_in=ColorRange.FULL
            )
            mask = vs.core.std.Loop(mask, hm.num_frames)

            hm = replace_ranges(hm, ExprOp.MAX.combine(hm, mask), ran)
    else:
        hm = depth(self._mask(clip, ref, **kwargs), clip, range_out=ColorRange.FULL, range_in=ColorRange.FULL)

    if self.bound:
        bm = self.bound.get_mask(hm, **kwargs)

        if self.blur:
            bm = box_blur(bm, 5, 5)

        hm = hm.std.BlankClip(keep=True).std.MaskedMerge(hm, bm)

    return hm

GeneralMask

Bases: ABC

Abstract GeneralMask interface

Methods:

apply_mask

apply_mask(
    _clipa: VideoNode,
    _clipb: VideoNode,
    _ref: VideoNode | None = None,
    /,
    **kwargs: Any,
) -> ConstantFormatVideoNode
Source code
37
38
39
40
41
@inject_self.init_kwargs.clean
def apply_mask(
    self, _clipa: vs.VideoNode, _clipb: vs.VideoNode, _ref: vs.VideoNode | None = None, /, **kwargs: Any
) -> ConstantFormatVideoNode:
    return _clipa.std.MaskedMerge(_clipb, self.get_mask(_ref or _clipa, **kwargs))

get_mask abstractmethod

get_mask(
    clip: VideoNode, /, *args: Any, **kwargs: Any
) -> ConstantFormatVideoNode
Source code
34
35
@abstractmethod
def get_mask(self, clip: vs.VideoNode, /, *args: Any, **kwargs: Any) -> ConstantFormatVideoNode: ...