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
47
48
49
50
51
52
53
54
55
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(pos), Position(size), 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
27
28
29
30
31
@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
57
58
59
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
def __init__(
    self,
    ranges: FrameRangeN | FrameRangesN | None = None,
    bound: BoundingBox | None = None,
    *,
    blur: bool = False,
    refframes: int | list[int | None] | None = None
) -> None:
    """
    :param ranges:          The frame ranges that the mask should be applied to.
    :param 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.
    :param blur:            Whether to apply a box blur effect to the mask.
    :param 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
27
28
29
30
31
@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
100
101
102
103
104
105
106
107
108
109
110
111
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
@limiter
def get_mask(self, clip: vs.VideoNode, /, ref: vs.VideoNode, **kwargs: Any) -> ConstantFormatVideoNode:
    """
    Get the constructed mask

    :param clip:        Source clip.
    :param ref:         Reference clip.
    :param **kwargs:    Keyword arguments passed to the internal `_mask` method.
    :return:            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
27
28
29
30
31
@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
23
24
25
@abstractmethod
def get_mask(self, clip: vs.VideoNode, /, *args: Any, **kwargs: Any) -> ConstantFormatVideoNode:
    ...