Skip to content

funcs

ClampScaler dataclass

ClampScaler(
    ref_scaler: ScalerT,
    strength: int = 80,
    overshoot: float | None = None,
    undershoot: float | None = None,
    limit: RepairMode | bool = True,
    operator: Literal[MAX, MIN] | None = MIN,
    masked: bool = True,
    reference: ScalerT | VideoNode = Nnedi3,
    *,
    kernel: KernelT | None = None,
    scaler: ScalerT | None = None,
    shifter: KernelT | None = None
)

Bases: GenericScaler

Clamp a reference Scaler.

func instance-attribute

func = func

kernel class-attribute instance-attribute

kernel: KernelT | None = field(default=None, kw_only=True)

Base kernel to be used for certain scaling/shifting/resampling operations. Must be specified and defaults to catrom

kernel_radius property

kernel_radius: int

kwargs instance-attribute

kwargs = kwargs

limit class-attribute instance-attribute

limit: RepairMode | bool = True

Whether to use under/overshoot limit (True) or a reference repaired clip for limiting.

masked class-attribute instance-attribute

masked: bool = True

Whether to mask with a ringing mask or not.

operator class-attribute instance-attribute

operator: Literal[MAX, MIN] | None = MIN

Whether to take the brightest or darkest pixels in the merge.

overshoot class-attribute instance-attribute

overshoot: float | None = None

Overshoot threshold.

ref_scaler instance-attribute

ref_scaler: ScalerT

Scaler to clamp.

reference class-attribute instance-attribute

reference: ScalerT | VideoNode = Nnedi3

Reference Scaler used to clamp ref_scaler

scale_function instance-attribute

scale_function: GenericVSFunction

Scale function called internally when scaling

scaler class-attribute instance-attribute

scaler: ScalerT | None = field(default=None, kw_only=True)

Scaler used for scaling operations. Defaults to kernel.

shifter class-attribute instance-attribute

shifter: KernelT | None = field(default=None, kw_only=True)

Kernel used for shifting operations. Defaults to kernel.

strength class-attribute instance-attribute

strength: int = 80

Strength of clamping.

undershoot class-attribute instance-attribute

undershoot: float | None = None

Undershoot threshold.

ensure_obj classmethod

ensure_obj(
    scaler: str | type[BaseScalerT] | BaseScalerT | None = None,
    /,
    func_except: FuncExceptT | None = None,
) -> BaseScalerT
Source code
186
187
188
189
190
191
192
193
@classmethod
def ensure_obj(
    cls: type[BaseScalerT], scaler: str | type[BaseScalerT] | BaseScalerT | None = None, /,
    func_except: FuncExceptT | None = None
) -> BaseScalerT:
    return _base_ensure_obj(
        cls, (mro := cls.mro())[mro.index(BaseScaler) - 1], scaler, cls._err_class, [], func_except
    )

ensure_scaler

ensure_scaler(scaler: ScalerT) -> Scaler
Source code
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
def ensure_scaler(self, scaler: ScalerT) -> Scaler:
    from dataclasses import is_dataclass, replace

    scaler_obj = Scaler.ensure_obj(scaler, self.__class__)

    if is_dataclass(scaler_obj):
        from inspect import Signature  #type: ignore[unreachable]

        kwargs = dict[str, ScalerT]()

        init_keys = Signature.from_callable(scaler_obj.__init__).parameters.keys()

        if 'kernel' in init_keys:
            kwargs.update(kernel=self.kernel or scaler_obj.kernel)

        if 'scaler' in init_keys:
            kwargs.update(scaler=self.scaler or scaler_obj.scaler)

        if 'shifter' in init_keys:
            kwargs.update(shifter=self.shifter or scaler_obj.shifter)

        if kwargs:
            scaler_obj = replace(scaler_obj, **kwargs)

    return scaler_obj

from_param classmethod

from_param(
    scaler: str | type[BaseScalerT] | BaseScalerT | None = None,
    /,
    func_except: FuncExceptT | None = None,
) -> type[BaseScalerT]
Source code
177
178
179
180
181
182
183
184
@classmethod
def from_param(
    cls: type[BaseScalerT], scaler: str | type[BaseScalerT] | BaseScalerT | None = None, /,
    func_except: FuncExceptT | None = None
) -> type[BaseScalerT]:
    return _base_from_param(
        cls, (mro := cls.mro())[mro.index(BaseScaler) - 1], scaler, cls._err_class, [], func_except
    )

get_clean_kwargs

get_clean_kwargs(*funcs: Callable[..., Any] | None) -> KwargsT
Source code
199
200
def get_clean_kwargs(self, *funcs: Callable[..., Any] | None) -> KwargsT:
    return _clean_self_kwargs(funcs, self)

get_implemented_funcs

get_implemented_funcs() -> tuple[Callable[..., Any], ...]
Source code
270
271
def get_implemented_funcs(self) -> tuple[Callable[..., Any], ...]:
    return (self.scale, self.multi)

get_scale_args

get_scale_args(
    clip: VideoNode,
    shift: tuple[TopShift, LeftShift] = (0, 0),
    width: int | None = None,
    height: int | None = None,
    *funcs: Callable[..., Any],
    **kwargs: Any
) -> KwargsT
Source code
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
@inject_kwargs_params
def get_scale_args(
    self, clip: vs.VideoNode, shift: tuple[TopShift, LeftShift] = (0, 0),
    width: int | None = None, height: int | None = None,
    *funcs: Callable[..., Any], **kwargs: Any
) -> KwargsT:
    return (
        dict(
            src_top=shift[0],
            src_left=shift[1]
        )
        | self.get_clean_kwargs(*funcs)
        | dict(width=width, height=height)
        | kwargs
    )

multi

multi(
    clip: VideoNode,
    multi: float = 2,
    shift: tuple[TopShift, LeftShift] = (0, 0),
    **kwargs: Any
) -> VideoNode
Source code
239
240
241
242
243
244
245
246
247
248
249
250
251
252
@inject_self.cached
def multi(
    self, clip: vs.VideoNode, multi: float = 2, shift: tuple[TopShift, LeftShift] = (0, 0), **kwargs: Any
) -> vs.VideoNode:
    assert check_variable_resolution(clip, self.multi)

    dst_width, dst_height = ceil(clip.width * multi), ceil(clip.height * multi)

    if max(dst_width, dst_height) <= 0.0:
        raise CustomValueError(
            'Multiplying the resolution by "multi" must result in a positive resolution!', self.multi, multi
        )

    return self.scale(clip, dst_width, dst_height, shift, **kwargs)

pretty_string

pretty_string() -> str
Source code
202
203
204
205
206
207
208
209
210
211
212
213
214
@inject_self.cached.property
def pretty_string(self) -> str:
    attrs = {}

    if hasattr(self, 'b'):
        attrs.update(b=self.b, c=self.c)
    elif hasattr(self, 'taps'):
        attrs['taps'] = self.taps

    if hasattr(self, 'kwargs'):
        attrs.update(self.kwargs)

    return f"{self.__class__.__name__}{' (' + ', '.join(f'{k}={v}' for k, v in attrs.items()) + ')' if attrs else ''}"

scale

scale(
    clip: VideoNode,
    width: int | None = None,
    height: int | None = None,
    shift: tuple[float, float] = (0, 0),
    *,
    smooth: VideoNode | None = None,
    **kwargs: Any
) -> VideoNode
Source code
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
@inject_self
def scale(  # type: ignore
    self, clip: vs.VideoNode, width: int | None = None, height: int | None = None,
    shift: tuple[float, float] = (0, 0), *, smooth: vs.VideoNode | None = None, **kwargs: Any
) -> vs.VideoNode:
    width, height = self._wh_norm(clip, width, height)

    assert (self.undershoot or self.undershoot == 0) and (self.overshoot or self.overshoot == 0)

    ref = self._ref_scaler.scale(clip, width, height, shift, **kwargs)

    if isinstance(self.reference, vs.VideoNode):
        smooth = self.reference

        if shift != (0, 0):
            smooth = self._kernel.shift(smooth, shift)  # type: ignore
    else:
        assert self._reference
        smooth = self._reference.scale(clip, width, height, shift)

    assert smooth

    check_ref_clip(ref, smooth)

    merge_weight = self.strength / 100

    if self.limit is True:
        expression = 'x {merge_weight} * y {ref_weight} * + a {undershoot} - z {overshoot} + clip'

        merged = norm_expr(
            [ref, smooth, smooth.std.Maximum(), smooth.std.Minimum()],
            expression, merge_weight=merge_weight, ref_weight=1.0 - merge_weight,
            undershoot=scale_delta(self.undershoot, 32, clip),
            overshoot=scale_delta(self.overshoot, 32, clip)
        )
    else:
        merged = smooth.std.Merge(ref, merge_weight)

        if isinstance(self.limit, RepairMode):
            merged = repair(merged, smooth, self.limit)

    if self.operator is not None:
        merge2 = combine([smooth, ref], self.operator)

        if self.masked:
            merged = merged.std.MaskedMerge(merge2, ringing_mask(smooth))
        else:
            merged = merge2
    elif self.masked:
        merged.std.MaskedMerge(smooth, ringing_mask(smooth))

    return merged

MergeScalers

MergeScalers(*scalers: ScalerT | tuple[ScalerT, float | None])

Bases: GenericScaler

Create a unified Scaler from multiple Scalers with optional weights.

Source code
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
def __init__(self, *scalers: ScalerT | tuple[ScalerT, float | None]) -> None:
    """Create a unified Scaler from multiple Scalers with optional weights."""
    if (slen := len(scalers)) < 2:
        raise CustomIndexError('Not enough scalers passed!', self.__class__, slen)
    elif slen > len(EXPR_VARS):
        raise CustomIndexError('Too many scalers passed!', self.__class__, slen)

    def _not_all_tuple_scalers(
        scalers: tuple[ScalerT | tuple[ScalerT, float | None], ...]
    ) -> TypeGuard[tuple[ScalerT, ...]]:
        return all(not isinstance(s, tuple) for s in scalers)

    if not _not_all_tuple_scalers(scalers):
        norm_scalers = [
            scaler if isinstance(scaler, tuple) else (scaler, None) for scaler in scalers
        ]

        curr_sum = 0.0
        n_auto_weight = 0

        for i, (_, weight) in enumerate(norm_scalers):
            if weight is None:
                n_auto_weight += 1
            elif weight <= 0.0:
                raise CustomOverflowError(
                    f'Weights have to be positive, >= 0.0! (Scaler index: ({i})', self.__class__
                )
            else:
                curr_sum += weight

        if curr_sum > 1.0:
            raise CustomOverflowError(
                'Sum of the weights should be less or equal than 1.0!', self.__class__
            )

        if n_auto_weight:
            a_wgh = (1.0 - curr_sum) / n_auto_weight

            norm_scalers = [
                (scaler, a_wgh if weight is None else weight)
                for scaler, weight in norm_scalers
            ]
    else:
        weight = 1.0 / len(scalers)

        norm_scalers = [(scaler, weight) for scaler in scalers]

    self.scalers = [
        (self.ensure_scaler(scaler), float(weight if weight else 0))
        for scaler, weight in norm_scalers
    ]

func instance-attribute

func = func

kernel class-attribute instance-attribute

kernel: KernelT | None = field(default=None, kw_only=True)

Base kernel to be used for certain scaling/shifting/resampling operations. Must be specified and defaults to catrom

kernel_radius property

kernel_radius: int

kwargs instance-attribute

kwargs = kwargs

scale_function instance-attribute

scale_function: GenericVSFunction

Scale function called internally when scaling

scaler class-attribute instance-attribute

scaler: ScalerT | None = field(default=None, kw_only=True)

Scaler used for scaling operations. Defaults to kernel.

scalers instance-attribute

scalers = [
    (ensure_scaler(scaler), float(weight if weight else 0))
    for (scaler, weight) in norm_scalers
]

shifter class-attribute instance-attribute

shifter: KernelT | None = field(default=None, kw_only=True)

Kernel used for shifting operations. Defaults to kernel.

ensure_obj classmethod

ensure_obj(
    scaler: str | type[BaseScalerT] | BaseScalerT | None = None,
    /,
    func_except: FuncExceptT | None = None,
) -> BaseScalerT
Source code
186
187
188
189
190
191
192
193
@classmethod
def ensure_obj(
    cls: type[BaseScalerT], scaler: str | type[BaseScalerT] | BaseScalerT | None = None, /,
    func_except: FuncExceptT | None = None
) -> BaseScalerT:
    return _base_ensure_obj(
        cls, (mro := cls.mro())[mro.index(BaseScaler) - 1], scaler, cls._err_class, [], func_except
    )

ensure_scaler

ensure_scaler(scaler: ScalerT) -> Scaler
Source code
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
def ensure_scaler(self, scaler: ScalerT) -> Scaler:
    from dataclasses import is_dataclass, replace

    scaler_obj = Scaler.ensure_obj(scaler, self.__class__)

    if is_dataclass(scaler_obj):
        from inspect import Signature  #type: ignore[unreachable]

        kwargs = dict[str, ScalerT]()

        init_keys = Signature.from_callable(scaler_obj.__init__).parameters.keys()

        if 'kernel' in init_keys:
            kwargs.update(kernel=self.kernel or scaler_obj.kernel)

        if 'scaler' in init_keys:
            kwargs.update(scaler=self.scaler or scaler_obj.scaler)

        if 'shifter' in init_keys:
            kwargs.update(shifter=self.shifter or scaler_obj.shifter)

        if kwargs:
            scaler_obj = replace(scaler_obj, **kwargs)

    return scaler_obj

from_param classmethod

from_param(
    scaler: str | type[BaseScalerT] | BaseScalerT | None = None,
    /,
    func_except: FuncExceptT | None = None,
) -> type[BaseScalerT]
Source code
177
178
179
180
181
182
183
184
@classmethod
def from_param(
    cls: type[BaseScalerT], scaler: str | type[BaseScalerT] | BaseScalerT | None = None, /,
    func_except: FuncExceptT | None = None
) -> type[BaseScalerT]:
    return _base_from_param(
        cls, (mro := cls.mro())[mro.index(BaseScaler) - 1], scaler, cls._err_class, [], func_except
    )

get_clean_kwargs

get_clean_kwargs(*funcs: Callable[..., Any] | None) -> KwargsT
Source code
199
200
def get_clean_kwargs(self, *funcs: Callable[..., Any] | None) -> KwargsT:
    return _clean_self_kwargs(funcs, self)

get_implemented_funcs

get_implemented_funcs() -> tuple[Callable[..., Any], ...]
Source code
270
271
def get_implemented_funcs(self) -> tuple[Callable[..., Any], ...]:
    return (self.scale, self.multi)

get_scale_args

get_scale_args(
    clip: VideoNode,
    shift: tuple[TopShift, LeftShift] = (0, 0),
    width: int | None = None,
    height: int | None = None,
    *funcs: Callable[..., Any],
    **kwargs: Any
) -> KwargsT
Source code
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
@inject_kwargs_params
def get_scale_args(
    self, clip: vs.VideoNode, shift: tuple[TopShift, LeftShift] = (0, 0),
    width: int | None = None, height: int | None = None,
    *funcs: Callable[..., Any], **kwargs: Any
) -> KwargsT:
    return (
        dict(
            src_top=shift[0],
            src_left=shift[1]
        )
        | self.get_clean_kwargs(*funcs)
        | dict(width=width, height=height)
        | kwargs
    )

multi

multi(
    clip: VideoNode,
    multi: float = 2,
    shift: tuple[TopShift, LeftShift] = (0, 0),
    **kwargs: Any
) -> VideoNode
Source code
239
240
241
242
243
244
245
246
247
248
249
250
251
252
@inject_self.cached
def multi(
    self, clip: vs.VideoNode, multi: float = 2, shift: tuple[TopShift, LeftShift] = (0, 0), **kwargs: Any
) -> vs.VideoNode:
    assert check_variable_resolution(clip, self.multi)

    dst_width, dst_height = ceil(clip.width * multi), ceil(clip.height * multi)

    if max(dst_width, dst_height) <= 0.0:
        raise CustomValueError(
            'Multiplying the resolution by "multi" must result in a positive resolution!', self.multi, multi
        )

    return self.scale(clip, dst_width, dst_height, shift, **kwargs)

pretty_string

pretty_string() -> str
Source code
202
203
204
205
206
207
208
209
210
211
212
213
214
@inject_self.cached.property
def pretty_string(self) -> str:
    attrs = {}

    if hasattr(self, 'b'):
        attrs.update(b=self.b, c=self.c)
    elif hasattr(self, 'taps'):
        attrs['taps'] = self.taps

    if hasattr(self, 'kwargs'):
        attrs.update(self.kwargs)

    return f"{self.__class__.__name__}{' (' + ', '.join(f'{k}={v}' for k, v in attrs.items()) + ')' if attrs else ''}"

scale

scale(
    clip: VideoNode,
    width: int | None = None,
    height: int | None = None,
    shift: tuple[float, float] = (0, 0),
    **kwargs: Any
) -> VideoNode
Source code
79
80
81
82
83
84
85
86
87
88
89
90
def scale(  # type: ignore
    self, clip: vs.VideoNode, width: int | None = None, height: int | None = None,
    shift: tuple[float, float] = (0, 0), **kwargs: Any
) -> vs.VideoNode:
    width, height = self._wh_norm(clip, width, height)

    scalers, weights = cast(tuple[list[Scaler], list[float]], zip(*self.scalers))

    return combine(
        [scaler.scale(clip, width, height, shift, **kwargs) for scaler in scalers],
        ExprOp.ADD, zip(weights, ExprOp.MUL), expr_suffix=[sum(weights), ExprOp.DIV]
    )

MergedFSRCNNX dataclass

MergedFSRCNNX(
    strength: int = 80,
    overshoot: float | None = None,
    undershoot: float | None = None,
    limit: RepairMode | bool = True,
    operator: Literal[MAX, MIN] | None = MIN,
    masked: bool = True,
    reference: ScalerT | VideoNode = Nnedi3,
    *,
    kernel: KernelT | None = None,
    scaler: ScalerT | None = None,
    shifter: KernelT | None = None,
    ref_scaler: FSRCNNXShaderT = lambda: x56()
)

Bases: ClampScaler

Clamped FSRCNNX Scaler.

func instance-attribute

func = func

kernel class-attribute instance-attribute

kernel: KernelT | None = field(default=None, kw_only=True)

Base kernel to be used for certain scaling/shifting/resampling operations. Must be specified and defaults to catrom

kernel_radius property

kernel_radius: int

kwargs instance-attribute

kwargs = kwargs

limit class-attribute instance-attribute

limit: RepairMode | bool = True

Whether to use under/overshoot limit (True) or a reference repaired clip for limiting.

masked class-attribute instance-attribute

masked: bool = True

Whether to mask with a ringing mask or not.

operator class-attribute instance-attribute

operator: Literal[MAX, MIN] | None = MIN

Whether to take the brightest or darkest pixels in the merge.

overshoot class-attribute instance-attribute

overshoot: float | None = None

Overshoot threshold.

ref_scaler class-attribute instance-attribute

ref_scaler: FSRCNNXShaderT = field(default_factory=lambda: x56, kw_only=True)

reference class-attribute instance-attribute

reference: ScalerT | VideoNode = Nnedi3

Reference Scaler used to clamp ref_scaler

scale_function instance-attribute

scale_function: GenericVSFunction

Scale function called internally when scaling

scaler class-attribute instance-attribute

scaler: ScalerT | None = field(default=None, kw_only=True)

Scaler used for scaling operations. Defaults to kernel.

shifter class-attribute instance-attribute

shifter: KernelT | None = field(default=None, kw_only=True)

Kernel used for shifting operations. Defaults to kernel.

strength class-attribute instance-attribute

strength: int = 80

Strength of clamping.

undershoot class-attribute instance-attribute

undershoot: float | None = None

Undershoot threshold.

ensure_obj classmethod

ensure_obj(
    scaler: str | type[BaseScalerT] | BaseScalerT | None = None,
    /,
    func_except: FuncExceptT | None = None,
) -> BaseScalerT
Source code
186
187
188
189
190
191
192
193
@classmethod
def ensure_obj(
    cls: type[BaseScalerT], scaler: str | type[BaseScalerT] | BaseScalerT | None = None, /,
    func_except: FuncExceptT | None = None
) -> BaseScalerT:
    return _base_ensure_obj(
        cls, (mro := cls.mro())[mro.index(BaseScaler) - 1], scaler, cls._err_class, [], func_except
    )

ensure_scaler

ensure_scaler(scaler: ScalerT) -> Scaler
Source code
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
def ensure_scaler(self, scaler: ScalerT) -> Scaler:
    from dataclasses import is_dataclass, replace

    scaler_obj = Scaler.ensure_obj(scaler, self.__class__)

    if is_dataclass(scaler_obj):
        from inspect import Signature  #type: ignore[unreachable]

        kwargs = dict[str, ScalerT]()

        init_keys = Signature.from_callable(scaler_obj.__init__).parameters.keys()

        if 'kernel' in init_keys:
            kwargs.update(kernel=self.kernel or scaler_obj.kernel)

        if 'scaler' in init_keys:
            kwargs.update(scaler=self.scaler or scaler_obj.scaler)

        if 'shifter' in init_keys:
            kwargs.update(shifter=self.shifter or scaler_obj.shifter)

        if kwargs:
            scaler_obj = replace(scaler_obj, **kwargs)

    return scaler_obj

from_param classmethod

from_param(
    scaler: str | type[BaseScalerT] | BaseScalerT | None = None,
    /,
    func_except: FuncExceptT | None = None,
) -> type[BaseScalerT]
Source code
177
178
179
180
181
182
183
184
@classmethod
def from_param(
    cls: type[BaseScalerT], scaler: str | type[BaseScalerT] | BaseScalerT | None = None, /,
    func_except: FuncExceptT | None = None
) -> type[BaseScalerT]:
    return _base_from_param(
        cls, (mro := cls.mro())[mro.index(BaseScaler) - 1], scaler, cls._err_class, [], func_except
    )

get_clean_kwargs

get_clean_kwargs(*funcs: Callable[..., Any] | None) -> KwargsT
Source code
199
200
def get_clean_kwargs(self, *funcs: Callable[..., Any] | None) -> KwargsT:
    return _clean_self_kwargs(funcs, self)

get_implemented_funcs

get_implemented_funcs() -> tuple[Callable[..., Any], ...]
Source code
270
271
def get_implemented_funcs(self) -> tuple[Callable[..., Any], ...]:
    return (self.scale, self.multi)

get_scale_args

get_scale_args(
    clip: VideoNode,
    shift: tuple[TopShift, LeftShift] = (0, 0),
    width: int | None = None,
    height: int | None = None,
    *funcs: Callable[..., Any],
    **kwargs: Any
) -> KwargsT
Source code
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
@inject_kwargs_params
def get_scale_args(
    self, clip: vs.VideoNode, shift: tuple[TopShift, LeftShift] = (0, 0),
    width: int | None = None, height: int | None = None,
    *funcs: Callable[..., Any], **kwargs: Any
) -> KwargsT:
    return (
        dict(
            src_top=shift[0],
            src_left=shift[1]
        )
        | self.get_clean_kwargs(*funcs)
        | dict(width=width, height=height)
        | kwargs
    )

multi

multi(
    clip: VideoNode,
    multi: float = 2,
    shift: tuple[TopShift, LeftShift] = (0, 0),
    **kwargs: Any
) -> VideoNode
Source code
239
240
241
242
243
244
245
246
247
248
249
250
251
252
@inject_self.cached
def multi(
    self, clip: vs.VideoNode, multi: float = 2, shift: tuple[TopShift, LeftShift] = (0, 0), **kwargs: Any
) -> vs.VideoNode:
    assert check_variable_resolution(clip, self.multi)

    dst_width, dst_height = ceil(clip.width * multi), ceil(clip.height * multi)

    if max(dst_width, dst_height) <= 0.0:
        raise CustomValueError(
            'Multiplying the resolution by "multi" must result in a positive resolution!', self.multi, multi
        )

    return self.scale(clip, dst_width, dst_height, shift, **kwargs)

pretty_string

pretty_string() -> str
Source code
202
203
204
205
206
207
208
209
210
211
212
213
214
@inject_self.cached.property
def pretty_string(self) -> str:
    attrs = {}

    if hasattr(self, 'b'):
        attrs.update(b=self.b, c=self.c)
    elif hasattr(self, 'taps'):
        attrs['taps'] = self.taps

    if hasattr(self, 'kwargs'):
        attrs.update(self.kwargs)

    return f"{self.__class__.__name__}{' (' + ', '.join(f'{k}={v}' for k, v in attrs.items()) + ')' if attrs else ''}"

scale

scale(
    clip: VideoNode,
    width: int | None = None,
    height: int | None = None,
    shift: tuple[float, float] = (0, 0),
    *,
    smooth: VideoNode | None = None,
    **kwargs: Any
) -> VideoNode
Source code
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
@inject_self
def scale(  # type: ignore
    self, clip: vs.VideoNode, width: int | None = None, height: int | None = None,
    shift: tuple[float, float] = (0, 0), *, smooth: vs.VideoNode | None = None, **kwargs: Any
) -> vs.VideoNode:
    width, height = self._wh_norm(clip, width, height)

    assert (self.undershoot or self.undershoot == 0) and (self.overshoot or self.overshoot == 0)

    ref = self._ref_scaler.scale(clip, width, height, shift, **kwargs)

    if isinstance(self.reference, vs.VideoNode):
        smooth = self.reference

        if shift != (0, 0):
            smooth = self._kernel.shift(smooth, shift)  # type: ignore
    else:
        assert self._reference
        smooth = self._reference.scale(clip, width, height, shift)

    assert smooth

    check_ref_clip(ref, smooth)

    merge_weight = self.strength / 100

    if self.limit is True:
        expression = 'x {merge_weight} * y {ref_weight} * + a {undershoot} - z {overshoot} + clip'

        merged = norm_expr(
            [ref, smooth, smooth.std.Maximum(), smooth.std.Minimum()],
            expression, merge_weight=merge_weight, ref_weight=1.0 - merge_weight,
            undershoot=scale_delta(self.undershoot, 32, clip),
            overshoot=scale_delta(self.overshoot, 32, clip)
        )
    else:
        merged = smooth.std.Merge(ref, merge_weight)

        if isinstance(self.limit, RepairMode):
            merged = repair(merged, smooth, self.limit)

    if self.operator is not None:
        merge2 = combine([smooth, ref], self.operator)

        if self.masked:
            merged = merged.std.MaskedMerge(merge2, ringing_mask(smooth))
        else:
            merged = merge2
    elif self.masked:
        merged.std.MaskedMerge(smooth, ringing_mask(smooth))

    return merged

UnsharpLimitScaler

UnsharpLimitScaler(
    ref_scaler: ScalerT,
    unsharp_func: Callable[Concatenate[VideoNode, P], VideoNode] = partial(
        unsharp_masked, radius=2, strength=65
    ),
    merge_mode: LimitFilterMode | bool = True,
    reference: ScalerT | VideoNode = Nnedi3(0, opencl=None),
    *args: args,
    **kwargs: kwargs
)

Bases: GenericScaler

Limit a scaler with a masked unsharping.

Parameters:

  • ref_scaler

    (ScalerT) –

    Scaler of which to limit haloing.

  • unsharp_func

    (Callable[Concatenate[VideoNode, P], VideoNode], default: partial(unsharp_masked, radius=2, strength=65) ) –

    Unsharpening function used as reference for limiting.

  • merge_mode

    (LimitFilterMode | bool, default: True ) –

    Whether to limit with LimitFilterMode, use a median filter (True) or just take the darkest pixels (False).

  • reference

    (ScalerT | VideoNode, default: Nnedi3(0, opencl=None) ) –

    Reference scaler used to fill in the haloed parts.

Source code
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
def __init__(
    self, ref_scaler: ScalerT,
    unsharp_func: Callable[
        Concatenate[vs.VideoNode, P], vs.VideoNode
    ] = partial(unsharp_masked, radius=2, strength=65),
    merge_mode: LimitFilterMode | bool = True,
    reference: ScalerT | vs.VideoNode = Nnedi3(0, opencl=None),
    *args: P.args, **kwargs: P.kwargs
) -> None:
    """
    :param ref_scaler:      Scaler of which to limit haloing.
    :param unsharp_func:    Unsharpening function used as reference for limiting.
    :param merge_mode:      Whether to limit with LimitFilterMode,
                            use a median filter (True) or just take the darkest pixels (False).
    :param reference:       Reference scaler used to fill in the haloed parts.
    """

    self.unsharp_func = unsharp_func

    self.merge_mode = merge_mode

    self.reference = reference
    self._reference = None if isinstance(self.reference, vs.VideoNode) else self.ensure_scaler(self.reference)
    self.ref_scaler = self.ensure_scaler(ref_scaler)

    self.args = args
    self.kwargs = kwargs

args instance-attribute

args = args

func instance-attribute

func = func

kernel class-attribute instance-attribute

kernel: KernelT | None = field(default=None, kw_only=True)

Base kernel to be used for certain scaling/shifting/resampling operations. Must be specified and defaults to catrom

kernel_radius property

kernel_radius: int

kwargs instance-attribute

kwargs = kwargs

merge_mode instance-attribute

merge_mode = merge_mode

ref_scaler instance-attribute

ref_scaler = ensure_scaler(ref_scaler)

reference instance-attribute

reference = reference

scale_function instance-attribute

scale_function: GenericVSFunction

Scale function called internally when scaling

scaler class-attribute instance-attribute

scaler: ScalerT | None = field(default=None, kw_only=True)

Scaler used for scaling operations. Defaults to kernel.

shifter class-attribute instance-attribute

shifter: KernelT | None = field(default=None, kw_only=True)

Kernel used for shifting operations. Defaults to kernel.

unsharp_func instance-attribute

unsharp_func = unsharp_func

ensure_obj classmethod

ensure_obj(
    scaler: str | type[BaseScalerT] | BaseScalerT | None = None,
    /,
    func_except: FuncExceptT | None = None,
) -> BaseScalerT
Source code
186
187
188
189
190
191
192
193
@classmethod
def ensure_obj(
    cls: type[BaseScalerT], scaler: str | type[BaseScalerT] | BaseScalerT | None = None, /,
    func_except: FuncExceptT | None = None
) -> BaseScalerT:
    return _base_ensure_obj(
        cls, (mro := cls.mro())[mro.index(BaseScaler) - 1], scaler, cls._err_class, [], func_except
    )

ensure_scaler

ensure_scaler(scaler: ScalerT) -> Scaler
Source code
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
def ensure_scaler(self, scaler: ScalerT) -> Scaler:
    from dataclasses import is_dataclass, replace

    scaler_obj = Scaler.ensure_obj(scaler, self.__class__)

    if is_dataclass(scaler_obj):
        from inspect import Signature  #type: ignore[unreachable]

        kwargs = dict[str, ScalerT]()

        init_keys = Signature.from_callable(scaler_obj.__init__).parameters.keys()

        if 'kernel' in init_keys:
            kwargs.update(kernel=self.kernel or scaler_obj.kernel)

        if 'scaler' in init_keys:
            kwargs.update(scaler=self.scaler or scaler_obj.scaler)

        if 'shifter' in init_keys:
            kwargs.update(shifter=self.shifter or scaler_obj.shifter)

        if kwargs:
            scaler_obj = replace(scaler_obj, **kwargs)

    return scaler_obj

from_param classmethod

from_param(
    scaler: str | type[BaseScalerT] | BaseScalerT | None = None,
    /,
    func_except: FuncExceptT | None = None,
) -> type[BaseScalerT]
Source code
177
178
179
180
181
182
183
184
@classmethod
def from_param(
    cls: type[BaseScalerT], scaler: str | type[BaseScalerT] | BaseScalerT | None = None, /,
    func_except: FuncExceptT | None = None
) -> type[BaseScalerT]:
    return _base_from_param(
        cls, (mro := cls.mro())[mro.index(BaseScaler) - 1], scaler, cls._err_class, [], func_except
    )

get_clean_kwargs

get_clean_kwargs(*funcs: Callable[..., Any] | None) -> KwargsT
Source code
199
200
def get_clean_kwargs(self, *funcs: Callable[..., Any] | None) -> KwargsT:
    return _clean_self_kwargs(funcs, self)

get_implemented_funcs

get_implemented_funcs() -> tuple[Callable[..., Any], ...]
Source code
270
271
def get_implemented_funcs(self) -> tuple[Callable[..., Any], ...]:
    return (self.scale, self.multi)

get_scale_args

get_scale_args(
    clip: VideoNode,
    shift: tuple[TopShift, LeftShift] = (0, 0),
    width: int | None = None,
    height: int | None = None,
    *funcs: Callable[..., Any],
    **kwargs: Any
) -> KwargsT
Source code
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
@inject_kwargs_params
def get_scale_args(
    self, clip: vs.VideoNode, shift: tuple[TopShift, LeftShift] = (0, 0),
    width: int | None = None, height: int | None = None,
    *funcs: Callable[..., Any], **kwargs: Any
) -> KwargsT:
    return (
        dict(
            src_top=shift[0],
            src_left=shift[1]
        )
        | self.get_clean_kwargs(*funcs)
        | dict(width=width, height=height)
        | kwargs
    )

multi

multi(
    clip: VideoNode,
    multi: float = 2,
    shift: tuple[TopShift, LeftShift] = (0, 0),
    **kwargs: Any
) -> VideoNode
Source code
239
240
241
242
243
244
245
246
247
248
249
250
251
252
@inject_self.cached
def multi(
    self, clip: vs.VideoNode, multi: float = 2, shift: tuple[TopShift, LeftShift] = (0, 0), **kwargs: Any
) -> vs.VideoNode:
    assert check_variable_resolution(clip, self.multi)

    dst_width, dst_height = ceil(clip.width * multi), ceil(clip.height * multi)

    if max(dst_width, dst_height) <= 0.0:
        raise CustomValueError(
            'Multiplying the resolution by "multi" must result in a positive resolution!', self.multi, multi
        )

    return self.scale(clip, dst_width, dst_height, shift, **kwargs)

pretty_string

pretty_string() -> str
Source code
202
203
204
205
206
207
208
209
210
211
212
213
214
@inject_self.cached.property
def pretty_string(self) -> str:
    attrs = {}

    if hasattr(self, 'b'):
        attrs.update(b=self.b, c=self.c)
    elif hasattr(self, 'taps'):
        attrs['taps'] = self.taps

    if hasattr(self, 'kwargs'):
        attrs.update(self.kwargs)

    return f"{self.__class__.__name__}{' (' + ', '.join(f'{k}={v}' for k, v in attrs.items()) + ')' if attrs else ''}"

scale

scale(
    clip: VideoNode,
    width: int | None = None,
    height: int | None = None,
    shift: tuple[float, float] = (0, 0),
    *,
    smooth: VideoNode | None = None,
    **kwargs: Any
) -> VideoNode
Source code
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
@inject_self
def scale(  # type: ignore
    self, clip: vs.VideoNode, width: int | None = None, height: int | None = None,
    shift: tuple[float, float] = (0, 0), *, smooth: vs.VideoNode | None = None, **kwargs: Any
) -> vs.VideoNode:
    width, height = self._wh_norm(clip, width, height)

    fsrcnnx = self.ref_scaler.scale(clip, width, height, shift, **kwargs)

    if isinstance(self.reference, vs.VideoNode):
        smooth = self.reference

        if shift != (0, 0):
            smooth = self._kernel.shift(smooth, shift)  # type: ignore
    else:
        smooth = self._reference.scale(clip, width, height, shift)  # type: ignore

    assert smooth

    check_ref_clip(fsrcnnx, smooth)

    smooth_sharp = self.unsharp_func(smooth, *self.args, **self.kwargs)

    if isinstance(self.merge_mode, LimitFilterMode):
        return limit_filter(smooth, fsrcnnx, smooth_sharp, self.merge_mode)

    if self.merge_mode:
        return MeanMode.MEDIAN(smooth, fsrcnnx, smooth_sharp)

    return combine([smooth, fsrcnnx, smooth_sharp], ExprOp.MIN)

UnsharpedFSRCNNX

UnsharpedFSRCNNX(
    unsharp_func: Callable[Concatenate[VideoNode, P], VideoNode] = partial(
        unsharp_masked, radius=2, strength=65
    ),
    merge_mode: LimitFilterMode | bool = True,
    reference: ScalerT | VideoNode = Nnedi3(0, opencl=None),
    ref_scaler: ScalerT = x56,
    *args: args,
    **kwargs: kwargs
)

Bases: UnsharpLimitScaler

Clamped FSRCNNX Scaler with an unsharp mask.

Source code
280
281
282
283
284
285
286
287
288
289
290
def __init__(
    self,
    unsharp_func: Callable[
        Concatenate[vs.VideoNode, P], vs.VideoNode
    ] = partial(unsharp_masked, radius=2, strength=65),
    merge_mode: LimitFilterMode | bool = True,
    reference: ScalerT | vs.VideoNode = Nnedi3(0, opencl=None),
    ref_scaler: ScalerT = FSRCNNXShader.x56,
    *args: P.args, **kwargs: P.kwargs
) -> None:
    super().__init__(ref_scaler, unsharp_func, merge_mode, reference, *args, **kwargs)

args instance-attribute

args = args

func instance-attribute

func = func

kernel class-attribute instance-attribute

kernel: KernelT | None = field(default=None, kw_only=True)

Base kernel to be used for certain scaling/shifting/resampling operations. Must be specified and defaults to catrom

kernel_radius property

kernel_radius: int

kwargs instance-attribute

kwargs = kwargs

merge_mode instance-attribute

merge_mode = merge_mode

ref_scaler instance-attribute

ref_scaler = ensure_scaler(ref_scaler)

reference instance-attribute

reference = reference

scale_function instance-attribute

scale_function: GenericVSFunction

Scale function called internally when scaling

scaler class-attribute instance-attribute

scaler: ScalerT | None = field(default=None, kw_only=True)

Scaler used for scaling operations. Defaults to kernel.

shifter class-attribute instance-attribute

shifter: KernelT | None = field(default=None, kw_only=True)

Kernel used for shifting operations. Defaults to kernel.

unsharp_func instance-attribute

unsharp_func = unsharp_func

ensure_obj classmethod

ensure_obj(
    scaler: str | type[BaseScalerT] | BaseScalerT | None = None,
    /,
    func_except: FuncExceptT | None = None,
) -> BaseScalerT
Source code
186
187
188
189
190
191
192
193
@classmethod
def ensure_obj(
    cls: type[BaseScalerT], scaler: str | type[BaseScalerT] | BaseScalerT | None = None, /,
    func_except: FuncExceptT | None = None
) -> BaseScalerT:
    return _base_ensure_obj(
        cls, (mro := cls.mro())[mro.index(BaseScaler) - 1], scaler, cls._err_class, [], func_except
    )

ensure_scaler

ensure_scaler(scaler: ScalerT) -> Scaler
Source code
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
def ensure_scaler(self, scaler: ScalerT) -> Scaler:
    from dataclasses import is_dataclass, replace

    scaler_obj = Scaler.ensure_obj(scaler, self.__class__)

    if is_dataclass(scaler_obj):
        from inspect import Signature  #type: ignore[unreachable]

        kwargs = dict[str, ScalerT]()

        init_keys = Signature.from_callable(scaler_obj.__init__).parameters.keys()

        if 'kernel' in init_keys:
            kwargs.update(kernel=self.kernel or scaler_obj.kernel)

        if 'scaler' in init_keys:
            kwargs.update(scaler=self.scaler or scaler_obj.scaler)

        if 'shifter' in init_keys:
            kwargs.update(shifter=self.shifter or scaler_obj.shifter)

        if kwargs:
            scaler_obj = replace(scaler_obj, **kwargs)

    return scaler_obj

from_param classmethod

from_param(
    scaler: str | type[BaseScalerT] | BaseScalerT | None = None,
    /,
    func_except: FuncExceptT | None = None,
) -> type[BaseScalerT]
Source code
177
178
179
180
181
182
183
184
@classmethod
def from_param(
    cls: type[BaseScalerT], scaler: str | type[BaseScalerT] | BaseScalerT | None = None, /,
    func_except: FuncExceptT | None = None
) -> type[BaseScalerT]:
    return _base_from_param(
        cls, (mro := cls.mro())[mro.index(BaseScaler) - 1], scaler, cls._err_class, [], func_except
    )

get_clean_kwargs

get_clean_kwargs(*funcs: Callable[..., Any] | None) -> KwargsT
Source code
199
200
def get_clean_kwargs(self, *funcs: Callable[..., Any] | None) -> KwargsT:
    return _clean_self_kwargs(funcs, self)

get_implemented_funcs

get_implemented_funcs() -> tuple[Callable[..., Any], ...]
Source code
270
271
def get_implemented_funcs(self) -> tuple[Callable[..., Any], ...]:
    return (self.scale, self.multi)

get_scale_args

get_scale_args(
    clip: VideoNode,
    shift: tuple[TopShift, LeftShift] = (0, 0),
    width: int | None = None,
    height: int | None = None,
    *funcs: Callable[..., Any],
    **kwargs: Any
) -> KwargsT
Source code
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
@inject_kwargs_params
def get_scale_args(
    self, clip: vs.VideoNode, shift: tuple[TopShift, LeftShift] = (0, 0),
    width: int | None = None, height: int | None = None,
    *funcs: Callable[..., Any], **kwargs: Any
) -> KwargsT:
    return (
        dict(
            src_top=shift[0],
            src_left=shift[1]
        )
        | self.get_clean_kwargs(*funcs)
        | dict(width=width, height=height)
        | kwargs
    )

multi

multi(
    clip: VideoNode,
    multi: float = 2,
    shift: tuple[TopShift, LeftShift] = (0, 0),
    **kwargs: Any
) -> VideoNode
Source code
239
240
241
242
243
244
245
246
247
248
249
250
251
252
@inject_self.cached
def multi(
    self, clip: vs.VideoNode, multi: float = 2, shift: tuple[TopShift, LeftShift] = (0, 0), **kwargs: Any
) -> vs.VideoNode:
    assert check_variable_resolution(clip, self.multi)

    dst_width, dst_height = ceil(clip.width * multi), ceil(clip.height * multi)

    if max(dst_width, dst_height) <= 0.0:
        raise CustomValueError(
            'Multiplying the resolution by "multi" must result in a positive resolution!', self.multi, multi
        )

    return self.scale(clip, dst_width, dst_height, shift, **kwargs)

pretty_string

pretty_string() -> str
Source code
202
203
204
205
206
207
208
209
210
211
212
213
214
@inject_self.cached.property
def pretty_string(self) -> str:
    attrs = {}

    if hasattr(self, 'b'):
        attrs.update(b=self.b, c=self.c)
    elif hasattr(self, 'taps'):
        attrs['taps'] = self.taps

    if hasattr(self, 'kwargs'):
        attrs.update(self.kwargs)

    return f"{self.__class__.__name__}{' (' + ', '.join(f'{k}={v}' for k, v in attrs.items()) + ')' if attrs else ''}"

scale

scale(
    clip: VideoNode,
    width: int | None = None,
    height: int | None = None,
    shift: tuple[float, float] = (0, 0),
    *,
    smooth: VideoNode | None = None,
    **kwargs: Any
) -> VideoNode
Source code
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
@inject_self
def scale(  # type: ignore
    self, clip: vs.VideoNode, width: int | None = None, height: int | None = None,
    shift: tuple[float, float] = (0, 0), *, smooth: vs.VideoNode | None = None, **kwargs: Any
) -> vs.VideoNode:
    width, height = self._wh_norm(clip, width, height)

    fsrcnnx = self.ref_scaler.scale(clip, width, height, shift, **kwargs)

    if isinstance(self.reference, vs.VideoNode):
        smooth = self.reference

        if shift != (0, 0):
            smooth = self._kernel.shift(smooth, shift)  # type: ignore
    else:
        smooth = self._reference.scale(clip, width, height, shift)  # type: ignore

    assert smooth

    check_ref_clip(fsrcnnx, smooth)

    smooth_sharp = self.unsharp_func(smooth, *self.args, **self.kwargs)

    if isinstance(self.merge_mode, LimitFilterMode):
        return limit_filter(smooth, fsrcnnx, smooth_sharp, self.merge_mode)

    if self.merge_mode:
        return MeanMode.MEDIAN(smooth, fsrcnnx, smooth_sharp)

    return combine([smooth, fsrcnnx, smooth_sharp], ExprOp.MIN)