Skip to content

rescale

Classes:

  • Rescale

    Rescale wrapper supporting everything you need for (fractional) descaling,

  • RescaleBase

Attributes:

RescaleT module-attribute

RescaleT = TypeVar('RescaleT', bound='RescaleBase')

Rescale

Rescale(
    clip: VideoNode,
    /,
    height: int | float,
    kernel: KernelT,
    upscaler: ScalerT = ArtCNN,
    downscaler: ScalerT = Hermite(linear=True),
    width: int | float | None = None,
    base_height: int | None = None,
    base_width: int | None = None,
    crop: tuple[LeftCrop, RightCrop, TopCrop, BottomCrop] = CropRel(),
    shift: tuple[TopShift, LeftShift] = (0, 0),
    field_based: FieldBasedT | bool | None = None,
    border_handling: int | BorderHandling = MIRROR,
)

Bases: RescaleBase

Rescale wrapper supporting everything you need for (fractional) descaling, re-upscaling and masking-out details.

Examples usage:

  • Basic 720p rescale:

    from vsscale import Rescale
    from vskernels import Bilinear
    
    rs = Rescale(clip, 720, Bilinear)
    final = rs.upscale
    
  • Adding aa and dehalo on doubled clip:

    from vsaa import based_aa
    from vsdehalo import fine_dehalo
    
    aa = based_aa(rs.doubled, supersampler=False)
    dehalo = fine_dehalo(aa, ...)
    
    rs.doubled = dehalo
    
  • Loading line_mask and credit_mask:

    from vsmasktools import diff_creditless_oped
    from vsexprtools import ExprOp
    
    rs.default_line_mask()
    
    oped_credit_mask = diff_creditless_oped(...)
    credit_mask = rs.default_credit_mask(thr=0.209, ranges=(200, 300), postfilter=4)
    rs.credit_mask = ExprOp.ADD.combine(oped_credit_mask, credit_mask)
    
  • Fractional rescale:

    from vsscale import Rescale
    from vskernels import Bilinear
    
    # Forcing the height to a float will ensure a fractional descale
    rs = Rescale(clip, 800.0, Bilinear)
    >>> rs.descale_args
    ScalingArgs(
        width=1424, height=800, src_width=1422.2222222222222, src_height=800.0,
        src_top=0.0, src_left=0.8888888888889142, mode='hw'
    )
    
    # while doing this will not
    rs = Rescale(clip, 800, Bilinear)
    >>> rs.descale_args
    ScalingArgs(width=1422, height=800, src_width=1422, src_height=800, src_top=0, src_left=0, mode='hw')
    
  • Cropping is also supported:

    from vsscale import Rescale
    from vskernels import Bilinear
    
    # Descaling while cropping the letterboxes at the top and bottom
    rs = Rescale(clip, 874, Bilinear, crop=(0, 0, 202, 202))
    >>> rs.descale_args
    ScalingArgs(
        width=1554, height=548, src_width=1554.0, src_height=547.0592592592592,
        src_top=0.4703703703703752, src_left=0.0, mode='hw'
    )
    
    # Same thing but ensuring the width is fractional descaled
    rs = Rescale(clip, 874.0, Bilinear, crop=(0, 0, 202, 202))
    >>> rs.descale_args
    ScalingArgs(
        width=1554, height=548, src_width=1553.7777777777778, src_height=547.0592592592592,
        src_top=0.4703703703703752, src_left=0.11111111111108585, mode='hw'
    )
    

Initialize the rescaling process.

Parameters:

  • clip

    (VideoNode) –

    Clip to be rescaled.

  • height

    (int | float) –

    Height to be descaled to. If passed as a float, a fractional descale is performed.

  • kernel

    (KernelT) –

    Kernel used for descaling.

  • upscaler

    (ScalerT, default: ArtCNN ) –

    Scaler that supports doubling. Defaults to ArtCNN.

  • downscaler

    (ScalerT, default: Hermite(linear=True) ) –

    Scaler used to downscale the upscaled clip back to input resolution. Defaults to Hermite(linear=True).

  • width

    (int | float | None, default: None ) –

    Width to be descaled to. If None, it is automatically calculated from the height.

  • base_height

    (int | None, default: None ) –

    Integer height to contain the clip within. If None, it is automatically calculated from the height.

  • base_width

    (int | None, default: None ) –

    Integer width to contain the clip within. If None, it is automatically calculated from the width.

  • crop

    (tuple[LeftCrop, RightCrop, TopCrop, BottomCrop], default: CropRel() ) –

    Cropping values to apply before descale. The ratio descale_height / source_height is preserved even after descale. The cropped area is restored when calling the upscale property.

  • shift

    (tuple[TopShift, LeftShift], default: (0, 0) ) –

    Pixel shifts to apply during descale and upscale. Defaults to (0, 0).

  • field_based

    (FieldBasedT | bool | None, default: None ) –

    Whether the input is cross-converted or interlaced content.

  • border_handling

    (int | BorderHandling, default: MIRROR ) –

    Adjusts how the clip is padded internally during the scaling process. Accepted values are: - 0 (MIRROR): Assume the image was resized with mirror padding. - 1 (ZERO): Assume the image was resized with zero padding. - 2 (EXTEND): Assume the image was resized with extend padding, where the outermost row was extended infinitely far. Defaults to 0.

Methods:

  • default_credit_mask

    Load a credit mask by making a difference mask between src and rescaled clips

  • default_line_mask

    Load a default Kirsch line mask in the class instance. Additionnaly, it is returned.

Attributes:

Source code
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
def __init__(
    self,
    clip: vs.VideoNode,
    /,
    height: int | float,
    kernel: KernelT,
    upscaler: ScalerT = ArtCNN,
    downscaler: ScalerT = Hermite(linear=True),
    width: int | float | None = None,
    base_height: int | None = None,
    base_width: int | None = None,
    crop: tuple[LeftCrop, RightCrop, TopCrop, BottomCrop] = CropRel(),
    shift: tuple[TopShift, LeftShift] = (0, 0),
    field_based: FieldBasedT | bool | None = None,
    border_handling: int | BorderHandling = BorderHandling.MIRROR
) -> None:
    """
    Initialize the rescaling process.

    :param clip:                Clip to be rescaled.
    :param height:              Height to be descaled to.
                                If passed as a float, a fractional descale is performed.
    :param kernel:              Kernel used for descaling.
    :param upscaler:            Scaler that supports doubling. Defaults to ``ArtCNN``.
    :param downscaler:          Scaler used to downscale the upscaled clip back to input resolution.
                                Defaults to ``Hermite(linear=True)``.
    :param width:               Width to be descaled to. If ``None``, it is automatically calculated from the height.
    :param base_height:         Integer height to contain the clip within.
                                If ``None``, it is automatically calculated from the height.
    :param base_width:          Integer width to contain the clip within.
                                If ``None``, it is automatically calculated from the width.
    :param crop:                Cropping values to apply before descale.
                                The ratio ``descale_height / source_height`` is preserved even after descale.
                                The cropped area is restored when calling the ``upscale`` property.
    :param shift:               Pixel shifts to apply during descale and upscale. Defaults to ``(0, 0)``.
    :param field_based:         Whether the input is cross-converted or interlaced content.
    :param border_handling:     Adjusts how the clip is padded internally during the scaling process.
                                Accepted values are:

                                   - ``0`` (MIRROR): Assume the image was resized with mirror padding.
                                   - ``1`` (ZERO):   Assume the image was resized with zero padding.
                                   - ``2`` (EXTEND): Assume the image was resized with extend padding, where the outermost row was extended infinitely far.

                                Defaults to ``0``.
    """
    self._line_mask: ConstantFormatVideoNode | None = None
    self._credit_mask: ConstantFormatVideoNode | None = None
    self._ignore_mask: ConstantFormatVideoNode | None = None
    self._crop = crop
    self._pre = clip

    self.descale_args = ScalingArgs.from_args(
        clip, height, width, base_height, base_width, shift[0], shift[1], crop, mode='hw'
    )

    super().__init__(clip, kernel, upscaler, downscaler, field_based, border_handling)

    if self._crop > (0, 0, 0, 0):
        self.clipy = self.clipy.std.Crop(*self._crop)

border_handling instance-attribute

border_handling = BorderHandling(int(border_handling))

chroma instance-attribute

chroma = chroma

clipy instance-attribute

clipy = Crop(*_crop)

credit_mask deletable property writable

credit_mask: ConstantFormatVideoNode

descale cached property

descale: ConstantFormatVideoNode

descale_args instance-attribute

descale_args = from_args(
    clip,
    height,
    width,
    base_height,
    base_width,
    shift[0],
    shift[1],
    crop,
    mode="hw",
)

doubled cached property

doubled: ConstantFormatVideoNode

downscaler instance-attribute

downscaler = ensure_obj(downscaler)

field_based instance-attribute

field_based: FieldBased | None = from_param(field_based)

ignore_mask deletable property writable

ignore_mask: ConstantFormatVideoNode

kernel instance-attribute

kernel = ensure_obj(kernel)

line_mask deletable property writable

line_mask: ConstantFormatVideoNode

rescale cached property

rescale: ConstantFormatVideoNode

upscale cached property

upscale: ConstantFormatVideoNode

Returns the upscaled clip

upscaler instance-attribute

upscaler = ensure_obj(upscaler)

default_credit_mask

default_credit_mask(
    rescale: VideoNode | None = None,
    src: VideoNode | None = None,
    thr: float = 0.216,
    expand: int = 4,
    ranges: FrameRangeN | FrameRangesN | None = None,
    exclusive: bool = False,
    **kwargs: Any
) -> ConstantFormatVideoNode

Load a credit mask by making a difference mask between src and rescaled clips

Parameters:

  • rescale

    (VideoNode | None, default: None ) –

    Rescaled clip, defaults to rescaled instance clip

  • src

    (VideoNode | None, default: None ) –

    Source clip, defaults to source instance clip

  • thr

    (float, default: 0.216 ) –

    Threshold of the amplification expr, defaults to 0.216

  • expand

    (int, default: 4 ) –

    Additional expand radius applied to the mask, defaults to 4

  • ranges

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

    If specified, ranges to apply the credit clip to

  • exclusive

    (bool, default: False ) –

    Use exclusive ranges (Default: False)

Returns:

  • ConstantFormatVideoNode

    Generated mask

Source code
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
def default_credit_mask(
    self, rescale: vs.VideoNode | None = None, src: vs.VideoNode | None = None,
    thr: float = 0.216, expand: int = 4,
    ranges: FrameRangeN | FrameRangesN | None = None, exclusive: bool = False,
    **kwargs: Any
) -> ConstantFormatVideoNode:
    """
    Load a credit mask by making a difference mask between src and rescaled clips

    :param rescale:     Rescaled clip, defaults to rescaled instance clip
    :param src:         Source clip, defaults to source instance clip
    :param thr:         Threshold of the amplification expr, defaults to 0.216
    :param expand:      Additional expand radius applied to the mask, defaults to 4
    :param ranges:      If specified, ranges to apply the credit clip to
    :param exclusive:   Use exclusive ranges (Default: False)
    :return:            Generated mask
    """
    if not src:
        src = self.clipy
    if not rescale:
        rescale = self.rescale

    src, rescale = get_y(src), get_y(rescale)

    credit_mask = based_diff_mask(
        src, rescale, thr=thr, expand=expand, func=self.default_credit_mask, **kwargs
    )

    if ranges is not None:
        credit_mask = replace_ranges(credit_mask.std.BlankClip(keep=True), credit_mask, ranges, exclusive)

    self.credit_mask = credit_mask

    return self.credit_mask

default_line_mask

default_line_mask(
    clip: VideoNode | None = None, scaler: ScalerT = Bilinear, **kwargs: Any
) -> ConstantFormatVideoNode

Load a default Kirsch line mask in the class instance. Additionnaly, it is returned.

Parameters:

  • clip

    (VideoNode | None, default: None ) –

    Reference clip, defaults to doubled clip if None.

  • scaler

    (ScalerT, default: Bilinear ) –

    Scaled used for matching the source clip format, defaults to Bilinear

Returns:

  • ConstantFormatVideoNode

    Generated mask.

Source code
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
def default_line_mask(
    self, clip: vs.VideoNode | None = None, scaler: ScalerT = Bilinear, **kwargs: Any
) -> ConstantFormatVideoNode:
    """
    Load a default Kirsch line mask in the class instance. Additionnaly, it is returned.

    :param clip:    Reference clip, defaults to doubled clip if None.
    :param scaler:  Scaled used for matching the source clip format, defaults to Bilinear
    :return:        Generated mask.
    """
    scaler = Scaler.ensure_obj(scaler)
    scale_kwargs = scaler.kwargs if clip else self.descale_args.kwargs(self.doubled) | scaler.kwargs

    clip = clip if clip else self.doubled

    line_mask = KirschTCanny.edgemask(clip, **kwargs).std.Maximum().std.Minimum()
    line_mask = scaler.scale(  # type: ignore[assignment]
        line_mask, self.clipy.width, self.clipy.height, format=self.clipy.format, **scale_kwargs
    )

    self.line_mask = line_mask

    return self.line_mask

RescaleBase

RescaleBase(
    clip: VideoNode,
    /,
    kernel: KernelT,
    upscaler: ScalerT = ArtCNN,
    downscaler: ScalerT = Hermite(linear=True),
    field_based: FieldBasedT | bool | None = None,
    border_handling: int | BorderHandling = MIRROR,
)

Attributes:

Source code
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
def __init__(
    self,
    clip: vs.VideoNode,
    /,
    kernel: KernelT,
    upscaler: ScalerT = ArtCNN,
    downscaler: ScalerT = Hermite(linear=True),
    field_based: FieldBasedT | bool | None = None,
    border_handling: int | BorderHandling = BorderHandling.MIRROR
) -> None:
    assert check_variable(clip, self.__class__)

    self.clipy, *chroma = split(clip)
    self.chroma = chroma

    self.kernel = Kernel.ensure_obj(kernel)
    self.upscaler = Scaler.ensure_obj(upscaler)

    self.downscaler = Scaler.ensure_obj(downscaler)

    self.field_based = FieldBased.from_param(field_based)

    self.border_handling = BorderHandling(int(border_handling))

border_handling instance-attribute

border_handling = BorderHandling(int(border_handling))

chroma instance-attribute

chroma = chroma

descale cached property

descale: ConstantFormatVideoNode

descale_args instance-attribute

descale_args: ScalingArgs

doubled cached property

doubled: ConstantFormatVideoNode

downscaler instance-attribute

downscaler = ensure_obj(downscaler)

field_based instance-attribute

field_based: FieldBased | None = from_param(field_based)

kernel instance-attribute

kernel = ensure_obj(kernel)

rescale cached property

rescale: ConstantFormatVideoNode

upscale cached property

upscale: ConstantFormatVideoNode

Returns the upscaled clip

upscaler instance-attribute

upscaler = ensure_obj(upscaler)