Skip to content

qtgmc

Classes:

  • QTempGaussMC

    Quick Temporal Gaussian Motion Compensated (QTGMC)

Functions:

  • mask_shimmer

    Filters out differences unrelated to bob shimmer by isolating thin horizontal areas.

QTGMCArgs

Namespace containing helper TypedDict definitions for various argument groups.

Classes:

Blur

Bases: TypedDict

Arguments accepted by MVTools.flow_blur.

Attributes:

prec instance-attribute

prec: int | None

Compensate

Bases: TypedDict

Arguments accepted by MVTools.compensate.

Attributes:

thsad instance-attribute

thsad: int | None

time instance-attribute

time: float | None

Degrain

Bases: TypedDict

Arguments accepted by MVTools.degrain.

Attributes:

limit instance-attribute

limit: float | tuple[float, float] | None

planes instance-attribute

planes: Planes

Mask

Bases: TypedDict

Arguments accepted by MVTools.mask.

Attributes:

gamma instance-attribute

gamma: float | None

ml instance-attribute

ml: float | None

scval instance-attribute

scval: float | None

time instance-attribute

time: float | None

MaskShimmer

Bases: TypedDict

Arguments accepted by mask_shimmer.

Attributes:

erosion_distance instance-attribute

erosion_distance: int

over_dilation instance-attribute

over_dilation: int

PrefilterToFullRange

Bases: TypedDict

Arguments accepted by prefilter_to_full_range.

Attributes:

slope instance-attribute

slope: float

smooth instance-attribute

smooth: float

QTGMCGraph

QTGMCGraph(
    mode: Mode,
    clip: VideoNode,
    tff: FieldBasedLike | bool | None,
    settings: _QTGMCBuilder,
    func: FuncExcept,
)

Bases: VSObject

Processing graph for an individual QTempGaussMC run.

The graph exposes each processing stage as a lazily evaluated cached property. It is returned alongside the output clip when return_graph=True is passed to a QTempGaussMC processing method. This allows the intermediate clips and motion vectors used to produce the output to be inspected or reused.

Returned graphs are frozen after evaluation so that access is limited to stages used to construct the output.

Usage examples
  • Inspecting the output of QTempGaussMC.prefilter:
    qtgmc = vsdeinterlace.QTempGaussMC()
    deinterlaced, graph = qtgmc.deinterlace(clip, return_graph=True)
    prefilter = graph.prefilter
    
  • Reusing the internal MVTools object's MotionVectors:
    qtgmc = vsdeinterlace.QTempGaussMC()
    deinterlaced, graph = qtgmc.deinterlace(clip, return_graph=True)
    vectors = graph.mv.vectors
    

Additional usage info: JET Encoding Guide

Parameters:

  • mode

    (Mode) –

    Processing mode used to construct the graph.

  • clip

    (VideoNode) –

    Clip to process.

  • tff

    (FieldBasedLike | bool | None) –

    Field order (top-field-first). If None, inferred from the clip.

  • settings

    (_QTGMCBuilder) –

    _QTGMCBuilder instance containing the settings for each processing stage.

  • func

    (FuncExcept) –

    Function returned for custom error handling. This should only be set by VS package developers.

Raises:

Classes:

  • Mode

    Processing mode used to construct the graph.

Methods:

Attributes:

Source code in vsdeinterlace/qtgmc.py
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
def __init__(
    self,
    mode: Mode,
    clip: vs.VideoNode,
    tff: FieldBasedLike | bool | None,
    settings: _QTGMCBuilder,
    func: FuncExcept,
) -> None:
    """
    Args:
        mode: Processing mode used to construct the graph.
        clip: Clip to process.
        tff: Field order (top-field-first). If `None`, inferred from the clip.
        settings: `_QTGMCBuilder` instance containing the settings for each processing stage.
        func: Function returned for custom error handling. This should only be set by VS package developers.

    Raises:
        UnsupportedFieldBasedError: If `clip` is [FieldBased.PROGRESSIVE][vstools.FieldBased.PROGRESSIVE] and `mode`
            is not `Mode.DESHIMMER`.
    """

    self.clip = clip
    self.tff = FieldBased.from_param_or_video(tff, clip, True, func)
    self.mode = mode
    self.settings = settings
    self.func = func

    if not (self.tff.is_inter or mode is self.Mode.DESHIMMER):
        raise UnsupportedFieldBasedError("This mode is incompatible with progressive video!", func)

clip instance-attribute

clip = clip

func instance-attribute

func = func

mode instance-attribute

mode = mode

settings instance-attribute

settings = settings

tff instance-attribute

Mode

Bases: CustomEnum

Processing mode used to construct the graph.

Methods:

Attributes:

  • BOB

    Bob interlaced input.

  • DEINTERLACE

    Deinterlace interlaced input.

  • DESHIMMER

    Deshimmer progressive input.

  • REPAIR

    Repair badly deinterlaced input.

BOB class-attribute instance-attribute

BOB = auto()

Bob interlaced input.

Interpolates missing fields to reconstruct progressive frames. QTempGaussMC.motion_blur fps_divisor is ignored.

DEINTERLACE class-attribute instance-attribute

DEINTERLACE = auto()

Deinterlace interlaced input.

Interpolates missing fields to reconstruct progressive frames. QTempGaussMC.motion_blur fps_divisor is respected.

DESHIMMER class-attribute instance-attribute

DESHIMMER = auto()

Deshimmer progressive input.

Removes horizontal shimmering artifacts from progressive sources.

REPAIR class-attribute instance-attribute

REPAIR = auto()

Repair badly deinterlaced input.

Drops half the fields to recreate an interlaced clip using the remaining ones.

__call__

__call__(
    clip: VideoNode,
    tff: FieldBasedLike | bool | None,
    settings: _QTGMCBuilder,
    func: FuncExcept,
) -> QTGMCGraph
Source code in vsdeinterlace/qtgmc.py
 999
1000
1001
1002
1003
1004
1005
1006
def __call__(
    self,
    clip: vs.VideoNode,
    tff: FieldBasedLike | bool | None,
    settings: _QTGMCBuilder,
    func: FuncExcept,
) -> QTGMCGraph:
    return QTGMCGraph(self, clip, tff, settings, func)

from_param classmethod

from_param(value: Any, func_except: FuncExcept | None = None) -> Self

Return the enum value from a parameter.

Parameters:

  • value
    (Any) –

    Value to instantiate the enum class.

  • func_except
    (FuncExcept | None, default: None ) –

    Exception function.

Returns:

  • Self

    Enum value.

Raises:

Source code in jetpytools/enums/base.py
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
@classmethod
def from_param(cls, value: Any, func_except: FuncExcept | None = None) -> Self:
    """
    Return the enum value from a parameter.

    Args:
        value: Value to instantiate the enum class.
        func_except: Exception function.

    Returns:
        Enum value.

    Raises:
        NotFoundEnumValue: Variable not found in the given enum.
    """
    func_except = func_except or cls.from_param

    try:
        return cls(value)
    except (ValueError, TypeError):
        pass

    if isinstance(func_except, tuple):
        func_name, var_name = func_except
    else:
        func_name, var_name = func_except, repr(cls)

    raise NotFoundEnumValueError(
        'The given value for "{var_name}" argument must be a valid {enum_name}, not "{value}"!\n'
        "Valid values are: [{readable_enum}].",
        func_name,
        var_name=var_name,
        enum_name=cls,
        value=value,
        readable_enum=(f"{name} ({value!s})" for name, value in cls.__members__.items()),
        reason=value,
    ) from None

basic

basic() -> VideoNode

Output of QTempGaussMC.basic.

Source code in vsdeinterlace/qtgmc.py
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
@cachedproperty
def basic(self) -> vs.VideoNode:
    """Output of [QTempGaussMC.basic][vsdeinterlace.QTempGaussMC.basic]."""

    smoothed = self._binomial_degrain(self.bobbed, self.settings.basic_tr, **self.settings.basic_degrain_args)

    if self.settings.basic_tr:
        smoothed = mask_shimmer(smoothed, self.bobbed, **self.settings.basic_mask_shimmer_args, func=self.func)

        if self.settings.source_match_iterations:
            smoothed = self._source_match(smoothed)

    if self.settings.lossless_mode is self.settings.LosslessMode.PRESHARPEN:
        smoothed = self._lossless(smoothed)

    resharp = self._sharpen(smoothed)

    if self.settings.sharpen_limit_mode.is_presmooth and self._sharpness_limiting_enabled:
        if self.settings.back_blend_mode in (
            self.settings.BackBlendMode.PRELIMIT,
            self.settings.BackBlendMode.BOTH,
        ):
            resharp = self._back_blend(resharp, smoothed)

        resharp = self._sharpen_limit(resharp)

        if self.settings.back_blend_mode in (
            self.settings.BackBlendMode.POSTLIMIT,
            self.settings.BackBlendMode.BOTH,
        ):
            resharp = self._back_blend(resharp, smoothed)
    elif self.settings.back_blend_mode is not self.settings.BackBlendMode.NONE and self._sharpening_enabled:
        resharp = self._back_blend(resharp, smoothed)

    return self._noise_restore(resharp, self.settings.basic_noise_restore)

bobbed

bobbed() -> VideoNode

High-quality bobbed clip.

Used as a spatial interpolation base for QTempGaussMC.basic and QTempGaussMC.source_match.

Source code in vsdeinterlace/qtgmc.py
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
@cachedproperty
def bobbed(self) -> vs.VideoNode:
    """
    High-quality bobbed clip.

    Used as a spatial interpolation base for [QTempGaussMC.basic][vsdeinterlace.QTempGaussMC.basic] and
    [QTempGaussMC.source_match][vsdeinterlace.QTempGaussMC.source_match].
    """

    bobbed = self._interpolate(self._bobber_input, self.settings.basic_bobber)

    if self._repair_mask_enabled:
        mask = self.mv.mask(
            direction=MVDirection.BACKWARD,
            kind=MaskMode.SAD,
            thscd=self.settings.analyze_thscd,
            **self.settings.basic_mask_args,
        )
        bobbed = self._denoise_output.std.MaskedMerge(bobbed, mask)

    return bobbed

denoise

denoise() -> VideoNode

Output of QTempGaussMC.denoise.

Only available when using noise processing.

Source code in vsdeinterlace/qtgmc.py
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
@cachedproperty
def denoise(self) -> vs.VideoNode:
    """
    Output of [QTempGaussMC.denoise][vsdeinterlace.QTempGaussMC.denoise].

    Only available when using noise processing.
    """

    if self.settings.denoise_mc_denoise and self.settings.denoise_tr:
        denoised = self.mv.compensate(
            tr=self.settings.denoise_tr,
            thscd=self.settings.analyze_thscd,
            temporal_func=lambda clip: self.settings.denoise_func(clip, tr=self.settings.denoise_tr),
            **self.settings.denoise_func_comp_args,
        )
    else:
        denoised = self.settings.denoise_func(self.draft, tr=self.settings.denoise_tr)

    if self.mode in (self.Mode.DEINTERLACE, self.Mode.BOB):
        denoised = reinterlace(denoised, self.tff, self.func)

    return denoised

draft

draft() -> VideoNode

Draft processed clip.

Used as a base for QTempGaussMC.prefilter and QTempGaussMC.denoise.

Only available when using noise or motion-compensated processing.

Source code in vsdeinterlace/qtgmc.py
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
@cachedproperty
def draft(self) -> vs.VideoNode:
    """
    Draft processed clip.

    Used as a base for [QTempGaussMC.prefilter][vsdeinterlace.QTempGaussMC.prefilter] and
    [QTempGaussMC.denoise][vsdeinterlace.QTempGaussMC.denoise].

    Only available when using noise or motion-compensated processing.
    """

    if self.mode in (self.Mode.DEINTERLACE, self.Mode.BOB):
        return Catrom().bob(self.clip, tff=self.tff)

    return self.clip

final

final() -> VideoNode

Output of QTempGaussMC.final.

Source code in vsdeinterlace/qtgmc.py
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
@cachedproperty
def final(self) -> vs.VideoNode:
    """Output of [QTempGaussMC.final][vsdeinterlace.QTempGaussMC.final]."""

    if self.settings.final_tr:
        smoothed = self.mv.degrain(
            self.basic,
            tr=self.settings.final_tr,
            thsad=self.settings.final_thsad,
            thsad2=self.settings.final_thsad2,
            thscd=self.settings.analyze_thscd,
            **self.settings.final_degrain_args,
        )
    else:
        smoothed = self.basic

    if smoothed is not self.bobbed:
        smoothed = mask_shimmer(smoothed, self.bobbed, **self.settings.final_mask_shimmer_args, func=self.func)

    if self.settings.sharpen_limit_mode.is_postsmooth and self._sharpness_limiting_enabled:
        smoothed = self._sharpen_limit(smoothed)

    if self.settings.lossless_mode is self.settings.LosslessMode.POSTSMOOTH:
        smoothed = self._lossless(smoothed)

    return self._noise_restore(smoothed, self.settings.final_noise_restore)

freeze

freeze() -> Self

Freeze the graph at its current evaluation state.

Cached properties remain accessible; however, attempting to access a property that has not been evaluated raises an AttributeError

Source code in vsdeinterlace/qtgmc.py
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
def freeze(self) -> Self:
    """
    Freeze the graph at its current evaluation state.

    Cached properties remain accessible; however, attempting to access a property that has not been evaluated raises
    an `AttributeError`
    """

    cache = self.__dict__.setdefault(cachedproperty.cache_key, {})

    if not isinstance(cache, self._FrozenCache):
        self.__dict__[cachedproperty.cache_key] = self._FrozenCache(cache)

    return self

motion_blur

motion_blur() -> VideoNode

Output of QTempGaussMC.motion_blur.

Source code in vsdeinterlace/qtgmc.py
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
@cachedproperty
def motion_blur(self) -> vs.VideoNode:
    """Output of [QTempGaussMC.motion_blur][vsdeinterlace.QTempGaussMC.motion_blur]."""

    if self._motion_blur_level:
        blurred = self.mv.flow_blur(
            self.final,
            blur=self._motion_blur_level,
            thscd=self.settings.analyze_thscd,
            **self.settings.motion_blur_blur_args,
        )

        if self.settings.motion_blur_mask_args.get("ml") != 0:
            mask = self.mv.mask(
                direction=MVDirection.BACKWARD,
                kind=MaskMode.VECTOR_LENGTH,
                thscd=self.settings.analyze_thscd,
                **self.settings.motion_blur_mask_args,
            )

            blurred = self.final.std.MaskedMerge(blurred, mask)
    else:
        blurred = self.final

    if self._motion_blur_fps_divisor > 1:
        blurred = blurred[:: self._motion_blur_fps_divisor]

    return blurred

mv

mv() -> MVTools

MVTools instance used during processing.

Only available when using motion-compensated processing.

Source code in vsdeinterlace/qtgmc.py
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
@cachedproperty
def mv(self) -> MVTools:
    """
    [MVTools][vsdenoise.mvtools.mvtools.MVTools] instance used during processing.

    Only available when using motion-compensated processing.
    """

    preset = dict(self.settings.analyze_preset)
    if not self.settings.analyze_vectors:
        preset.update(search_clip=self.prefilter)

    mv = MVTools(self.draft, vectors=self.settings.analyze_vectors, **preset)

    if self.settings.analyze_vectors:
        return mv

    noise_restore_enabled = bool(self.settings.basic_noise_restore or self.settings.final_noise_restore)

    tr = max(
        self.settings.analyze_force_tr,
        self.settings.denoise_tr
        if self.settings.denoise_mc_denoise and (self.settings.denoise_full_denoise or noise_restore_enabled)
        else 0,
        self.settings.denoise_stabilize is not False and noise_restore_enabled,
        self._repair_mask_enabled,
        self.settings.basic_tr,
        self.settings.source_match_tr
        if self.settings.source_match_iterations > 1 and self.settings.basic_tr
        else 0,
        self.settings.sharpen_limit_radius
        if self.settings.sharpen_limit_mode.is_temporal and self._sharpness_limiting_enabled
        else 0,
        self.settings.final_tr,
        bool(self._motion_blur_level),
    )

    blksize = self.settings.analyze_blksize
    mv.analyze(tr=tr, blksize=blksize, overlap_div=self.settings.analyze_overlap)

    for _ in range(self.settings.analyze_refine):
        blksize = refine_blksize(blksize)
        mv.recalculate(
            thsad=self.settings.analyze_thsad_recalc, blksize=blksize, overlap_div=self.settings.analyze_overlap
        )

    return mv

noise

noise() -> VideoNode

Noise extracted by QTempGaussMC.denoise.

Only available when using noise restoration.

Source code in vsdeinterlace/qtgmc.py
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
@cachedproperty
def noise(self) -> vs.VideoNode:
    """
    Noise extracted by [QTempGaussMC.denoise][vsdeinterlace.QTempGaussMC.denoise].

    Only available when using noise restoration.
    """

    noise = self.clip.std.MakeDiff(self.denoise)

    if self.mode in (self.Mode.DEINTERLACE, self.Mode.BOB):
        match self.settings.denoise_deint:
            case self.settings.NoiseDeintMode.WEAVE:
                noise = noise.std.SeparateFields(self.tff.is_tff).std.DoubleWeave(self.tff.is_tff)
            case self.settings.NoiseDeintMode.BOB:
                noise = Catrom().bob(noise, tff=self.tff)
            case self.settings.NoiseDeintMode.GENERATE:
                noise = noise.std.SeparateFields(self.tff.is_tff)

                noise_min = Morpho.inpand(noise, sw=2, sh=1, func=self.func)
                noise_max = Morpho.expand(noise, sw=2, sh=1, func=self.func)

                noise_gen = Grainer.GAUSS(
                    noise,
                    # Use the maximum variance that satisfies the 3-sigma rule.
                    (0.5 * 255 / 3) ** 2,
                    protect_edges=False,
                    protect_neutral_chroma=False,
                    neutral_out=True,
                )
                noise_gen = norm_expr(
                    [noise_max, noise_min, noise_gen],
                    # Limitation: This gain map can never reach 1.0 with integer formats.
                    # Peak gain at 8-bit: (255 - 128) / 256 + 0.5 = ~0.996.
                    "y x y - z neutral - range_size / 0.5 + * +",
                    func=self.func,
                )
                noise = reweave(noise, noise_gen, self.tff.field, self.func)

        noise = FieldBased.PROGRESSIVE.apply(noise)

    if self.settings.denoise_stabilize is not False:
        noise_comp, _ = self.mv.compensate(
            noise,
            direction=MVDirection.BACKWARD,
            tr=1,
            thscd=self.settings.analyze_thscd,
            interleave=False,
            **self.settings.denoise_stabilize_comp_args,
        )

        noise = norm_expr(
            [noise, *noise_comp],
            "x neutral - abs y neutral - abs > x y ? dup x y + 2 / swap - {weight} * +",
            weight=self.settings.denoise_stabilize,
            func=self.func,
        )

    return noise

prefilter

prefilter() -> VideoNode

Output of QTempGaussMC.prefilter.

Only available when motion vectors need to be generated.

Source code in vsdeinterlace/qtgmc.py
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
@cachedproperty
def prefilter(self) -> vs.VideoNode:
    """
    Output of [QTempGaussMC.prefilter][vsdeinterlace.QTempGaussMC.prefilter].

    Only available when motion vectors need to be generated.
    """

    if self.mode is self.Mode.REPAIR:
        search = BlurMatrix.BINOMIAL()(self.draft, mode=ConvMode.VERTICAL, func=self.func)
    else:
        search = self.draft

    if self.settings.prefilter_tr:
        smoothed = BlurMatrix.BINOMIAL(self.settings.prefilter_tr, mode=ConvMode.TEMPORAL)(
            sc_detect(search, self.settings.prefilter_sc_threshold), scenechange=True, func=self.func
        )
        smoothed = mask_shimmer(smoothed, search, **self.settings.prefilter_mask_shimmer_args, func=self.func)
    else:
        smoothed = search

    sigma, blend_weight = self.settings.prefilter_strength
    lim1, lim2, lim3 = [scale_delta(thr, 8, self.clip) for thr in self.settings.prefilter_limit]

    blurred = gauss_blur(smoothed, sigma) if sigma and blend_weight else smoothed
    limited = norm_expr(
        [blurred, smoothed, search],
        "y x y - {weight} * + BLUR! z y {lim1} - y {lim1} + clamp TWEAK! "
        "BLUR@ {lim2} + TWEAK@ < BLUR@ {lim3} + BLUR@ {lim2} - TWEAK@ > BLUR@ {lim3} - "
        "TWEAK@ BLUR@ TWEAK@ - {bias} * + ? ?",
        weight=blend_weight,
        lim1=lim1,
        lim2=lim2,
        lim3=lim3,
        bias=self.settings.prefilter_bias,
        func=self.func,
    )

    return prefilter_to_full_range(limited, func=self.func, **self.settings.prefilter_range_expansion_args)

QTempGaussMC

QTempGaussMC(**kwargs: Any)

Bases: _QTGMCBuilder

Quick Temporal Gaussian Motion Compensated (QTGMC)

A very high-quality deinterlacer with a range of features for quality and convenience. This includes extensive noise processing capabilities, support for repair of progressive material, precision source matching, shutter speed simulation, and more.

Originally based on QTGMC by Vit and TempGaussMC by Didée.

Usage examples
  • Basic call with defaults:
    deinterlaced = QTempGaussMC().deinterlace(clip)
    
  • Using EEDI3 for interpolation:
    deinterlaced = QTempGaussMC().basic(bobber=EEDI3()).deinterlace(clip)
    
  • Enabling QTempGaussMC.lossless and increasing QTempGaussMC.final tr:
    deinterlaced = QTempGaussMC().lossless(QTempGaussMC.LosslessMode.PRESHARPEN).final(tr=2).deinterlace(clip)
    

Additional usage info: JET Encoding Guide

Parameters:

  • **kwargs

    (Any, default: {} ) –

    Additional arguments to be passed to the parameter category methods. Separate the method name from its argument with two underscores, for example: sharpen_limit__radius=1.

Classes:

Methods:

  • analyze

    Configures parameters for motion analysis.

  • back_blend

    Configures parameters for back-blending.

  • basic

    Configures parameters for the basic stage.

  • bob

    Bob interlaced input.

  • deinterlace

    Deinterlace interlaced input.

  • denoise

    Configures parameters for the denoise stage.

  • deshimmer

    Deshimmer progressive input.

  • final

    Configures parameters for the final stage.

  • lossless

    Configures parameters for lossless processing.

  • motion_blur

    Configures parameters for the motion blur stage.

  • prefilter

    Configures parameters for the prefilter stage.

  • repair

    Repair badly deinterlaced input.

  • sharpen

    Configures parameters for sharpening.

  • sharpen_limit

    Configures parameters for sharpness limiting.

  • source_match

    Configures parameters for source match processing.

Attributes:

Source code in vsdeinterlace/qtgmc.py
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
def __init__(self, **kwargs: Any) -> None:
    """
    Args:
        **kwargs: Additional arguments to be passed to the parameter category methods. Separate the method name
            from its argument with two underscores, for example: `sharpen_limit__radius=1`.
    """

    settings_methods = (
        self.prefilter,
        self.analyze,
        self.denoise,
        self.basic,
        self.source_match,
        self.lossless,
        self.sharpen,
        self.back_blend,
        self.sharpen_limit,
        self.final,
        self.motion_blur,
    )

    for method in settings_methods:
        prefix = f"{method.__name__}__"

        method(**{k.removeprefix(prefix): kwargs.pop(k) for k in tuple(kwargs) if k.startswith(prefix)})

    if kwargs:
        raise CustomValueError("Unknown arguments were passed.", self.__class__, kwargs)

analyze_thsad_recalc property writable

analyze_thsad_recalc: int

sharpen_limit_mode property writable

sharpen_limit_mode: SharpenLimitMode

sharpen_strength property writable

sharpen_strength: float

source_match_bobber property writable

source_match_bobber: Bobber

BackBlendMode

Bases: CustomEnum

When to back-blend the (blurred) difference between the pre- and post-sharpened clips.

Methods:

  • from_param

    Return the enum value from a parameter.

Attributes:

BOTH class-attribute instance-attribute

BOTH = auto()

Back-blending prior to and after QTempGaussMC.sharpen_limit.

Provides a balanced middle ground between PRELIMIT and POSTLIMIT dampening.

Note

Identical to PRELIMIT when using SharpenLimitMode.NONE, SharpenLimitMode.SPATIAL_POSTSMOOTH or SharpenLimitMode.TEMPORAL_POSTSMOOTH.

NONE class-attribute instance-attribute

NONE = auto()

No back-blending.

Keeps all QTempGaussMC.sharpen frequencies.

POSTLIMIT class-attribute instance-attribute

POSTLIMIT = auto()

Back-blending after QTempGaussMC.sharpen_limit.

Provides the strongest low-frequency dampening.

Note

Identical to PRELIMIT when using SharpenLimitMode.NONE, SharpenLimitMode.SPATIAL_POSTSMOOTH or SharpenLimitMode.TEMPORAL_POSTSMOOTH.

PRELIMIT class-attribute instance-attribute

PRELIMIT = auto()

Back-blending prior to QTempGaussMC.sharpen_limit.

Provides the weakest low-frequency dampening.

from_param classmethod

from_param(value: Any, func_except: FuncExcept | None = None) -> Self

Return the enum value from a parameter.

Parameters:

  • value
    (Any) –

    Value to instantiate the enum class.

  • func_except
    (FuncExcept | None, default: None ) –

    Exception function.

Returns:

  • Self

    Enum value.

Raises:

Source code in jetpytools/enums/base.py
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
@classmethod
def from_param(cls, value: Any, func_except: FuncExcept | None = None) -> Self:
    """
    Return the enum value from a parameter.

    Args:
        value: Value to instantiate the enum class.
        func_except: Exception function.

    Returns:
        Enum value.

    Raises:
        NotFoundEnumValue: Variable not found in the given enum.
    """
    func_except = func_except or cls.from_param

    try:
        return cls(value)
    except (ValueError, TypeError):
        pass

    if isinstance(func_except, tuple):
        func_name, var_name = func_except
    else:
        func_name, var_name = func_except, repr(cls)

    raise NotFoundEnumValueError(
        'The given value for "{var_name}" argument must be a valid {enum_name}, not "{value}"!\n'
        "Valid values are: [{readable_enum}].",
        func_name,
        var_name=var_name,
        enum_name=cls,
        value=value,
        readable_enum=(f"{name} ({value!s})" for name, value in cls.__members__.items()),
        reason=value,
    ) from None

LosslessMode

Bases: CustomEnum

When to put the original fields into the output.

Methods:

  • from_param

    Return the enum value from a parameter.

Attributes:

NONE class-attribute instance-attribute

NONE = auto()

Do not restore the original fields.

POSTSMOOTH class-attribute instance-attribute

POSTSMOOTH = auto()

Restore the original fields after QTempGaussMC.final smoothing.

Provides true lossless output, given QTempGaussMC.final noise_restore is not used. Offers minimal sharpness control and tends to have more significant artifacts.

PRESHARPEN class-attribute instance-attribute

PRESHARPEN = auto()

Restore the original fields prior to QTempGaussMC.sharpen.

Provides near-lossless fidelity, mitigates most artifacts, and retains sharpness control.

from_param classmethod

from_param(value: Any, func_except: FuncExcept | None = None) -> Self

Return the enum value from a parameter.

Parameters:

  • value
    (Any) –

    Value to instantiate the enum class.

  • func_except
    (FuncExcept | None, default: None ) –

    Exception function.

Returns:

  • Self

    Enum value.

Raises:

Source code in jetpytools/enums/base.py
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
@classmethod
def from_param(cls, value: Any, func_except: FuncExcept | None = None) -> Self:
    """
    Return the enum value from a parameter.

    Args:
        value: Value to instantiate the enum class.
        func_except: Exception function.

    Returns:
        Enum value.

    Raises:
        NotFoundEnumValue: Variable not found in the given enum.
    """
    func_except = func_except or cls.from_param

    try:
        return cls(value)
    except (ValueError, TypeError):
        pass

    if isinstance(func_except, tuple):
        func_name, var_name = func_except
    else:
        func_name, var_name = func_except, repr(cls)

    raise NotFoundEnumValueError(
        'The given value for "{var_name}" argument must be a valid {enum_name}, not "{value}"!\n'
        "Valid values are: [{readable_enum}].",
        func_name,
        var_name=var_name,
        enum_name=cls,
        value=value,
        readable_enum=(f"{name} ({value!s})" for name, value in cls.__members__.items()),
        reason=value,
    ) from None

NoiseDeintMode

Bases: CustomEnum

How to 'deinterlace' noise taken from an interlaced source.

Methods:

  • from_param

    Return the enum value from a parameter.

Attributes:

  • BOB

    Bob source noise.

  • GENERATE

    Generate fresh noise lines.

  • WEAVE

    Double weave source noise.

BOB class-attribute instance-attribute

BOB = auto()

Bob source noise.

Results in coarse noise.

GENERATE class-attribute instance-attribute

GENERATE = auto()

Generate fresh noise lines.

WEAVE class-attribute instance-attribute

WEAVE = auto()

Double weave source noise.

Lags behind by one frame.

from_param classmethod

from_param(value: Any, func_except: FuncExcept | None = None) -> Self

Return the enum value from a parameter.

Parameters:

  • value
    (Any) –

    Value to instantiate the enum class.

  • func_except
    (FuncExcept | None, default: None ) –

    Exception function.

Returns:

  • Self

    Enum value.

Raises:

Source code in jetpytools/enums/base.py
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
@classmethod
def from_param(cls, value: Any, func_except: FuncExcept | None = None) -> Self:
    """
    Return the enum value from a parameter.

    Args:
        value: Value to instantiate the enum class.
        func_except: Exception function.

    Returns:
        Enum value.

    Raises:
        NotFoundEnumValue: Variable not found in the given enum.
    """
    func_except = func_except or cls.from_param

    try:
        return cls(value)
    except (ValueError, TypeError):
        pass

    if isinstance(func_except, tuple):
        func_name, var_name = func_except
    else:
        func_name, var_name = func_except, repr(cls)

    raise NotFoundEnumValueError(
        'The given value for "{var_name}" argument must be a valid {enum_name}, not "{value}"!\n'
        "Valid values are: [{readable_enum}].",
        func_name,
        var_name=var_name,
        enum_name=cls,
        value=value,
        readable_enum=(f"{name} ({value!s})" for name, value in cls.__members__.items()),
        reason=value,
    ) from None

NoiseProcessMode

Bases: CustomIntEnum

Methods:

Attributes:

DENOISE class-attribute instance-attribute

DENOISE = 1

IDENTIFY class-attribute instance-attribute

IDENTIFY = 0

from_param classmethod

from_param(value: Any, func_except: FuncExcept | None = None) -> Self

Return the enum value from a parameter.

Parameters:

  • value
    (Any) –

    Value to instantiate the enum class.

  • func_except
    (FuncExcept | None, default: None ) –

    Exception function.

Returns:

  • Self

    Enum value.

Raises:

Source code in jetpytools/enums/base.py
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
@classmethod
def from_param(cls, value: Any, func_except: FuncExcept | None = None) -> Self:
    """
    Return the enum value from a parameter.

    Args:
        value: Value to instantiate the enum class.
        func_except: Exception function.

    Returns:
        Enum value.

    Raises:
        NotFoundEnumValue: Variable not found in the given enum.
    """
    func_except = func_except or cls.from_param

    try:
        return cls(value)
    except (ValueError, TypeError):
        pass

    if isinstance(func_except, tuple):
        func_name, var_name = func_except
    else:
        func_name, var_name = func_except, repr(cls)

    raise NotFoundEnumValueError(
        'The given value for "{var_name}" argument must be a valid {enum_name}, not "{value}"!\n'
        "Valid values are: [{readable_enum}].",
        func_name,
        var_name=var_name,
        enum_name=cls,
        value=value,
        readable_enum=(f"{name} ({value!s})" for name, value in cls.__members__.items()),
        reason=value,
    ) from None

value

value() -> int
Source code in jetpytools/enums/base.py
86
87
@enum_property
def value(self) -> int: ...

SearchPostProcess

Bases: CustomIntEnum

Methods:

Attributes:

GAUSSBLUR class-attribute instance-attribute

GAUSSBLUR = 0

GAUSSBLUR_EDGESOFTEN class-attribute instance-attribute

GAUSSBLUR_EDGESOFTEN = 1

from_param classmethod

from_param(value: Any, func_except: FuncExcept | None = None) -> Self

Return the enum value from a parameter.

Parameters:

  • value
    (Any) –

    Value to instantiate the enum class.

  • func_except
    (FuncExcept | None, default: None ) –

    Exception function.

Returns:

  • Self

    Enum value.

Raises:

Source code in jetpytools/enums/base.py
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
@classmethod
def from_param(cls, value: Any, func_except: FuncExcept | None = None) -> Self:
    """
    Return the enum value from a parameter.

    Args:
        value: Value to instantiate the enum class.
        func_except: Exception function.

    Returns:
        Enum value.

    Raises:
        NotFoundEnumValue: Variable not found in the given enum.
    """
    func_except = func_except or cls.from_param

    try:
        return cls(value)
    except (ValueError, TypeError):
        pass

    if isinstance(func_except, tuple):
        func_name, var_name = func_except
    else:
        func_name, var_name = func_except, repr(cls)

    raise NotFoundEnumValueError(
        'The given value for "{var_name}" argument must be a valid {enum_name}, not "{value}"!\n'
        "Valid values are: [{readable_enum}].",
        func_name,
        var_name=var_name,
        enum_name=cls,
        value=value,
        readable_enum=(f"{name} ({value!s})" for name, value in cls.__members__.items()),
        reason=value,
    ) from None

value

value() -> int
Source code in jetpytools/enums/base.py
86
87
@enum_property
def value(self) -> int: ...

SharpenLimitMode

Bases: CustomEnum

How and when to apply limiting to QTempGaussMC.sharpen.

Methods:

  • from_param

    Return the enum value from a parameter.

Attributes:

NONE class-attribute instance-attribute

NONE = auto()

No sharpness limiting.

SPATIAL_POSTSMOOTH class-attribute instance-attribute

SPATIAL_POSTSMOOTH = auto()

Spatial sharpness limiting after QTempGaussMC.final smoothing.

Spatial limiting is less accurate, but allows more sharpening. Applying sharpness limiting later in the algorithm leaves the result sharper, but can produce additional artifacts.

SPATIAL_PRESMOOTH class-attribute instance-attribute

SPATIAL_PRESMOOTH = auto()

Spatial sharpness limiting prior to QTempGaussMC.final smoothing.

Spatial limiting is less accurate, but allows more sharpening. Applying sharpness limiting earlier in the algorithm leaves the result softer, but produces fewer artifacts.

TEMPORAL_POSTSMOOTH class-attribute instance-attribute

TEMPORAL_POSTSMOOTH = auto()

Temporal sharpness limiting after QTempGaussMC.final smoothing.

Temporal limiting is more accurate, but allows less sharpening. Applying sharpness limiting later in the algorithm leaves the result sharper, but can produce additional artifacts.

TEMPORAL_PRESMOOTH class-attribute instance-attribute

TEMPORAL_PRESMOOTH = auto()

Temporal sharpness limiting prior to QTempGaussMC.final smoothing.

Temporal limiting is more accurate, but allows less sharpening. Applying sharpness limiting earlier in the algorithm leaves the result softer, but produces fewer artifacts.

is_postsmooth property

is_postsmooth: bool

Whether the mode applies sharpness limiting after smoothing.

is_presmooth property

is_presmooth: bool

Whether the mode applies sharpness limiting prior to smoothing.

is_spatial property

is_spatial: bool

Whether the mode uses spatial sharpness limiting.

is_temporal property

is_temporal: bool

Whether the mode uses temporal sharpness limiting.

from_param classmethod

from_param(value: Any, func_except: FuncExcept | None = None) -> Self

Return the enum value from a parameter.

Parameters:

  • value
    (Any) –

    Value to instantiate the enum class.

  • func_except
    (FuncExcept | None, default: None ) –

    Exception function.

Returns:

  • Self

    Enum value.

Raises:

Source code in jetpytools/enums/base.py
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
@classmethod
def from_param(cls, value: Any, func_except: FuncExcept | None = None) -> Self:
    """
    Return the enum value from a parameter.

    Args:
        value: Value to instantiate the enum class.
        func_except: Exception function.

    Returns:
        Enum value.

    Raises:
        NotFoundEnumValue: Variable not found in the given enum.
    """
    func_except = func_except or cls.from_param

    try:
        return cls(value)
    except (ValueError, TypeError):
        pass

    if isinstance(func_except, tuple):
        func_name, var_name = func_except
    else:
        func_name, var_name = func_except, repr(cls)

    raise NotFoundEnumValueError(
        'The given value for "{var_name}" argument must be a valid {enum_name}, not "{value}"!\n'
        "Valid values are: [{readable_enum}].",
        func_name,
        var_name=var_name,
        enum_name=cls,
        value=value,
        readable_enum=(f"{name} ({value!s})" for name, value in cls.__members__.items()),
        reason=value,
    ) from None

SharpenMode

Bases: CustomIntEnum

Methods:

Attributes:

UNSHARP class-attribute instance-attribute

UNSHARP = 0

UNSHARP_MINMAX class-attribute instance-attribute

UNSHARP_MINMAX = 1

from_param classmethod

from_param(value: Any, func_except: FuncExcept | None = None) -> Self

Return the enum value from a parameter.

Parameters:

  • value
    (Any) –

    Value to instantiate the enum class.

  • func_except
    (FuncExcept | None, default: None ) –

    Exception function.

Returns:

  • Self

    Enum value.

Raises:

Source code in jetpytools/enums/base.py
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
@classmethod
def from_param(cls, value: Any, func_except: FuncExcept | None = None) -> Self:
    """
    Return the enum value from a parameter.

    Args:
        value: Value to instantiate the enum class.
        func_except: Exception function.

    Returns:
        Enum value.

    Raises:
        NotFoundEnumValue: Variable not found in the given enum.
    """
    func_except = func_except or cls.from_param

    try:
        return cls(value)
    except (ValueError, TypeError):
        pass

    if isinstance(func_except, tuple):
        func_name, var_name = func_except
    else:
        func_name, var_name = func_except, repr(cls)

    raise NotFoundEnumValueError(
        'The given value for "{var_name}" argument must be a valid {enum_name}, not "{value}"!\n'
        "Valid values are: [{readable_enum}].",
        func_name,
        var_name=var_name,
        enum_name=cls,
        value=value,
        readable_enum=(f"{name} ({value!s})" for name, value in cls.__members__.items()),
        reason=value,
    ) from None

value

value() -> int
Source code in jetpytools/enums/base.py
86
87
@enum_property
def value(self) -> int: ...

SourceMatchMode

Bases: CustomIntEnum

Methods:

Attributes:

BASIC class-attribute instance-attribute

BASIC = 1

NONE class-attribute instance-attribute

NONE = 0

REFINED class-attribute instance-attribute

REFINED = 2

TWICE_REFINED class-attribute instance-attribute

TWICE_REFINED = 3

from_param classmethod

from_param(value: Any, func_except: FuncExcept | None = None) -> Self

Return the enum value from a parameter.

Parameters:

  • value
    (Any) –

    Value to instantiate the enum class.

  • func_except
    (FuncExcept | None, default: None ) –

    Exception function.

Returns:

  • Self

    Enum value.

Raises:

Source code in jetpytools/enums/base.py
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
@classmethod
def from_param(cls, value: Any, func_except: FuncExcept | None = None) -> Self:
    """
    Return the enum value from a parameter.

    Args:
        value: Value to instantiate the enum class.
        func_except: Exception function.

    Returns:
        Enum value.

    Raises:
        NotFoundEnumValue: Variable not found in the given enum.
    """
    func_except = func_except or cls.from_param

    try:
        return cls(value)
    except (ValueError, TypeError):
        pass

    if isinstance(func_except, tuple):
        func_name, var_name = func_except
    else:
        func_name, var_name = func_except, repr(cls)

    raise NotFoundEnumValueError(
        'The given value for "{var_name}" argument must be a valid {enum_name}, not "{value}"!\n'
        "Valid values are: [{readable_enum}].",
        func_name,
        var_name=var_name,
        enum_name=cls,
        value=value,
        readable_enum=(f"{name} ({value!s})" for name, value in cls.__members__.items()),
        reason=value,
    ) from None

value

value() -> int
Source code in jetpytools/enums/base.py
86
87
@enum_property
def value(self) -> int: ...

analyze

analyze(
    *,
    vectors: MotionVectors | None = None,
    preset: Mapping[str, Any] = HQ_SAD,
    force_tr: int = 0,
    blksize: int | tuple[int, int] = 16,
    overlap: int | tuple[int, int] = 2,
    refine: int = 1,
    thsad_recalc: int | None = None,
    thscd: int | tuple[int | None, float | None] | None = (180, 38.5),
) -> Self

Configures parameters for motion analysis.

Performs motion analysis, which is then utilized by all subsequent stages for motion-compensated processing.

High-level overview
  • Dynamic temporal radius calculation: Determines the minimum required temporal search radius across all actively used settings and processes.
  • Motion vector refinement: Iteratively shrinks block size and calls MVTools.recalculate to improve motion vector precision.

Parameters:

  • vectors

    (MotionVectors | None, default: None ) –

    Motion vectors to use instead of internally generating them. Defaults to None.

  • preset

    (Mapping[str, Any], default: HQ_SAD ) –

    MVTools preset defining base values for MVTools. Defaults to MVToolsPreset.HQ_SAD.

  • force_tr

    (int, default: 0 ) –

    Always analyze motion to at least this value, even if otherwise unnecessary. Useful if you want to reuse the generated motion vectors for other tasks. Defaults to 0.

  • blksize

    (int | tuple[int, int], default: 16 ) –

    Motion analysis block size. Larger values are faster and less sensitive to noise, but less accurate.

    • First value: Horizontal block size.
    • Second value: Vertical block size.

    A single value applies to both axes. Defaults to 16.

  • overlap

    (int | tuple[int, int], default: 2 ) –

    The block size divisor for block size overlap. Smaller values reduce blocking artifacts of MVTools processes.

    • First value: Horizontal block size divisor.
    • Second value: Vertical block size divisor.

    A single value applies to both axes. Defaults to 2.

  • refine

    (int, default: 1 ) –

    Number of iterations to recalculate motion vectors with halved block size. Improves motion vector precision without reducing denoising effectiveness. Defaults to 1.

  • thsad_recalc

    (int | None, default: None ) –

    Only poor-quality new vectors with a SAD above this value will be re-estimated by motion search. Only active when refine is used. Defaults to QTempGaussMC.basic thsad / 2.

  • thscd

    (int | tuple[int | None, float | None] | None, default: (180, 38.5) ) –

    Scene-change detection thresholds:

    • First value: SAD threshold for considering a block changed between frames.
    • Second value: Percentage of changed blocks needed to trigger a scene change.

    Defaults to (180, 38.5).

Source code in vsdeinterlace/qtgmc.py
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
def analyze(
    self,
    *,
    vectors: MotionVectors | None = None,
    preset: Mapping[str, Any] = MVToolsPreset.HQ_SAD,
    force_tr: int = 0,
    blksize: int | tuple[int, int] = 16,
    overlap: int | tuple[int, int] = 2,
    refine: int = 1,
    thsad_recalc: int | None = None,
    thscd: int | tuple[int | None, float | None] | None = (180, 38.5),
) -> Self:
    """
    Configures parameters for motion analysis.

    Performs motion analysis, which is then utilized by all subsequent stages for motion-compensated processing.

    High-level overview:
        - Dynamic temporal radius calculation: Determines the minimum required temporal search radius across all
            actively used settings and processes.
        - Motion vector refinement: Iteratively shrinks block size and calls
            [MVTools.recalculate][vsdenoise.mvtools.mvtools.MVTools.recalculate] to improve motion vector precision.

    Args:
        vectors: Motion vectors to use instead of internally generating them. Defaults to None.
        preset: [MVTools][vsdenoise.mvtools.mvtools.MVTools] preset defining base values for
            [MVTools][vsdenoise.mvtools.mvtools.MVTools]. Defaults to MVToolsPreset.HQ_SAD.
        force_tr: Always analyze motion to at least this value, even if otherwise unnecessary. Useful if you want to
            reuse the generated motion vectors for other tasks. Defaults to 0.
        blksize: Motion analysis block size. Larger values are faster and less sensitive to noise, but less
            accurate.

            - First value: Horizontal block size.
            - Second value: Vertical block size.

            A single value applies to both axes. Defaults to 16.
        overlap: The block size divisor for block size overlap. Smaller values reduce blocking artifacts of
            [MVTools][vsdenoise.mvtools.mvtools.MVTools] processes.

            - First value: Horizontal block size divisor.
            - Second value: Vertical block size divisor.

            A single value applies to both axes. Defaults to 2.
        refine: Number of iterations to recalculate motion vectors with halved block size. Improves motion vector
            precision without reducing denoising effectiveness. Defaults to 1.
        thsad_recalc: Only poor-quality new vectors with a SAD above this value will be re-estimated by motion
            search. Only active when refine is used. Defaults to
            [QTempGaussMC.basic][vsdeinterlace.QTempGaussMC.basic] `thsad / 2`.
        thscd: Scene-change detection thresholds:

               - First value: SAD threshold for considering a block changed between frames.
               - Second value: Percentage of changed blocks needed to trigger a scene change.

            Defaults to (180, 38.5).
    """

    self.analyze_vectors = vectors
    self.analyze_preset = preset
    self.analyze_force_tr = force_tr
    self.analyze_blksize = blksize
    self.analyze_overlap = overlap
    self.analyze_refine = refine
    self.analyze_thsad_recalc = thsad_recalc
    self.analyze_thscd = thscd

    return self

back_blend

back_blend(*, mode: BackBlendMode = BOTH, scale: float = 2) -> Self

Configures parameters for back-blending.

Improves QTempGaussMC.sharpen fidelity by dampening low-frequency enhancement caused by unsharpening.

High-level overview
  • Low-frequency back-blending: Gaussian-blurs the pre- and post-sharpening difference to isolate broad low-frequency shifts, then merges that blurred difference back onto the source to preserve only high-frequency edge sharpening.

Parameters:

  • mode

    (BackBlendMode, default: BOTH ) –

    When to back-blend the (blurred) sharpening difference. Defaults to BackBlendMode.BOTH.

  • scale

    (float, default: 2 ) –

    Scale factor for the Gaussian blur sigma applied to the sharpening difference. Lower values dampen sharpening more aggressively. Defaults to 2.

Source code in vsdeinterlace/qtgmc.py
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
def back_blend(self, *, mode: BackBlendMode = BackBlendMode.BOTH, scale: float = 2) -> Self:
    """
    Configures parameters for back-blending.

    Improves [QTempGaussMC.sharpen][vsdeinterlace.QTempGaussMC.sharpen] fidelity by dampening low-frequency
    enhancement caused by unsharpening.

    High-level overview:
        - Low-frequency back-blending: Gaussian-blurs the pre- and post-sharpening difference to isolate broad
            low-frequency shifts, then merges that blurred difference back onto the source to preserve only
            high-frequency edge sharpening.

    Args:
        mode: When to back-blend the (blurred) sharpening difference. Defaults to BackBlendMode.BOTH.
        scale: Scale factor for the Gaussian blur sigma applied to the sharpening difference. Lower values dampen
            sharpening more aggressively. Defaults to 2.
    """

    self.back_blend_mode = mode
    self.back_blend_scale = scale

    return self

basic

basic(
    *,
    bobber: BobberLike = _NNEDI3_DEFAULT,
    tr: int = 2,
    thsad: int | tuple[int, int] = 640,
    thsad2: int | tuple[int, int] | None = None,
    noise_restore: float = 0,
    mask_args: Mask | None = None,
    degrain_args: Degrain | None = None,
    mask_shimmer_args: MaskShimmer | None = None,
) -> Self

Configures parameters for the basic stage.

Creates the basic output of the core algorithm. Intended to eliminate bob shimmer.

High-level overview
  • High-quality bobbed clip generation: Begins with high-quality spatial interpolation to produce the bobbed clip, which inherently contains severe temporal instability known as bob shimmer.
  • (QTempGaussMC.repair) Motion SAD masking: Generates a motion-vector SAD mask to blend QTempGaussMC.denoise output over the bobbed clip, protecting static/low-motion detail.
  • Motion-compensated temporal binomial smoothing: Applies a motion-compensated temporal binomial blur to smooth the bobbed clip, removing the shimmer while avoiding ghosting artifacts.
  • Shimmer masking: Uses a specialized masking process to eliminate the introduced blurring while retaining the shimmer removal.
  • Additional refinements: Passes the temporally smoothed clip through optional fine-tuning processes:

  • Noise restoration: Optionally restores noise previously extracted by QTempGaussMC.denoise at the end of this stage.

Parameters:

  • bobber

    (BobberLike, default: _NNEDI3_DEFAULT ) –

    Bobber to use for spatial interpolation. Defaults to NNEDI3(nsize=1).

  • tr

    (int, default: 2 ) –

    Temporal radius of the motion-compensated binomial blur. Larger values reduce more shimmer but can introduce blurring and ghosting. Defaults to 2.

  • thsad

    (int | tuple[int, int], default: 640 ) –

    SAD threshold of the motion-compensated binomial blur. Larger values reduce more shimmer but can introduce blurring and ghosting.

    • First value: Luma SAD threshold.
    • Second value: Chroma SAD threshold.

    A single value applies to both luma and chroma. Defaults to 640.

  • thsad2

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

    SAD threshold of the motion-compensated linear blur for the furthest references. Larger values clean more artifacts but can introduce blurring and ghosting.

    • First value: Luma SAD threshold.
    • Second value: Chroma SAD threshold.

    A single value applies to both luma and chroma. Defaults to None.

  • noise_restore

    (float, default: 0 ) –

    Amount of noise to restore after this stage. Used to retain stable noise. Defaults to 0.

  • mask_args

    (Mask | None, default: None ) –

    Additional arguments passed to MVTools.mask. Only used for QTempGaussMC.repair. Defaults to {"ml": 10}.

  • degrain_args

    (Degrain | None, default: None ) –

    Additional arguments passed to the internal _binomial_degrain call. Defaults to None.

  • mask_shimmer_args

    (MaskShimmer | None, default: None ) –

    Additional arguments passed to mask_shimmer. Defaults to {"erosion_distance": 0}.

Source code in vsdeinterlace/qtgmc.py
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
def basic(
    self,
    *,
    bobber: BobberLike = _NNEDI3_DEFAULT,
    tr: int = 2,
    thsad: int | tuple[int, int] = 640,
    thsad2: int | tuple[int, int] | None = None,
    noise_restore: float = 0,
    mask_args: QTGMCArgs.Mask | None = None,
    degrain_args: QTGMCArgs.Degrain | None = None,
    mask_shimmer_args: QTGMCArgs.MaskShimmer | None = None,
) -> Self:
    """
    Configures parameters for the basic stage.

    Creates the basic output of the core algorithm. Intended to eliminate bob shimmer.

    High-level overview:
        - High-quality bobbed clip generation: Begins with high-quality spatial interpolation to produce the bobbed
            clip, which inherently contains severe temporal instability known as bob shimmer.
        - ([QTempGaussMC.repair][vsdeinterlace.QTempGaussMC.repair]) Motion SAD masking: Generates a motion-vector
            SAD mask to blend [QTempGaussMC.denoise][vsdeinterlace.QTempGaussMC.denoise] output over the bobbed
            clip, protecting static/low-motion detail.
        - Motion-compensated temporal binomial smoothing: Applies a motion-compensated temporal binomial blur to
            smooth the bobbed clip, removing the shimmer while avoiding ghosting artifacts.
        - Shimmer masking: Uses a specialized masking process to eliminate the introduced blurring while retaining
            the shimmer removal.
        - Additional refinements: Passes the temporally smoothed clip through optional fine-tuning processes:
            - [QTempGaussMC.source_match][vsdeinterlace.QTempGaussMC.source_match]
            - [QTempGaussMC.lossless][vsdeinterlace.QTempGaussMC.lossless]
            - [QTempGaussMC.sharpen][vsdeinterlace.QTempGaussMC.sharpen]
            - [QTempGaussMC.back_blend][vsdeinterlace.QTempGaussMC.back_blend]
            - [QTempGaussMC.sharpen_limit][vsdeinterlace.QTempGaussMC.sharpen_limit]

        - Noise restoration: Optionally restores noise previously extracted by
            [QTempGaussMC.denoise][vsdeinterlace.QTempGaussMC.denoise] at the end of this stage.

    Args:
        bobber: Bobber to use for spatial interpolation. Defaults to NNEDI3(nsize=1).
        tr: Temporal radius of the motion-compensated binomial blur. Larger values reduce more shimmer but can
            introduce blurring and ghosting. Defaults to 2.
        thsad: SAD threshold of the motion-compensated binomial blur. Larger values reduce more shimmer but can
            introduce blurring and ghosting.

            - First value: Luma SAD threshold.
            - Second value: Chroma SAD threshold.

            A single value applies to both luma and chroma. Defaults to 640.
        thsad2: SAD threshold of the motion-compensated linear blur for the furthest references. Larger values clean
            more artifacts but can introduce blurring and ghosting.

            - First value: Luma SAD threshold.
            - Second value: Chroma SAD threshold.

            A single value applies to both luma and chroma. Defaults to None.
        noise_restore: Amount of noise to restore after this stage. Used to retain stable noise. Defaults to 0.
        mask_args: Additional arguments passed to [MVTools.mask][vsdenoise.mvtools.mvtools.MVTools.mask]. Only used
            for [QTempGaussMC.repair][vsdeinterlace.QTempGaussMC.repair]. Defaults to {"ml": 10}.
        degrain_args: Additional arguments passed to the internal `_binomial_degrain` call. Defaults to None.
        mask_shimmer_args: Additional arguments passed to [mask_shimmer][vsdeinterlace.mask_shimmer]. Defaults
            to {"erosion_distance": 0}.
    """

    self.basic_bobber = (
        deepcopy(bobber) if isinstance(bobber, Bobber) else Bobber.ensure_obj(bobber, self.__class__)
    )
    self.basic_tr = tr
    self.basic_thsad = thsad
    self.basic_thsad2 = thsad2
    self.basic_noise_restore = noise_restore
    self.basic_mask_args = QTGMCArgs.Mask(ml=10) | (mask_args or {})
    self.basic_degrain_args = fallback(degrain_args, QTGMCArgs.Degrain())
    self.basic_mask_shimmer_args = QTGMCArgs.MaskShimmer(erosion_distance=0) | (mask_shimmer_args or {})

    return self

bob

bob(
    clip: VideoNode,
    tff: FieldBasedLike | bool | None = None,
    return_graph: Literal[False] = False,
) -> VideoNode
bob(
    clip: VideoNode,
    tff: FieldBasedLike | bool | None = None,
    *,
    return_graph: Literal[True],
) -> tuple[VideoNode, QTGMCGraph]
bob(
    clip: VideoNode,
    tff: FieldBasedLike | bool | None,
    return_graph: Literal[True],
) -> tuple[VideoNode, QTGMCGraph]
bob(
    clip: VideoNode,
    tff: FieldBasedLike | bool | None = None,
    return_graph: bool = ...,
) -> VideoNode | tuple[VideoNode, QTGMCGraph]
bob(
    clip: VideoNode,
    tff: FieldBasedLike | bool | None = None,
    return_graph: bool = False,
) -> VideoNode | tuple[VideoNode, QTGMCGraph]

Bob interlaced input.

Interpolates missing fields to reconstruct progressive frames. QTempGaussMC.motion_blur fps_divisor is ignored.

Parameters:

  • clip

    (VideoNode) –

    Clip to process.

  • tff

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

    Field order (top-field-first). If None, inferred from the clip. Defaults to None.

  • return_graph

    (bool, default: False ) –

    Whether to return the QTGMCGraph object. It can be used for inspecting the output or QTGMCGraph.mv can be reused for other motion-compensated processing. Defaults to False.

Returns:

  • VideoNode | tuple[VideoNode, QTGMCGraph]

    The bobbed clip, or a (clip, graph) pair containing the bobbed clip and its QTGMCGraph object if

  • VideoNode | tuple[VideoNode, QTGMCGraph]

    return_graph is True.

Source code in vsdeinterlace/qtgmc.py
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
def bob(
    self, clip: vs.VideoNode, tff: FieldBasedLike | bool | None = None, return_graph: bool = False
) -> vs.VideoNode | tuple[vs.VideoNode, QTGMCGraph]:
    """
    Bob interlaced input.

    Interpolates missing fields to reconstruct progressive frames.
    [QTempGaussMC.motion_blur][vsdeinterlace.QTempGaussMC.motion_blur] `fps_divisor` is ignored.

    Args:
        clip: Clip to process.
        tff: Field order (top-field-first). If `None`, inferred from the clip. Defaults to None.
        return_graph: Whether to return the [QTGMCGraph][vsdeinterlace.qtgmc.QTGMCGraph] object. It can be used for
            inspecting the output or [QTGMCGraph.mv][vsdeinterlace.qtgmc.QTGMCGraph.mv] can be reused for other
            motion-compensated processing. Defaults to False.

    Returns:
        The bobbed clip, or a (clip, graph) pair containing the bobbed clip and its `QTGMCGraph` object if
        `return_graph` is `True`.
    """

    run = QTGMCGraph.Mode.BOB(clip, tff, self, self.bob)

    if return_graph:
        return run.motion_blur, run.freeze()

    return run.motion_blur

deinterlace

deinterlace(
    clip: VideoNode,
    tff: FieldBasedLike | bool | None = None,
    return_graph: Literal[False] = False,
) -> VideoNode
deinterlace(
    clip: VideoNode,
    tff: FieldBasedLike | bool | None = None,
    *,
    return_graph: Literal[True],
) -> tuple[VideoNode, QTGMCGraph]
deinterlace(
    clip: VideoNode,
    tff: FieldBasedLike | bool | None,
    return_graph: Literal[True],
) -> tuple[VideoNode, QTGMCGraph]
deinterlace(
    clip: VideoNode,
    tff: FieldBasedLike | bool | None = None,
    return_graph: bool = ...,
) -> VideoNode | tuple[VideoNode, QTGMCGraph]
deinterlace(
    clip: VideoNode,
    tff: FieldBasedLike | bool | None = None,
    return_graph: bool = False,
) -> VideoNode | tuple[VideoNode, QTGMCGraph]

Deinterlace interlaced input.

Interpolates missing fields to reconstruct progressive frames. QTempGaussMC.motion_blur fps_divisor is respected.

Parameters:

  • clip

    (VideoNode) –

    Clip to process.

  • tff

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

    Field order (top-field-first). If None, inferred from the clip. Defaults to None.

  • return_graph

    (bool, default: False ) –

    Whether to return the QTGMCGraph object. It can be used for inspecting the output or QTGMCGraph.mv can be reused for other motion-compensated processing. Defaults to False.

Returns:

  • VideoNode | tuple[VideoNode, QTGMCGraph]

    The deinterlaced clip, or a (clip, graph) pair containing the deinterlaced clip and its QTGMCGraph

  • VideoNode | tuple[VideoNode, QTGMCGraph]

    object if return_graph is True.

Source code in vsdeinterlace/qtgmc.py
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
def deinterlace(
    self, clip: vs.VideoNode, tff: FieldBasedLike | bool | None = None, return_graph: bool = False
) -> vs.VideoNode | tuple[vs.VideoNode, QTGMCGraph]:
    """
    Deinterlace interlaced input.

    Interpolates missing fields to reconstruct progressive frames.
    [QTempGaussMC.motion_blur][vsdeinterlace.QTempGaussMC.motion_blur] `fps_divisor` is respected.

    Args:
        clip: Clip to process.
        tff: Field order (top-field-first). If `None`, inferred from the clip. Defaults to None.
        return_graph: Whether to return the [QTGMCGraph][vsdeinterlace.qtgmc.QTGMCGraph] object. It can be used for
            inspecting the output or [QTGMCGraph.mv][vsdeinterlace.qtgmc.QTGMCGraph.mv] can be reused for other
            motion-compensated processing. Defaults to False.

    Returns:
        The deinterlaced clip, or a (clip, graph) pair containing the deinterlaced clip and its `QTGMCGraph`
        object if `return_graph` is `True`.
    """

    run = QTGMCGraph.Mode.DEINTERLACE(clip, tff, self, self.deinterlace)

    if return_graph:
        return run.motion_blur, run.freeze()

    return run.motion_blur

denoise

denoise(
    *,
    func: DFTTest | _DenoiseFuncTr = _DFTTEST_DEFAULT,
    tr: int = 1,
    mc_denoise: bool = True,
    full_denoise: bool = False,
    deint: NoiseDeintMode = GENERATE,
    stabilize: float | Literal[False] = 0.4,
    func_comp_args: Compensate | None = None,
    stabilize_comp_args: Compensate | None = None,
    mode: NoiseProcessMode | None = None,
) -> Self

Configures parameters for the denoise stage.

Determines how to handle noise in the source, including extraction, removal, deinterlacing, and stabilization.

High-level overview
  • Noise handling approaches:

    • Complete denoising: Denoise the source clip entirely, run the denoised clip through the standard deinterlacing routine, and optionally restore a portion of the original noise later in the algorithm.
    • Noise extraction: Denoise the source clip solely to estimate the noise profile, run the source clip through the standard deinterlacing routine (which naturally reduces noise), and optionally restore a portion of the original noise later in the algorithm.
  • Motion-compensated denoising: Motion compensation can optionally be used during the denoising to improve the accuracy of the noise estimation.

  • (QTempGaussMC.deinterlace) Interlaced noise processing: Because the extracted noise is inherently interlaced and standard processing would eliminate it, three alternative methods (QTempGaussMC.NoiseDeintMode) are available to process it separately.
  • Noise stabilization: The extracted noise can optionally be stabilized at the end of processing using a blend of the maximum variance determined through motion compensation and the average of that maximum variance and the extracted noise.

Parameters:

  • func

    (DFTTest | _DenoiseFuncTr, default: _DFTTEST_DEFAULT ) –

    Denoising function to use. Defaults to DFTTest(sigma=8).

  • tr

    (int, default: 1 ) –

    Temporal radius of the denoising function and its motion compensation. Larger values remove/separate more noise. Defaults to 1.

  • mc_denoise

    (bool, default: True ) –

    Whether to motion-compensate the denoiser being used. Provides more accurate denoising/noise extraction when using a non-motion-compensated temporal denoiser. Defaults to True.

  • full_denoise

    (bool, default: False ) –

    Whether the denoised output will be directly used in all subsequent processing. If False, the denoising is only for noise extraction. Defaults to False.

  • deint

    (NoiseDeintMode, default: GENERATE ) –

    How to 'deinterlace' noise taken from an interlaced source. Defaults to NoiseDeintMode.GENERATE.

  • stabilize

    (float | Literal[False], default: 0.4 ) –

    Weight used when blending max noise variance with averaged noise. Higher values give more weight to the averaged noise. False disables stabilization. Defaults to 0.4.

  • func_comp_args

    (Compensate | None, default: None ) –

    Additional arguments passed to MVTools.compensate for denoising. Defaults to None.

  • stabilize_comp_args

    (Compensate | None, default: None ) –

    Additional arguments passed to MVTools.compensate for stabilization. Defaults to None.

Source code in vsdeinterlace/qtgmc.py
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
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
def denoise(
    self,
    *,
    func: DFTTest | _DenoiseFuncTr = _DFTTEST_DEFAULT,
    tr: int = 1,
    mc_denoise: bool = True,
    full_denoise: bool = False,
    deint: NoiseDeintMode = NoiseDeintMode.GENERATE,
    stabilize: float | Literal[False] = 0.4,
    func_comp_args: QTGMCArgs.Compensate | None = None,
    stabilize_comp_args: QTGMCArgs.Compensate | None = None,
    mode: NoiseProcessMode | None = None,
) -> Self:
    """
    Configures parameters for the denoise stage.

    Determines how to handle noise in the source, including extraction, removal, deinterlacing, and stabilization.

    High-level overview:
        - Noise handling approaches:
            - Complete denoising: Denoise the source clip entirely, run the denoised clip through the standard
                deinterlacing routine, and optionally restore a portion of the original noise later in the
                algorithm.
            - Noise extraction: Denoise the source clip solely to estimate the noise profile, run the source clip
                through the standard deinterlacing routine (which naturally reduces noise), and optionally restore a
                portion of the original noise later in the algorithm.

        - Motion-compensated denoising: Motion compensation can optionally be used during the denoising to improve
            the accuracy of the noise estimation.
        - ([QTempGaussMC.deinterlace][vsdeinterlace.QTempGaussMC.deinterlace]) Interlaced noise processing: Because
            the extracted noise is inherently interlaced and standard processing would eliminate it, three
            alternative methods ([QTempGaussMC.NoiseDeintMode][vsdeinterlace.QTempGaussMC.NoiseDeintMode]) are
            available to process it separately.
        - Noise stabilization: The extracted noise can optionally be stabilized at the end of processing using a
            blend of the maximum variance determined through motion compensation and the average of that maximum
            variance and the extracted noise.

    Args:
        func: Denoising function to use. Defaults to DFTTest(sigma=8).
        tr: Temporal radius of the denoising function and its motion compensation. Larger values remove/separate
            more noise. Defaults to 1.
        mc_denoise: Whether to motion-compensate the denoiser being used. Provides more accurate denoising/noise
            extraction when using a non-motion-compensated temporal denoiser. Defaults to True.
        full_denoise: Whether the denoised output will be directly used in all subsequent processing. If `False`,
            the denoising is only for noise extraction. Defaults to False.
        deint: How to 'deinterlace' noise taken from an interlaced source. Defaults to NoiseDeintMode.GENERATE.
        stabilize: Weight used when blending max noise variance with averaged noise. Higher values give more
            weight to the averaged noise. `False` disables stabilization. Defaults to 0.4.
        func_comp_args: Additional arguments passed to
            [MVTools.compensate][vsdenoise.mvtools.mvtools.MVTools.compensate] for denoising. Defaults to None.
        stabilize_comp_args: Additional arguments passed to
            [MVTools.compensate][vsdenoise.mvtools.mvtools.MVTools.compensate] for stabilization. Defaults to
            None.
    """

    self.denoise_func = func.denoise if isinstance(func, DFTTest) else func
    self.denoise_tr = tr
    self.denoise_mc_denoise = mc_denoise
    self.denoise_full_denoise = full_denoise
    self.denoise_deint = deint
    self.denoise_stabilize = stabilize
    self.denoise_func_comp_args = fallback(func_comp_args, QTGMCArgs.Compensate())
    self.denoise_stabilize_comp_args = fallback(stabilize_comp_args, QTGMCArgs.Compensate())

    if mode is not None:  # TODO: remove
        self.denoise_full_denoise = bool(mode.value)

    return self

deshimmer

deshimmer(clip: VideoNode, return_graph: Literal[False] = False) -> VideoNode
deshimmer(
    clip: VideoNode, return_graph: Literal[True]
) -> tuple[VideoNode, QTGMCGraph]
deshimmer(
    clip: VideoNode, return_graph: bool = ...
) -> VideoNode | tuple[VideoNode, QTGMCGraph]
deshimmer(
    clip: VideoNode, return_graph: bool = False
) -> VideoNode | tuple[VideoNode, QTGMCGraph]

Deshimmer progressive input.

Removes horizontal shimmering artifacts from progressive sources.

Parameters:

  • clip

    (VideoNode) –

    Clip to process.

  • return_graph

    (bool, default: False ) –

    Whether to return the QTGMCGraph object. It can be used for inspecting the output or QTGMCGraph.mv can be reused for other motion-compensated processing. Defaults to False.

Returns:

  • VideoNode | tuple[VideoNode, QTGMCGraph]

    The deshimmered clip, or a (clip, graph) pair containing the deshimmered clip and its QTGMCGraph object if return_graph is True.

Source code in vsdeinterlace/qtgmc.py
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
def deshimmer(
    self, clip: vs.VideoNode, return_graph: bool = False
) -> vs.VideoNode | tuple[vs.VideoNode, QTGMCGraph]:
    """
    Deshimmer progressive input.

    Removes horizontal shimmering artifacts from progressive sources.

    Args:
        clip: Clip to process.
        return_graph: Whether to return the [QTGMCGraph][vsdeinterlace.qtgmc.QTGMCGraph] object. It can be used for
            inspecting the output or [QTGMCGraph.mv][vsdeinterlace.qtgmc.QTGMCGraph.mv] can be reused for other
            motion-compensated processing. Defaults to False.

    Returns:
        The deshimmered clip, or a (clip, graph) pair containing the deshimmered clip and its `QTGMCGraph`
            object if `return_graph` is `True`.
    """

    run = QTGMCGraph.Mode.DESHIMMER(clip, FieldBased.PROGRESSIVE, self, self.deshimmer)

    if return_graph:
        return run.motion_blur, run.freeze()

    return run.motion_blur

final

final(
    *,
    tr: int = 1,
    thsad: int | tuple[int, int] = 256,
    thsad2: int | tuple[int, int] | None = None,
    noise_restore: float = 0,
    degrain_args: Degrain | None = None,
    mask_shimmer_args: MaskShimmer | None = None,
) -> Self

Configures parameters for the final stage.

Creates the final output of the core algorithm. Intended to eliminate residual artifacts.

High-level overview
  • Motion-compensated temporal linear smoothing: Applies a motion-compensated temporal linear blur to smooth the output of QTempGaussMC.basic, cleaning any residual artifacts.
  • Shimmer masking: Uses a specialized masking process to eliminate the introduced blurring while retaining the artifact removal.
  • Additional refinements: Passes the temporally smoothed clip through optional fine-tuning processes:

  • Noise restoration: Optionally restores noise previously extracted by QTempGaussMC.denoise at the end of this stage.

Parameters:

  • tr

    (int, default: 1 ) –

    Temporal radius of the motion-compensated linear blur. Larger values clean more artifacts but can introduce blurring and ghosting. Defaults to 1.

  • thsad

    (int | tuple[int, int], default: 256 ) –

    SAD threshold of the motion-compensated linear blur. Larger values clean more artifacts but can introduce blurring and ghosting.

    • First value: Luma SAD threshold.
    • Second value: Chroma SAD threshold.

    A single value applies to both luma and chroma. Defaults to 256.

  • thsad2

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

    SAD threshold of the motion-compensated linear blur for the furthest references. Larger values clean more artifacts but can introduce blurring and ghosting.

    • First value: Luma SAD threshold.
    • Second value: Chroma SAD threshold.

    A single value applies to both luma and chroma. Defaults to None.

  • noise_restore

    (float, default: 0 ) –

    Amount of noise to restore after this stage. Used to retain any noise. Defaults to 0.

  • degrain_args

    (Degrain | None, default: None ) –

    Additional arguments passed to MVTools.degrain. Defaults to None.

  • mask_shimmer_args

    (MaskShimmer | None, default: None ) –

    Additional arguments passed to mask_shimmer. Defaults to None.

Source code in vsdeinterlace/qtgmc.py
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
def final(
    self,
    *,
    tr: int = 1,
    thsad: int | tuple[int, int] = 256,
    thsad2: int | tuple[int, int] | None = None,
    noise_restore: float = 0,
    degrain_args: QTGMCArgs.Degrain | None = None,
    mask_shimmer_args: QTGMCArgs.MaskShimmer | None = None,
) -> Self:
    """
    Configures parameters for the final stage.

    Creates the final output of the core algorithm. Intended to eliminate residual artifacts.

    High-level overview:
        - Motion-compensated temporal linear smoothing: Applies a motion-compensated temporal linear blur to smooth
            the output of [QTempGaussMC.basic][vsdeinterlace.QTempGaussMC.basic], cleaning any residual artifacts.
        - Shimmer masking: Uses a specialized masking process to eliminate the introduced blurring while retaining
            the artifact removal.
        - Additional refinements: Passes the temporally smoothed clip through optional fine-tuning processes:
            - [QTempGaussMC.sharpen_limit][vsdeinterlace.QTempGaussMC.sharpen_limit]
            - [QTempGaussMC.lossless][vsdeinterlace.QTempGaussMC.lossless]

        - Noise restoration: Optionally restores noise previously extracted by
            [QTempGaussMC.denoise][vsdeinterlace.QTempGaussMC.denoise] at the end of this stage.

    Args:
        tr: Temporal radius of the motion-compensated linear blur. Larger values clean more artifacts but can
            introduce blurring and ghosting. Defaults to 1.
        thsad: SAD threshold of the motion-compensated linear blur. Larger values clean more artifacts but can
            introduce blurring and ghosting.

            - First value: Luma SAD threshold.
            - Second value: Chroma SAD threshold.

            A single value applies to both luma and chroma. Defaults to 256.
        thsad2: SAD threshold of the motion-compensated linear blur for the furthest references. Larger values clean
            more artifacts but can introduce blurring and ghosting.

            - First value: Luma SAD threshold.
            - Second value: Chroma SAD threshold.

            A single value applies to both luma and chroma. Defaults to None.
        noise_restore: Amount of noise to restore after this stage. Used to retain any noise. Defaults to 0.
        degrain_args: Additional arguments passed to [MVTools.degrain][vsdenoise.mvtools.mvtools.MVTools.degrain].
            Defaults to None.
        mask_shimmer_args: Additional arguments passed to [mask_shimmer][vsdeinterlace.mask_shimmer]. Defaults
            to None.
    """

    self.final_tr = tr
    self.final_thsad = thsad
    self.final_thsad2 = thsad2
    self.final_noise_restore = noise_restore
    self.final_degrain_args = fallback(degrain_args, QTGMCArgs.Degrain())
    self.final_mask_shimmer_args = fallback(mask_shimmer_args, QTGMCArgs.MaskShimmer())

    return self

lossless

lossless(*, mode: LosslessMode = NONE, anti_comb: bool = True) -> Self

Configures parameters for lossless processing.

Creates higher-fidelity output by restoring the original fields.

High-level overview
  • Source field weaving: Weaves the original fields together with the newly smoothed fields to preserve the original lines, removing the original field alteration introduced by temporal blurring.
  • Residual combing reduction: Applies vertical median filtering to clean up residual combing caused by mismatches between the original fields and the processed fields.

Parameters:

  • mode

    (LosslessMode, default: NONE ) –

    When to put the original fields into the output. Defaults to LosslessMode.NONE.

  • anti_comb

    (bool, default: True ) –

    Whether to apply combing reduction post-processing. Defaults to True.

Source code in vsdeinterlace/qtgmc.py
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
def lossless(self, *, mode: LosslessMode = LosslessMode.NONE, anti_comb: bool = True) -> Self:
    """
    Configures parameters for lossless processing.

    Creates higher-fidelity output by restoring the original fields.

    High-level overview:
        - Source field weaving: Weaves the original fields together with the newly smoothed fields to preserve the
            original lines, removing the original field alteration introduced by temporal blurring.
        - Residual combing reduction: Applies vertical median filtering to clean up residual combing caused by
            mismatches between the original fields and the processed fields.

    Args:
        mode: When to put the original fields into the output. Defaults to LosslessMode.NONE.
        anti_comb: Whether to apply combing reduction post-processing. Defaults to True.
    """

    self.lossless_mode = mode
    self.lossless_anti_comb = anti_comb

    return self

motion_blur

motion_blur(
    *,
    shutter_angle: tuple[float, float] | Literal[False] = False,
    fps_divisor: int = 1,
    blur_args: Blur | None = None,
    mask_args: Mask | None = None,
) -> Self

Configures parameters for the motion blur stage.

Simulates realistic camera shutter blur to smooth playback motion, primarily when reducing output frame rate.

High-level overview
  • Shutter angle calculation: Computes the required blur intensity based on the estimated input shutter angle, the output shutter angle, and the frame rate divisor.
  • Motion-compensated blurring: Applies vector-based directional blur along motion vectors when the required blur amount is non-zero.
  • Motion-compensated masking: Generates a mask based on motion to selectively merge motion blur into the source while keeping static areas sharp.
  • Frame rate reduction: Optionally decimates frame rate (e.g., dropping every other frame for single-rate output) after motion blur application.

Parameters:

  • shutter_angle

    (tuple[float, float] | Literal[False], default: False ) –

    Source and output shutter angle. Motion blur is applied if they do not match.

    • First value: Source shutter angle.
    • Second value: Output shutter angle.

    False disables motion blur. Defaults to False.

  • fps_divisor

    (int, default: 1 ) –

    Factor by which to smoothly reduce frame rate. Defaults to 1.

  • blur_args

    (Blur | None, default: None ) –

    Additional arguments passed to MVTools.flow_blur. Defaults to None.

  • mask_args

    (Mask | None, default: None ) –

    Additional arguments passed to MVTools.mask. Defaults to {"ml": 4}.

Source code in vsdeinterlace/qtgmc.py
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
def motion_blur(
    self,
    *,
    shutter_angle: tuple[float, float] | Literal[False] = False,
    fps_divisor: int = 1,
    blur_args: QTGMCArgs.Blur | None = None,
    mask_args: QTGMCArgs.Mask | None = None,
) -> Self:
    """
    Configures parameters for the motion blur stage.

    Simulates realistic camera shutter blur to smooth playback motion, primarily when reducing output frame rate.

    High-level overview:
        - Shutter angle calculation: Computes the required blur intensity based on the estimated input shutter
            angle, the output shutter angle, and the frame rate divisor.
        - Motion-compensated blurring: Applies vector-based directional blur along motion vectors when the required
            blur amount is non-zero.
        - Motion-compensated masking: Generates a mask based on motion to selectively merge motion blur into the
            source while keeping static areas sharp.
        - Frame rate reduction: Optionally decimates frame rate (e.g., dropping every other frame for single-rate
            output) after motion blur application.

    Args:
        shutter_angle: Source and output shutter angle. Motion blur is applied if they do not match.

            - First value: Source shutter angle.
            - Second value: Output shutter angle.

            `False` disables motion blur. Defaults to False.
        fps_divisor: Factor by which to smoothly reduce frame rate. Defaults to 1.
        blur_args: Additional arguments passed to [MVTools.flow_blur][vsdenoise.mvtools.mvtools.MVTools.flow_blur].
            Defaults to None.
        mask_args: Additional arguments passed to [MVTools.mask][vsdenoise.mvtools.mvtools.MVTools.mask]. Defaults
            to {"ml": 4}.
    """

    self.motion_blur_shutter_angle = shutter_angle
    self.motion_blur_fps_divisor = fps_divisor
    self.motion_blur_blur_args = fallback(blur_args, QTGMCArgs.Blur())
    self.motion_blur_mask_args = QTGMCArgs.Mask(ml=4) | (mask_args or {})

    return self

prefilter

prefilter(
    *,
    tr: int = 2,
    sc_threshold: float = 0.1,
    strength: tuple[float, float] = (1.96, 0.9),
    limit: tuple[float, float, float] = (3, 7, 2),
    bias: float = 0.51,
    mask_shimmer_args: MaskShimmer | None = None,
    range_expansion_args: PrefilterToFullRange | None = None,
    postprocess: SearchPostProcess | None = None,
) -> Self

Configures parameters for the prefilter stage.

Prepares a suitable search clip to be provided for motion analysis.

High-level overview
  • (QTempGaussMC.deinterlace) Draft bobbed clip generation: Begins with simple spatial interpolation to produce the draft clip, which inherently contains severe temporal instability known as bob shimmer.
  • (QTempGaussMC.repair) Vertical spatial pre-filtering: Applies a vertical binomial blur to filter out residual vertical artifacts.
  • Temporal binomial blurring: Applies a temporal binomial blur to smooth the draft clip, removing the shimmer, which prevents MVTools from falsely latching onto the shimmer as motion (though this uncompensated blur introduces ghosting).
  • Shimmer masking: Uses a specialized masking process to eliminate the introduced ghosting while retaining the shimmer removal.
  • Gaussian blurring post-processing: Applies Gaussian blurring to lower high SAD values caused by sharp edges, ensuring edges are properly processed rather than skipped.
  • Edge detail restoration: Conservatively restores essential edge detail from the draft clip back into the blurred clip via a limiting process so MVTools retains the ability to track motion effectively.
  • Levels optimization: Applies level adjustments to brighten dark regions and enhance contrast, enabling MVTools to better track dark details, reducing downstream ghosting and blurring.

Parameters:

  • tr

    (int, default: 2 ) –

    Temporal radius of the binomial blur. Larger values reduce more shimmer but can introduce blurring and ghosting. Defaults to 2.

  • sc_threshold

    (float, default: 0.1 ) –

    Threshold for scene changes. Higher values are less sensitive. Defaults to 0.1.

  • strength

    (tuple[float, float], default: (1.96, 0.9) ) –

    Gaussian blur sigma and its blend weight.

    • First value: Gaussian blur sigma. Higher values result in more blurring.
    • Second value: Blend weight of the Gaussian blur. Higher values give more weight to the Gaussian-blurred clip.

    Defaults to (1.96, 0.9).

  • limit

    (tuple[float, float, float], default: (3, 7, 2) ) –

    Three-step limiting thresholds (8-bit scale) for the Gaussian blur post-processing:

    • First value: Maximum allowed delta between the temporally blurred clip and the draft clip. Smaller values clamp the draft clip closer to the temporally blurred clip.
    • Second value: Tolerance threshold for the allowed difference between the clamped clip and the Gaussian-blurred clip before hard clipping triggers. Larger values widen the allowed range for smooth blending before hard clipping is enforced.
    • Third value: Offset applied to the Gaussian-blurred clip when the second threshold is exceeded. Larger values allow a bigger delta from the Gaussian-blurred clip when clipped.

    Defaults to (3, 7, 2).

  • bias

    (float, default: 0.51 ) –

    Weight used when blending the Gaussian-blurred clip back with the limited clip. Higher values give more weight to the Gaussian-blurred clip. Defaults to 0.51.

  • mask_shimmer_args

    (MaskShimmer | None, default: None ) –

    Additional arguments passed to mask_shimmer. Defaults to None.

  • range_expansion_args

    (PrefilterToFullRange | None, default: None ) –

    Additional arguments passed to prefilter_to_full_range. Defaults to None.

Source code in vsdeinterlace/qtgmc.py
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
def prefilter(
    self,
    *,
    tr: int = 2,
    sc_threshold: float = 0.1,
    strength: tuple[float, float] = (1.96, 0.9),
    limit: tuple[float, float, float] = (3, 7, 2),
    bias: float = 0.51,
    mask_shimmer_args: QTGMCArgs.MaskShimmer | None = None,
    range_expansion_args: QTGMCArgs.PrefilterToFullRange | None = None,
    postprocess: SearchPostProcess | None = None,
) -> Self:
    """
    Configures parameters for the prefilter stage.

    Prepares a suitable search clip to be provided for motion analysis.

    High-level overview:
        - ([QTempGaussMC.deinterlace][vsdeinterlace.QTempGaussMC.deinterlace]) Draft bobbed clip generation:
            Begins with simple spatial interpolation to produce the draft clip, which inherently contains severe
            temporal instability known as bob shimmer.
        - ([QTempGaussMC.repair][vsdeinterlace.QTempGaussMC.repair]) Vertical spatial pre-filtering: Applies a
            vertical binomial blur to filter out residual vertical artifacts.
        - Temporal binomial blurring: Applies a temporal binomial blur to smooth the draft clip, removing the
            shimmer, which prevents [MVTools][vsdenoise.mvtools.mvtools.MVTools] from falsely latching onto the
            shimmer as motion (though this uncompensated blur introduces ghosting).
        - Shimmer masking: Uses a specialized masking process to eliminate the introduced ghosting while retaining
            the shimmer removal.
        - Gaussian blurring post-processing: Applies Gaussian blurring to lower high SAD values caused by sharp
            edges, ensuring edges are properly processed rather than skipped.
        - Edge detail restoration: Conservatively restores essential edge detail from the draft clip back into the
            blurred clip via a limiting process so [MVTools][vsdenoise.mvtools.mvtools.MVTools] retains the ability
            to track motion effectively.
        - Levels optimization:
            Applies level adjustments to brighten dark regions and enhance contrast, enabling
            [MVTools][vsdenoise.mvtools.mvtools.MVTools] to better track dark details, reducing downstream ghosting
            and blurring.

    Args:
        tr: Temporal radius of the binomial blur. Larger values reduce more shimmer but can introduce blurring and
            ghosting. Defaults to 2.
        sc_threshold: Threshold for scene changes. Higher values are less sensitive. Defaults to 0.1.
        strength: Gaussian blur sigma and its blend weight.

            - First value: Gaussian blur sigma. Higher values result in more blurring.
            - Second value: Blend weight of the Gaussian blur. Higher values give more weight to the
                Gaussian-blurred clip.

            Defaults to (1.96, 0.9).
        limit: Three-step limiting thresholds (8-bit scale) for the Gaussian blur post-processing:

               - First value: Maximum allowed delta between the temporally blurred clip and the draft clip. Smaller
                values clamp the draft clip closer to the temporally blurred clip.
               - Second value: Tolerance threshold for the allowed difference between the clamped clip and the
                Gaussian-blurred clip before hard clipping triggers. Larger values widen the allowed range for
                smooth blending before hard clipping is enforced.
               - Third value: Offset applied to the Gaussian-blurred clip when the second threshold is exceeded.
                Larger values allow a bigger delta from the Gaussian-blurred clip when clipped.

            Defaults to (3, 7, 2).
        bias: Weight used when blending the Gaussian-blurred clip back with the limited clip. Higher
            values give more weight to the Gaussian-blurred clip. Defaults to 0.51.
        mask_shimmer_args: Additional arguments passed to [mask_shimmer][vsdeinterlace.mask_shimmer]. Defaults
            to None.
        range_expansion_args: Additional arguments passed to
            [prefilter_to_full_range][vsdenoise.prefilters.prefilter_to_full_range]. Defaults to None.
    """

    self.prefilter_tr = tr
    self.prefilter_sc_threshold = sc_threshold
    self.prefilter_strength = strength
    self.prefilter_limit = limit
    self.prefilter_bias = bias
    self.prefilter_mask_shimmer_args = fallback(mask_shimmer_args, QTGMCArgs.MaskShimmer())
    self.prefilter_range_expansion_args = fallback(range_expansion_args, QTGMCArgs.PrefilterToFullRange())

    if postprocess is not None and not postprocess.value:  # TODO: remove
        self.prefilter_limit = (0, 0, 0)

    return self

repair

repair(
    clip: VideoNode,
    tff: FieldBasedLike | bool | None = None,
    return_graph: Literal[False] = False,
) -> VideoNode
repair(
    clip: VideoNode,
    tff: FieldBasedLike | bool | None = None,
    *,
    return_graph: Literal[True],
) -> tuple[VideoNode, QTGMCGraph]
repair(
    clip: VideoNode,
    tff: FieldBasedLike | bool | None,
    return_graph: Literal[True],
) -> tuple[VideoNode, QTGMCGraph]
repair(
    clip: VideoNode,
    tff: FieldBasedLike | bool | None = None,
    return_graph: bool = ...,
) -> VideoNode | tuple[VideoNode, QTGMCGraph]
repair(
    clip: VideoNode,
    tff: FieldBasedLike | bool | None = None,
    return_graph: bool = False,
) -> VideoNode | tuple[VideoNode, QTGMCGraph]

Repair badly deinterlaced input.

Drops half the fields to recreate an interlaced clip using the remaining ones.

Parameters:

  • clip

    (VideoNode) –

    Clip to process.

  • tff

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

    Field order (top-field-first). If None, inferred from the clip. Defaults to None.

  • return_graph

    (bool, default: False ) –

    Whether to return the QTGMCGraph object. It can be used for inspecting the output or QTGMCGraph.mv can be reused for other motion-compensated processing. Defaults to False.

Returns:

  • VideoNode | tuple[VideoNode, QTGMCGraph]

    The repaired clip, or a (clip, graph) pair containing the repaired clip and its QTGMCGraph object if

  • VideoNode | tuple[VideoNode, QTGMCGraph]

    return_graph is True.

Source code in vsdeinterlace/qtgmc.py
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
def repair(
    self, clip: vs.VideoNode, tff: FieldBasedLike | bool | None = None, return_graph: bool = False
) -> vs.VideoNode | tuple[vs.VideoNode, QTGMCGraph]:
    """
    Repair badly deinterlaced input.

    Drops half the fields to recreate an interlaced clip using the remaining ones.

    Args:
        clip: Clip to process.
        tff: Field order (top-field-first). If `None`, inferred from the clip. Defaults to None.
        return_graph: Whether to return the [QTGMCGraph][vsdeinterlace.qtgmc.QTGMCGraph] object. It can be used for
            inspecting the output or [QTGMCGraph.mv][vsdeinterlace.qtgmc.QTGMCGraph.mv] can be reused for other
            motion-compensated processing. Defaults to False.

    Returns:
        The repaired clip, or a (clip, graph) pair containing the repaired clip and its `QTGMCGraph` object if
        `return_graph` is `True`.
    """

    run = QTGMCGraph.Mode.REPAIR(clip, tff, self, self.repair)

    if return_graph:
        return run.motion_blur, run.freeze()

    return run.motion_blur

sharpen

sharpen(
    *,
    strength: float | None = None,
    offset: float | tuple[float, float] | Literal[False] = 1,
    thin: float = 0,
    mode: SharpenMode | None = None,
) -> Self

Configures parameters for sharpening.

Re-sharpens the output after temporal smoothing is performed.

High-level overview
  • Pre-blur range limiting: Calculates the local vertical average and offsets it prior to applying the blur used for unsharpening to increase vertical sharpening while reducing overshoot/undershoot.
  • Unsharpening: Applies unsharpening onto the temporally smoothed clip to restore image sharpness.
  • Horizontal edge thinning: Optionally thins horizontal edges that have been widened due to interpolation into neighboring field lines.

Parameters:

  • strength

    (float | None, default: None ) –

    Sharpening strength. Higher values result in more sharpening. Defaults to 1 when QTempGaussMC.source_match iterations is 0, and 0 otherwise.

  • offset

    (float | tuple[float, float] | Literal[False], default: 1 ) –

    Shifts the unsharpen blur source to the vertical min/max average ± this value (8-bit scale). Smaller values result in more vertical sharpening.

    • First value: Dark offset.
    • Second value: Bright offset.

    A single value applies to both dark and bright offsets. False disables range limiting. Defaults to 1.

  • thin

    (float, default: 0 ) –

    How much to thin down horizontal edges. Higher values result in more thinning. Defaults to 0.

Source code in vsdeinterlace/qtgmc.py
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
def sharpen(
    self,
    *,
    strength: float | None = None,
    offset: float | tuple[float, float] | Literal[False] = 1,
    thin: float = 0,
    mode: SharpenMode | None = None,
) -> Self:
    """
    Configures parameters for sharpening.

    Re-sharpens the output after temporal smoothing is performed.

    High-level overview:
        - Pre-blur range limiting: Calculates the local vertical average and offsets it prior to applying the blur
            used for unsharpening to increase vertical sharpening while reducing overshoot/undershoot.
        - Unsharpening: Applies unsharpening onto the temporally smoothed clip to restore image sharpness.
        - Horizontal edge thinning: Optionally thins horizontal edges that have been widened due to interpolation
            into neighboring field lines.

    Args:
        strength: Sharpening strength. Higher values result in more sharpening. Defaults to 1 when
            [QTempGaussMC.source_match][vsdeinterlace.QTempGaussMC.source_match] `iterations` is `0`, and 0
            otherwise.
        offset: Shifts the unsharpen blur source to the vertical min/max average ± this value (8-bit scale). Smaller
            values result in more vertical sharpening.

            - First value: Dark offset.
            - Second value: Bright offset.

            A single value applies to both dark and bright offsets. `False` disables range limiting. Defaults to 1.
        thin: How much to thin down horizontal edges. Higher values result in more thinning. Defaults to 0.
    """

    self.sharpen_strength = strength
    self.sharpen_offset = offset is not False and normalize_seq(offset, 2)
    # Premultiply thin strength by the inverse L2 norm of the binomial blurs used in the algorithm.
    # After multiplication, thin = 1.0 means edges found by median filtering are merged at full strength.
    self.sharpen_thin = thin * 32 / sqrt(105)

    if mode is not None and not mode.value:  # TODO: remove
        self.sharpen_offset = False

    return self

sharpen_limit

sharpen_limit(
    *,
    mode: SharpenLimitMode | None = None,
    radius: int = 1,
    clamp: float | tuple[float, float] = 0,
    comp_args: Compensate | None = None,
) -> Self

Configures parameters for sharpness limiting.

Limits the effect of QTempGaussMC.sharpen to reduce oversharpening artifacts.

High-level overview
  • Sharpness limiting approaches:
    • Spatial limiting: Clamps the sharpened clip's pixel values to the local spatial minimum and maximum bounds of the bobbed clip.
    • Motion-compensated temporal limiting: Clamps the sharpened clip using motion-compensated reference frames from the bobbed clip.

Parameters:

  • mode

    (SharpenLimitMode | None, default: None ) –

    How and when to apply limiting to QTempGaussMC.sharpen. Defaults to SharpenLimitMode.TEMPORAL_PRESMOOTH when QTempGaussMC.source_match iterations is 0 and SharpenLimitMode.NONE otherwise.

  • radius

    (int, default: 1 ) –

    Radius of the sharpness limiting. Larger values allow more sharpening. Defaults to 1.

  • clamp

    (float | tuple[float, float], default: 0 ) –

    How much undershoot/overshoot to allow (8-bit scale). Larger values result in less limiting.

    • First value: Undershoot to allow.
    • Second value: Overshoot to allow.

    A single value applies to both undershoot and overshoot. Defaults to 0.

  • comp_args

    (Compensate | None, default: None ) –

    Additional arguments passed to MVTools.compensate for temporal limiting. Defaults to None.

Source code in vsdeinterlace/qtgmc.py
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
def sharpen_limit(
    self,
    *,
    mode: SharpenLimitMode | None = None,
    radius: int = 1,
    clamp: float | tuple[float, float] = 0,
    comp_args: QTGMCArgs.Compensate | None = None,
) -> Self:
    """
    Configures parameters for sharpness limiting.

    Limits the effect of [QTempGaussMC.sharpen][vsdeinterlace.QTempGaussMC.sharpen] to reduce oversharpening
    artifacts.

    High-level overview:
        - Sharpness limiting approaches:
            - Spatial limiting: Clamps the sharpened clip's pixel values to the local spatial minimum and maximum
                bounds of the bobbed clip.
            - Motion-compensated temporal limiting: Clamps the sharpened clip using motion-compensated reference
                frames from the bobbed clip.

    Args:
        mode: How and when to apply limiting to [QTempGaussMC.sharpen][vsdeinterlace.QTempGaussMC.sharpen]. Defaults
            to SharpenLimitMode.TEMPORAL_PRESMOOTH when
            [QTempGaussMC.source_match][vsdeinterlace.QTempGaussMC.source_match] `iterations` is `0` and
            SharpenLimitMode.NONE otherwise.
        radius: Radius of the sharpness limiting. Larger values allow more sharpening. Defaults to 1.
        clamp: How much undershoot/overshoot to allow (8-bit scale). Larger values result in less limiting.

            - First value: Undershoot to allow.
            - Second value: Overshoot to allow.

            A single value applies to both undershoot and overshoot. Defaults to 0.
        comp_args: Additional arguments passed to [MVTools.compensate][vsdenoise.mvtools.mvtools.MVTools.compensate]
            for temporal limiting. Defaults to None.
    """

    self.sharpen_limit_mode = mode
    self.sharpen_limit_radius = radius
    self.sharpen_limit_clamp = normalize_seq(clamp, 2)
    self.sharpen_limit_comp_args = fallback(comp_args, QTGMCArgs.Compensate())

    return self

source_match

source_match(
    *,
    iterations: Literal[0, 1, 2, 3] = 0,
    similarity: float = 0.5,
    bobber: BobberLike | None = None,
    tr: int = 1,
    enhance: float = 0.5,
    degrain_args: Degrain | None = None,
    mode: SourceMatchMode | None = None,
) -> Self

Configures parameters for source match processing.

Creates higher-fidelity output with extra processing; acts as an alternative method for sharpness restoration.

High-level overview
  • Error-adjusted source matching: Computes a weighted error-correction factor based on temporal radius and similarity, adjusting the input clip to compensate for the upcoming blur before re-interpolating and applying smoothing.
  • Detail enhancement: Optionally applies unsharpening to the result when enhance is used.
  • Residual refinement pass: For multiple iterations, isolates the difference between the original input and the current matched clip, interpolates and smooths this residual error (applying an additional error-adjustment pass if iterations > 2), and merges it back to restore fine detail missed during the initial pass.
Note
  • When source matching is used:

Parameters:

  • iterations

    (Literal[0, 1, 2, 3], default: 0 ) –

    Number of source match iterations to perform. Higher values are slower and more accurate. Using 2 or 3 iterations restores almost exact source detail but is sensitive to noise and introduces occasional aliasing (to a lesser extent for 3). Requires QTempGaussMC.basic tr > 0 Defaults to 0.

  • similarity

    (float, default: 0.5 ) –

    Temporal similarity of the error from frame to frame. Lower values make the result sharper. Defaults to 0.5.

  • bobber

    (BobberLike | None, default: None ) –

    Bobber to use for refined spatial interpolation. Only used for iterations > 1. Defaults to QTempGaussMC.basic bobber.

  • tr

    (int, default: 1 ) –

    Temporal radius of the refinement motion-compensated binomial blur. Larger values reduce more shimmer but can introduce blurring and ghosting. Only used for iterations > 1. Defaults to 1.

  • enhance

    (float, default: 0.5 ) –

    Enhances detail found by iterations > 1. Higher values exaggerate detail more. Defaults to 0.5.

  • degrain_args

    (Degrain | None, default: None ) –

    Additional arguments passed to the internal _binomial_degrain call. Defaults to None.

Source code in vsdeinterlace/qtgmc.py
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
def source_match(
    self,
    *,
    iterations: Literal[0, 1, 2, 3] = 0,
    similarity: float = 0.5,
    bobber: BobberLike | None = None,
    tr: int = 1,
    enhance: float = 0.5,
    degrain_args: QTGMCArgs.Degrain | None = None,
    mode: SourceMatchMode | None = None,
) -> Self:
    """
    Configures parameters for source match processing.

    Creates higher-fidelity output with extra processing; acts as an alternative method for sharpness restoration.

    High-level overview:
        - Error-adjusted source matching: Computes a weighted error-correction factor based on temporal radius and
            similarity, adjusting the input clip to compensate for the upcoming blur before re-interpolating and
            applying smoothing.
        - Detail enhancement: Optionally applies unsharpening to the result when `enhance` is used.
        - Residual refinement pass: For multiple iterations, isolates the difference between the original input and
            the current matched clip, interpolates and smooths this residual error (applying an additional
            error-adjustment pass if `iterations` > `2`), and merges it back to restore fine detail missed during
            the initial pass.

    Note:
        - When source matching is used:
            - [QTempGaussMC.sharpen][vsdeinterlace.QTempGaussMC.sharpen] is disabled by default, as source matching
                acts as an alternative form of sharpness restoration.
            - [QTempGaussMC.sharpen_limit][vsdeinterlace.QTempGaussMC.sharpen_limit] is disabled by default, as it
                reduces the accuracy of source matching.

    Args:
        iterations: Number of source match iterations to perform. Higher values are slower and more accurate. Using
            `2` or `3` iterations restores almost exact source detail but is sensitive to noise and introduces
            occasional aliasing (to a lesser extent for `3`). Requires
            [QTempGaussMC.basic][vsdeinterlace.QTempGaussMC.basic] `tr` > `0` Defaults to 0.
        similarity: Temporal similarity of the error from frame to frame. Lower values make the result sharper.
            Defaults to 0.5.
        bobber: Bobber to use for refined spatial interpolation. Only used for `iterations` > `1`. Defaults to
            [QTempGaussMC.basic][vsdeinterlace.QTempGaussMC.basic] `bobber`.
        tr: Temporal radius of the refinement motion-compensated binomial blur. Larger values reduce more shimmer
            but can introduce blurring and ghosting. Only used for `iterations` > `1`. Defaults to 1.
        enhance: Enhances detail found by `iterations` > `1`. Higher values exaggerate detail more. Defaults to 0.5.
        degrain_args: Additional arguments passed to the internal `_binomial_degrain` call. Defaults to None.
    """

    self.source_match_iterations = iterations
    self.source_match_similarity = similarity
    self.source_match_bobber = bobber
    self.source_match_tr = tr
    self.source_match_enhance = enhance
    self.source_match_degrain_args = fallback(degrain_args, QTGMCArgs.Degrain())

    if mode is not None:  # TODO: remove
        self.source_match_iterations = mode.value  # type: ignore

    return self

mask_shimmer

mask_shimmer(
    flt: VideoNode,
    src: VideoNode,
    erosion_distance: int = 4,
    over_dilation: int = 0,
    func: FuncExcept | None = None,
) -> VideoNode

Filters out differences unrelated to bob shimmer by isolating thin horizontal areas.

High-level overview
  • Vertical morphological analysis: Extracts the difference between source and filtered clips, running vertical opening and closing operations to collapse thin bob shimmer while leaving large motion artifacts intact.

Parameters:

  • flt

    (VideoNode) –

    Filtered clip to perform masking on.

  • src

    (VideoNode) –

    Source clip to restore from.

  • erosion_distance

    (int, default: 4 ) –

    Vertical radius for shimmer detection. Larger values capture more spread-out artifacts on soft sources. Defaults to 4.

  • over_dilation

    (int, default: 0 ) –

    Extra dilation passes to restore beyond the detected lines. Larger values restore more beyond the mask boundary. Defaults to 0.

  • func

    (FuncExcept | None, default: None ) –

    Function returned for custom error handling. This should only be set by VS package developers. Defaults to None.

Returns:

  • VideoNode

    Clip with only bob shimmer fixes kept.

Source code in vsdeinterlace/qtgmc.py
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
def mask_shimmer(
    flt: vs.VideoNode,
    src: vs.VideoNode,
    erosion_distance: int = 4,
    over_dilation: int = 0,
    func: FuncExcept | None = None,
) -> vs.VideoNode:
    """
    Filters out differences unrelated to bob shimmer by isolating thin horizontal areas.

    High-level overview:
        - Vertical morphological analysis: Extracts the difference between source and filtered clips, running
            vertical opening and closing operations to collapse thin bob shimmer while leaving large motion
            artifacts intact.

    Args:
        flt: Filtered clip to perform masking on.
        src: Source clip to restore from.
        erosion_distance: Vertical radius for shimmer detection. Larger values capture more spread-out artifacts on soft
            sources. Defaults to 4.
        over_dilation: Extra dilation passes to restore beyond the detected lines. Larger values restore more beyond the
            mask boundary. Defaults to 0.
        func: Function returned for custom error handling. This should only be set by VS package developers. Defaults to
            None.

    Returns:
        Clip with only bob shimmer fixes kept.
    """
    func = func or mask_shimmer

    if not erosion_distance:
        return flt

    ed1 = 1 + erosion_distance // 3
    ed2 = (erosion_distance + 4) // 3
    ed_res = erosion_distance % 3
    od, od_res = divmod(over_dilation, 3)

    ops = ((Morpho.minimum, Morpho.deflate), (Morpho.maximum, Morpho.inflate))

    diff = src.std.MakeDiff(flt)

    processed = list[vs.VideoNode]()
    for (inpand_op, deflate_op), (expand_op, inflate_op) in (ops[::-1], ops):
        clip = inpand_op(diff, iterations=ed1, coords=Coordinates.VERTICAL, func=func)

        if ed_res:
            clip = deflate_op(clip, func=func)
        if ed_res == 2:
            clip = median_blur(clip, func=func)

        clip = expand_op(clip, iterations=ed2, coords=Coordinates.VERTICAL, func=func)

        if over_dilation:
            clip = expand_op(clip, iterations=od, func=func)
            clip = inflate_op(clip, iterations=od_res, func=func)

        processed.append(clip)

    return norm_expr([flt, diff, *processed], "x y z neutral min a neutral max clamp neutral - +", func=func)