Skip to content

mvtools

MVTools

MVTools(
    clip: VideoNode,
    search_clip: VideoNode | GenericVSFunction | None = None,
    vectors: MotionVectors | MVTools | None = None,
    tr: int = 1,
    pad: int | tuple[int | None, int | None] | None = None,
    pel: int | None = None,
    planes: PlanesT = None,
    *,
    super_args: KwargsT | None = None,
    analyze_args: KwargsT | None = None,
    recalculate_args: KwargsT | None = None,
    compensate_args: KwargsT | None = None,
    flow_args: KwargsT | None = None,
    degrain_args: KwargsT | None = None,
    flow_interpolate_args: KwargsT | None = None,
    flow_fps_args: KwargsT | None = None,
    block_fps_args: KwargsT | None = None,
    flow_blur_args: KwargsT | None = None,
    mask_args: KwargsT | None = None,
    sc_detection_args: KwargsT | None = None
)

MVTools wrapper for motion analysis, degraining, compensation, interpolation, etc.

MVTools is a collection of functions for motion estimation and compensation in video.

Motion compensation may be used for strong temporal denoising, advanced framerate conversions, image restoration, and other similar tasks.

The plugin uses a block-matching method of motion estimation (similar methods as used in MPEG2, MPEG4, etc.). During the analysis stage the plugin divides frames into smaller blocks and tries to find the most similar matching block for every block in current frame in the second frame (which is either the previous or next frame). The relative shift of these blocks is the motion vector.

The main method of measuring block similarity is by calculating the sum of absolute differences (SAD) of all pixels of these two blocks, which indicates how correct the motion estimation was.

Parameters:

  • clip

    (VideoNode) –

    The clip to process.

  • search_clip

    (VideoNode | GenericVSFunction | None, default: None ) –

    Optional clip or callable to be used for motion vector gathering only.

  • vectors

    (MotionVectors | MVTools | None, default: None ) –

    Motion vectors to use. Can be a MotionVectors object or another MVTools instance. If None, uses the vectors from this instance.

  • tr

    (int, default: 1 ) –

    The temporal radius. This determines how many frames are analyzed before/after the current frame. Default: 1.

  • pad

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

    How much padding to add to the source frame. Small padding is added to help with motion estimation near frame borders.

  • pel

    (int | None, default: None ) –

    Subpixel precision for motion estimation (1=pixel, 2=half-pixel, 4=quarter-pixel). Default: 1.

  • planes

    (PlanesT, default: None ) –

    Which planes to process. Default: None (all planes).

  • super_args

    (KwargsT | None, default: None ) –

    Arguments passed to every :py:attr:MVToolsPlugin.Super calls.

  • analyze_args

    (KwargsT | None, default: None ) –

    Arguments passed to every :py:attr:MVToolsPlugin.Analyze calls.

  • recalculate_args

    (KwargsT | None, default: None ) –

    Arguments passed to every :py:attr:MVToolsPlugin.Recalculate calls.

  • compensate_args

    (KwargsT | None, default: None ) –

    Arguments passed to every :py:attr:MVToolsPlugin.Compensate calls.

  • flow_args

    (KwargsT | None, default: None ) –

    Arguments passed to every :py:attr:MVToolsPlugin.Flow calls.

  • degrain_args

    (KwargsT | None, default: None ) –

    Arguments passed to every :py:attr:MVToolsPlugin.Degrain calls.

  • flow_interpolate_args

    (KwargsT | None, default: None ) –

    Arguments passed to every :py:attr:MVToolsPlugin.FlowInter calls.

  • flow_fps_args

    (KwargsT | None, default: None ) –

    Arguments passed to every :py:attr:MVToolsPlugin.FlowFPS calls.

  • block_fps_args

    (KwargsT | None, default: None ) –

    Arguments passed to every :py:attr:MVToolsPlugin.BlockFPS calls.

  • flow_blur_args

    (KwargsT | None, default: None ) –

    Arguments passed to every :py:attr:MVToolsPlugin.FlowBlur calls.

  • mask_args

    (KwargsT | None, default: None ) –

    Arguments passed to every :py:attr:MVToolsPlugin.Mask calls.

  • sc_detection_args

    (KwargsT | None, default: None ) –

    Arguments passed to every :py:attr:MVToolsPlugin.SCDetection calls.

Source code
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
@disallow_variable_format
@disallow_variable_resolution
def __init__(
    self, clip: vs.VideoNode, search_clip: vs.VideoNode | GenericVSFunction | None = None,
    vectors: MotionVectors | MVTools | None = None,
    tr: int = 1, pad: int | tuple[int | None, int | None] | None = None,
    pel: int | None = None, planes: PlanesT = None,
    *,
    # kwargs for mvtools calls
    super_args: KwargsT | None = None,
    analyze_args: KwargsT | None = None,
    recalculate_args: KwargsT | None = None,
    compensate_args: KwargsT | None = None,
    flow_args: KwargsT | None = None,
    degrain_args: KwargsT | None = None,
    flow_interpolate_args: KwargsT | None = None,
    flow_fps_args: KwargsT | None = None,
    block_fps_args: KwargsT | None = None,
    flow_blur_args: KwargsT | None = None,
    mask_args: KwargsT | None = None,
    sc_detection_args: KwargsT | None = None
) -> None:
    """
    MVTools is a collection of functions for motion estimation and compensation in video.

    Motion compensation may be used for strong temporal denoising, advanced framerate conversions,
    image restoration, and other similar tasks.

    The plugin uses a block-matching method of motion estimation (similar methods as used in MPEG2, MPEG4, etc.).
    During the analysis stage the plugin divides frames into smaller blocks and tries to find the most similar matching block
    for every block in current frame in the second frame (which is either the previous or next frame).
    The relative shift of these blocks is the motion vector.

    The main method of measuring block similarity is by calculating the sum of absolute differences (SAD)
    of all pixels of these two blocks, which indicates how correct the motion estimation was.

    :param clip:                     The clip to process.
    :param search_clip:              Optional clip or callable to be used for motion vector gathering only.
    :param vectors:                  Motion vectors to use. Can be a MotionVectors object or another MVTools instance.
                                     If None, uses the vectors from this instance.
    :param tr:                       The temporal radius. This determines how many frames are analyzed before/after the current frame.
                                     Default: 1.
    :param pad:                      How much padding to add to the source frame.
                                     Small padding is added to help with motion estimation near frame borders.
    :param pel:                      Subpixel precision for motion estimation (1=pixel, 2=half-pixel, 4=quarter-pixel).
                                     Default: 1.
    :param planes:                   Which planes to process. Default: None (all planes).
    :param super_args:               Arguments passed to every :py:attr:`MVToolsPlugin.Super` calls.
    :param analyze_args:             Arguments passed to every :py:attr:`MVToolsPlugin.Analyze` calls.
    :param recalculate_args:         Arguments passed to every :py:attr:`MVToolsPlugin.Recalculate` calls.
    :param compensate_args:          Arguments passed to every :py:attr:`MVToolsPlugin.Compensate` calls.
    :param flow_args:                Arguments passed to every :py:attr:`MVToolsPlugin.Flow` calls.
    :param degrain_args:             Arguments passed to every :py:attr:`MVToolsPlugin.Degrain` calls.
    :param flow_interpolate_args:    Arguments passed to every :py:attr:`MVToolsPlugin.FlowInter` calls.
    :param flow_fps_args:            Arguments passed to every :py:attr:`MVToolsPlugin.FlowFPS` calls.
    :param block_fps_args:           Arguments passed to every :py:attr:`MVToolsPlugin.BlockFPS` calls.
    :param flow_blur_args:           Arguments passed to every :py:attr:`MVToolsPlugin.FlowBlur` calls.
    :param mask_args:                Arguments passed to every :py:attr:`MVToolsPlugin.Mask` calls.
    :param sc_detection_args:        Arguments passed to every :py:attr:`MVToolsPlugin.SCDetection` calls.
    """

    assert check_variable(clip, self.__class__)

    InvalidColorFamilyError.check(clip, (vs.YUV, vs.GRAY), self.__class__)

    if isinstance(vectors, MVTools):
        self.vectors = vectors.vectors
    elif isinstance(vectors, MotionVectors):
        self.vectors = vectors
    else:
        self.vectors = MotionVectors()

    self.mvtools = MVToolsPlugin.from_video(clip)
    self.fieldbased = FieldBased.from_video(clip, False, self.__class__)
    self.clip = clip.std.SeparateFields(self.fieldbased.is_tff) if self.fieldbased.is_inter else clip

    self.planes = normalize_planes(self.clip, planes)
    self.mv_plane = planes_to_mvtools(self.planes)
    self.chroma = self.mv_plane != 0

    self.tr = tr
    self.pel = pel
    self.pad = normalize_seq(pad, 2)

    if callable(search_clip):
        try:
            self.search_clip = search_clip(self.clip, planes=self.planes)
        except TypeError:
            self.search_clip = search_clip(self.clip)
    else:
        self.search_clip = fallback(search_clip, self.clip)

    self.disable_compensate = False

    if self.mvtools is MVToolsPlugin.FLOAT:
        self.disable_manipmv = True
        self.disable_degrain = True if tr == 1 else False
    else:
        self.disable_manipmv = False
        self.disable_degrain = False

    self.super_args = fallback(super_args, KwargsT())
    self.analyze_args = fallback(analyze_args, KwargsT())
    self.recalculate_args = fallback(recalculate_args, KwargsT())
    self.compensate_args = fallback(compensate_args, KwargsT())
    self.degrain_args = fallback(degrain_args, KwargsT())
    self.flow_args = fallback(flow_args, KwargsT())
    self.flow_interpolate_args = fallback(flow_interpolate_args, KwargsT())
    self.flow_fps_args = fallback(flow_fps_args, KwargsT())
    self.block_fps_args = fallback(block_fps_args, KwargsT())
    self.flow_blur_args = fallback(flow_blur_args, KwargsT())
    self.mask_args = fallback(mask_args, KwargsT())
    self.sc_detection_args = fallback(sc_detection_args, KwargsT())

analyze_args instance-attribute

analyze_args: KwargsT = fallback(analyze_args, KwargsT())

Arguments passed to every :py:attr:MVToolsPlugin.Analyze call.

block_fps_args instance-attribute

block_fps_args: KwargsT = fallback(block_fps_args, KwargsT())

Arguments passed to every :py:attr:MVToolsPlugin.BlockFPS call.

chroma instance-attribute

chroma = mv_plane != 0

clip instance-attribute

clip: VideoNode = SeparateFields(is_tff) if is_inter else clip

Clip to process.

compensate_args instance-attribute

compensate_args: KwargsT = fallback(compensate_args, KwargsT())

Arguments passed to every :py:attr:MVToolsPlugin.Compensate call.

degrain_args instance-attribute

degrain_args: KwargsT = fallback(degrain_args, KwargsT())

Arguments passed to every :py:attr:MVToolsPlugin.Degrain call.

disable_compensate instance-attribute

disable_compensate = False

disable_degrain instance-attribute

disable_degrain = True if tr == 1 else False

disable_manipmv instance-attribute

disable_manipmv = True

fieldbased instance-attribute

fieldbased = from_video(clip, False, __class__)

flow_args instance-attribute

flow_args: KwargsT = fallback(flow_args, KwargsT())

Arguments passed to every :py:attr:MVToolsPlugin.Flow call.

flow_blur_args instance-attribute

flow_blur_args: KwargsT = fallback(flow_blur_args, KwargsT())

Arguments passed to every :py:attr:MVToolsPlugin.FlowBlur call.

flow_fps_args instance-attribute

flow_fps_args: KwargsT = fallback(flow_fps_args, KwargsT())

Arguments passed to every :py:attr:MVToolsPlugin.FlowFPS call.

flow_interpolate_args instance-attribute

flow_interpolate_args: KwargsT = fallback(flow_interpolate_args, KwargsT())

Arguments passed to every :py:attr:MVToolsPlugin.FlowInter call.

mask_args instance-attribute

mask_args: KwargsT = fallback(mask_args, KwargsT())

Arguments passed to every :py:attr:MVToolsPlugin.Mask call.

mv_plane instance-attribute

mv_plane = planes_to_mvtools(planes)

mvtools instance-attribute

mvtools = from_video(clip)

pad instance-attribute

pad = normalize_seq(pad, 2)

pel instance-attribute

pel = pel

planes instance-attribute

planes = normalize_planes(clip, planes)

recalculate_args instance-attribute

recalculate_args: KwargsT = fallback(recalculate_args, KwargsT())

Arguments passed to every :py:attr:MVToolsPlugin.Recalculate call.

sc_detection_args instance-attribute

sc_detection_args: KwargsT = fallback(sc_detection_args, KwargsT())

Arguments passed to every :py:attr:MVToolsPlugin.SCDetection call.

search_clip instance-attribute

search_clip = search_clip(clip, planes=planes)

super_args instance-attribute

super_args: KwargsT = fallback(super_args, KwargsT())

Arguments passed to every :py:attr:MVToolsPlugin.Super call.

tr instance-attribute

tr = tr

vectors instance-attribute

vectors: MotionVectors

Motion vectors analyzed and used for all operations.

analyze

analyze(
    super: VideoNode | None = None,
    blksize: int | tuple[int | None, int | None] | None = None,
    levels: int | None = None,
    search: SearchMode | None = None,
    searchparam: int | None = None,
    pelsearch: int | None = None,
    lambda_: int | None = None,
    truemotion: MotionMode | None = None,
    lsad: int | None = None,
    plevel: PenaltyMode | None = None,
    global_: bool | None = None,
    pnew: int | None = None,
    pzero: int | None = None,
    pglobal: int | None = None,
    overlap: int | tuple[int | None, int | None] | None = None,
    divide: bool | None = None,
    badsad: int | None = None,
    badrange: int | None = None,
    meander: bool | None = None,
    trymany: bool | None = None,
    dct: SADMode | None = None,
) -> None

Analyze motion vectors in a clip using block matching.

Takes a prepared super clip (containing hierarchical frame data) and estimates motion by comparing blocks between frames. Outputs motion vector data that can be used by other functions for motion compensation.

The motion vector search is performed hierarchically, starting from a coarse image scale and progressively refining to finer scales. For each block, the function first checks predictors like the zero vector and neighboring block vectors.

This method calculates the Sum of Absolute Differences (SAD) for these predictors, then iteratively tests new candidate vectors by adjusting the current best vector. The vector with the lowest SAD value is chosen as the final motion vector, with a penalty applied to maintain motion coherence between blocks.

Parameters:

  • super

    (VideoNode | None, default: None ) –

    The multilevel super clip prepared by :py:attr:super. If None, super will be obtained from clip.

  • blksize

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

    Size of a block. Larger blocks are less sensitive to noise, are faster, but also less accurate.

  • levels

    (int | None, default: None ) –

    Number of levels used in hierarchical motion vector analysis. A positive value specifies how many levels to use. A negative or zero value specifies how many coarse levels to skip. Lower values generally give better results since vectors of any length can be found. Sometimes adding more levels can help prevent false vectors in CGI or similar content.

  • search

    (SearchMode | None, default: None ) –

    Search algorithm to use at the finest level. See :py:class:SearchMode for options.

  • searchparam

    (int | None, default: None ) –

    Additional parameter for the search algorithm. For NSTEP, this is the step size. For EXHAUSTIVE, EXHAUSTIVE_H, EXHAUSTIVE_V, HEXAGON and UMH, this is the search radius.

  • lambda_

    (int | None, default: None ) –

    Controls the coherence of the motion vector field. Higher values enforce more coherent/smooth motion between blocks. Too high values may cause the algorithm to miss the optimal vectors.

  • truemotion

    (MotionMode | None, default: None ) –

    Preset that controls the default values of motion estimation parameters to optimize for true motion. For more information, see :py:class:MotionMode.

  • lsad

    (int | None, default: None ) –

    SAD limit for lambda. When the SAD value of a vector predictor (formed from neighboring blocks) exceeds this limit, the local lambda value is decreased. This helps prevent the use of bad predictors, but reduces motion coherence between blocks.

  • plevel

    (PenaltyMode | None, default: None ) –

    Controls how the penalty factor (lambda) scales with hierarchical levels. For more information, see :py:class:PenaltyMode.

  • global_

    (bool | None, default: None ) –

    Whether to estimate global motion at each level and use it as an additional predictor. This can help with camera motion.

  • pnew

    (int | None, default: None ) –

    Penalty multiplier (relative to 256) applied to the SAD cost when evaluating new candidate vectors. Higher values make the search more conservative.

  • pzero

    (int | None, default: None ) –

    Penalty multiplier (relative to 256) applied to the SAD cost for the zero motion vector. Higher values discourage using zero motion.

  • pglobal

    (int | None, default: None ) –

    Penalty multiplier (relative to 256) applied to the SAD cost when using the global motion predictor.

  • overlap

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

    Block overlap value. Can be a single integer for both dimensions or a tuple of (horizontal, vertical) overlap values. Each value must be even and less than its corresponding block size dimension.

  • divide

    (bool | None, default: None ) –

    Whether to divide each block into 4 subblocks during post-processing. This may improve accuracy at the cost of performance.

  • badsad

    (int | None, default: None ) –

    SAD threshold above which a wider secondary search will be performed to find better motion vectors. Higher values mean fewer blocks will trigger the secondary search.

  • badrange

    (int | None, default: None ) –

    Search radius for the secondary search when a block's SAD exceeds badsad.

  • meander

    (bool | None, default: None ) –

    Whether to use a meandering scan pattern when processing blocks. If True, alternates between left-to-right and right-to-left scanning between rows to improve motion coherence.

  • trymany

    (bool | None, default: None ) –

    Whether to test multiple predictor vectors during the search process at coarser levels. Enabling this can find better vectors but increases processing time.

  • dct

    (SADMode | None, default: None ) –

    SAD calculation mode using block DCT (frequency spectrum) for comparing blocks. For more information, see :py:class:SADMode.

Returns:

  • None

    A :py:class:MotionVectors object containing the analyzed motion vectors for each frame. These vectors describe the estimated motion between frames and can be used for motion compensation.

Source code
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
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
def analyze(
    self, super: vs.VideoNode | None = None, blksize: int | tuple[int | None, int | None] | None = None,
    levels: int | None = None, search: SearchMode | None = None, searchparam: int | None = None,
    pelsearch: int | None = None, lambda_: int | None = None, truemotion: MotionMode | None = None,
    lsad: int | None = None, plevel: PenaltyMode | None = None, global_: bool | None = None,
    pnew: int | None = None, pzero: int | None = None, pglobal: int | None = None,
    overlap: int | tuple[int | None, int | None] | None = None, divide: bool | None = None,
    badsad: int | None = None, badrange: int | None = None, meander: bool | None = None,
    trymany: bool | None = None, dct: SADMode | None = None
) -> None:
    """
    Analyze motion vectors in a clip using block matching.

    Takes a prepared super clip (containing hierarchical frame data) and estimates motion by comparing blocks between frames.
    Outputs motion vector data that can be used by other functions for motion compensation.

    The motion vector search is performed hierarchically, starting from a coarse image scale and progressively refining to finer scales.
    For each block, the function first checks predictors like the zero vector and neighboring block vectors.

    This method calculates the Sum of Absolute Differences (SAD) for these predictors,
    then iteratively tests new candidate vectors by adjusting the current best vector.
    The vector with the lowest SAD value is chosen as the final motion vector,
    with a penalty applied to maintain motion coherence between blocks.

    :param super:          The multilevel super clip prepared by :py:attr:`super`.
                           If None, super will be obtained from clip.
    :param blksize:        Size of a block. Larger blocks are less sensitive to noise, are faster, but also less accurate.
    :param levels:         Number of levels used in hierarchical motion vector analysis.
                           A positive value specifies how many levels to use.
                           A negative or zero value specifies how many coarse levels to skip.
                           Lower values generally give better results since vectors of any length can be found.
                           Sometimes adding more levels can help prevent false vectors in CGI or similar content.
    :param search:         Search algorithm to use at the finest level. See :py:class:`SearchMode` for options.
    :param searchparam:    Additional parameter for the search algorithm. For NSTEP, this is the step size.
                           For EXHAUSTIVE, EXHAUSTIVE_H, EXHAUSTIVE_V, HEXAGON and UMH, this is the search radius.
    :param lambda_:        Controls the coherence of the motion vector field.
                           Higher values enforce more coherent/smooth motion between blocks.
                           Too high values may cause the algorithm to miss the optimal vectors.
    :param truemotion:     Preset that controls the default values of motion estimation parameters to optimize for true motion.
                           For more information, see :py:class:`MotionMode`.
    :param lsad:           SAD limit for lambda.
                           When the SAD value of a vector predictor (formed from neighboring blocks) exceeds this limit,
                           the local lambda value is decreased. This helps prevent the use of bad predictors,
                           but reduces motion coherence between blocks.
    :param plevel:         Controls how the penalty factor (lambda) scales with hierarchical levels.
                           For more information, see :py:class:`PenaltyMode`.
    :param global_:        Whether to estimate global motion at each level and use it as an additional predictor.
                           This can help with camera motion.
    :param pnew:           Penalty multiplier (relative to 256) applied to the SAD cost when evaluating new candidate vectors.
                           Higher values make the search more conservative.
    :param pzero:          Penalty multiplier (relative to 256) applied to the SAD cost for the zero motion vector.
                           Higher values discourage using zero motion.
    :param pglobal:        Penalty multiplier (relative to 256) applied to the SAD cost when using the global motion predictor.
    :param overlap:        Block overlap value. Can be a single integer for both dimensions or a tuple of (horizontal, vertical) overlap values.
                           Each value must be even and less than its corresponding block size dimension.
    :param divide:         Whether to divide each block into 4 subblocks during post-processing.
                           This may improve accuracy at the cost of performance.
    :param badsad:         SAD threshold above which a wider secondary search will be performed to find better motion vectors.
                           Higher values mean fewer blocks will trigger the secondary search.
    :param badrange:       Search radius for the secondary search when a block's SAD exceeds badsad.
    :param meander:        Whether to use a meandering scan pattern when processing blocks.
                           If True, alternates between left-to-right and right-to-left scanning between rows to improve motion coherence.
    :param trymany:        Whether to test multiple predictor vectors during the search process at coarser levels.
                           Enabling this can find better vectors but increases processing time.
    :param dct:            SAD calculation mode using block DCT (frequency spectrum) for comparing blocks.
                           For more information, see :py:class:`SADMode`.

    :return:               A :py:class:`MotionVectors` object containing the analyzed motion vectors for each frame.
                           These vectors describe the estimated motion between frames and can be used for motion compensation.
    """

    super_clip = self.get_super(fallback(super, self.search_clip))

    blksize, blksizev = normalize_seq(blksize, 2)
    overlap, overlapv = normalize_seq(overlap, 2)

    analyze_args = self.analyze_args | KwargsNotNone(
        blksize=blksize, blksizev=blksizev, levels=levels,
        search=search, searchparam=searchparam, pelsearch=pelsearch,
        lambda_=lambda_, chroma=self.chroma, truemotion=truemotion,
        lsad=lsad, plevel=plevel, global_=global_,
        pnew=pnew, pzero=pzero, pglobal=pglobal,
        overlap=overlap, overlapv=overlapv, divide=divide,
        badsad=badsad, badrange=badrange, meander=meander, trymany=trymany,
        fields=self.fieldbased.is_inter, tff=self.fieldbased.is_tff, dct=dct
    )

    if self.mvtools is MVToolsPlugin.INTEGER and not any(
        (analyze_args.get('overlap'), analyze_args.get('overlapv'))
    ):
        self.disable_compensate = True

    if self.mvtools is MVToolsPlugin.FLOAT:
        self.vectors.vmulti = self.mvtools.Analyze(super_clip, radius=self.tr, **analyze_args)
    else:
        for i in range(1, self.tr + 1):
            for direction in MVDirection:
                vector = self.mvtools.Analyze(
                    super_clip, isb=direction is MVDirection.BACK, delta=i, **analyze_args
                )
                self.vectors.set_mv(direction, i, vector)

        self.vectors.analysis_data.clear()

block_fps

block_fps(
    clip: VideoNode | None = None,
    super: VideoNode | None = None,
    vectors: MotionVectors | MVTools | None = None,
    fps: Fraction | None = None,
    mode: int | None = None,
    ml: float | None = None,
    blend: bool | None = None,
    thscd: int | tuple[int | None, int | None] | None = None,
) -> VideoNode

Changes the framerate of the clip by interpolating frames between existing frames using block-based motion compensation.

Uses both backward and forward motion vectors to estimate motion and create frames at any time position between the current and next frame. Occlusion masks are used to handle areas where motion estimation fails, and time weighting ensures smooth blending between frames to minimize artifacts.

Parameters:

  • clip

    (VideoNode | None, default: None ) –

    The clip to process.

  • super

    (VideoNode | None, default: None ) –

    The multilevel super clip prepared by :py:attr:super. If None, super will be obtained from clip.

  • vectors

    (MotionVectors | MVTools | None, default: None ) –

    Motion vectors to use. Can be a MotionVectors object or another MVTools instance. If None, uses the vectors from this instance.

  • fps

    (Fraction | None, default: None ) –

    Target output framerate as a Fraction.

  • mode

    (int | None, default: None ) –

    Processing mask mode for handling occlusions and motion failures.

  • ml

    (float | None, default: None ) –

    Mask scale parameter that controls occlusion mask strength. Higher values produce weaker occlusion masks. Used in MakeVectorOcclusionMaskTime for modes 3-5. Used in MakeSADMaskTime for modes 6-8.

  • blend

    (bool | None, default: None ) –

    Whether to blend frames at scene changes. If True, frames will be blended. If False, frames will be copied.

  • thscd

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

    Scene change detection thresholds. First value is the block change threshold between frames. Second value is the number of changed blocks needed for a scene change.

Returns:

  • VideoNode

    Clip with its framerate resampled.

Source code
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
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
def block_fps(
    self, clip: vs.VideoNode | None = None, super: vs.VideoNode | None = None,
    vectors: MotionVectors | MVTools | None = None, fps: Fraction | None = None,
    mode: int | None = None, ml: float | None = None, blend: bool | None = None,
    thscd: int | tuple[int | None, int | None] | None = None
) -> vs.VideoNode:
    """
    Changes the framerate of the clip by interpolating frames between existing frames
    using block-based motion compensation.

    Uses both backward and forward motion vectors to estimate motion and create frames at any time position between
    the current and next frame. Occlusion masks are used to handle areas where motion estimation fails, and time
    weighting ensures smooth blending between frames to minimize artifacts.

    :param clip:       The clip to process.
    :param super:      The multilevel super clip prepared by :py:attr:`super`.
                       If None, super will be obtained from clip.
    :param vectors:    Motion vectors to use. Can be a MotionVectors object or another MVTools instance.
                       If None, uses the vectors from this instance.
    :param fps:        Target output framerate as a Fraction.
    :param mode:       Processing mask mode for handling occlusions and motion failures.
    :param ml:         Mask scale parameter that controls occlusion mask strength.
                       Higher values produce weaker occlusion masks.
                       Used in MakeVectorOcclusionMaskTime for modes 3-5.
                       Used in MakeSADMaskTime for modes 6-8.
    :param blend:      Whether to blend frames at scene changes.
                       If True, frames will be blended. If False, frames will be copied.
    :param thscd:      Scene change detection thresholds.
                       First value is the block change threshold between frames.
                       Second value is the number of changed blocks needed for a scene change.

    :return:           Clip with its framerate resampled.
    """

    clip = fallback(clip, self.clip)
    super_clip = self.get_super(fallback(super, clip))

    if isinstance(vectors, MVTools):
        vectors = vectors.vectors
    elif vectors is None:
        vectors = self.vectors

    vect_b, vect_f = self.get_vectors(self.vectors, tr=1)

    thscd1, thscd2 = normalize_thscd(thscd)

    block_fps_args: dict[str, Any] = KwargsNotNone(mode=mode, ml=ml, blend=blend, thscd1=thscd1, thscd2=thscd2)

    if fps is not None:
        block_fps_args.update(num=fps.numerator, den=fps.denominator)

    block_fps_args = self.block_fps_args | block_fps_args

    return self.mvtools.BlockFPS(clip, super_clip, vect_b, vect_f, **block_fps_args)

compensate

compensate(
    clip: VideoNode | None = None,
    super: VideoNode | None = None,
    vectors: MotionVectors | MVTools | None = None,
    direction: MVDirection = BOTH,
    tr: int | None = None,
    scbehavior: bool | None = None,
    thsad: int | None = None,
    thsad2: int | None = None,
    time: float | None = None,
    thscd: int | tuple[int | None, int | None] | None = None,
    interleave: Literal[True] = True,
    temporal_func: None = None,
) -> VideoNode
compensate(
    clip: VideoNode | None = None,
    super: VideoNode | None = None,
    vectors: MotionVectors | MVTools | None = None,
    direction: MVDirection = BOTH,
    tr: int | None = None,
    scbehavior: bool | None = None,
    thsad: int | None = None,
    thsad2: int | None = None,
    time: float | None = None,
    thscd: int | tuple[int | None, int | None] | None = None,
    interleave: Literal[True] = True,
    temporal_func: VSFunction = ...,
) -> tuple[VideoNode, tuple[int, int]]
compensate(
    clip: VideoNode | None = None,
    super: VideoNode | None = None,
    vectors: MotionVectors | MVTools | None = None,
    direction: MVDirection = BOTH,
    tr: int | None = None,
    scbehavior: bool | None = None,
    thsad: int | None = None,
    thsad2: int | None = None,
    time: float | None = None,
    thscd: int | tuple[int | None, int | None] | None = None,
    interleave: Literal[False] = False,
) -> tuple[list[VideoNode], list[VideoNode]]
compensate(
    clip: VideoNode | None = None,
    super: VideoNode | None = None,
    vectors: MotionVectors | MVTools | None = None,
    direction: MVDirection = BOTH,
    tr: int | None = None,
    scbehavior: bool | None = None,
    thsad: int | None = None,
    thsad2: int | None = None,
    time: float | None = None,
    thscd: int | tuple[int | None, int | None] | None = None,
    interleave: bool = True,
    temporal_func: VSFunction | None = None,
) -> (
    VideoNode
    | tuple[list[VideoNode], list[VideoNode]]
    | tuple[VideoNode, tuple[int, int]]
)

Perform motion compensation by moving blocks from reference frames to the current frame according to motion vectors. This creates a prediction of the current frame by taking blocks from neighboring frames and moving them along their estimated motion paths.

Parameters:

  • clip

    (VideoNode | None, default: None ) –

    The clip to process.

  • super

    (VideoNode | None, default: None ) –

    The multilevel super clip prepared by :py:attr:super. If None, super will be obtained from clip.

  • vectors

    (MotionVectors | MVTools | None, default: None ) –

    Motion vectors to use. Can be a MotionVectors object or another MVTools instance. If None, uses the vectors from this instance.

  • direction

    (MVDirection, default: BOTH ) –

    Motion vector direction to use.

  • tr

    (int | None, default: None ) –

    The temporal radius. This determines how many frames are analyzed before/after the current frame.

  • scbehavior

    (bool | None, default: None ) –

    Whether to keep the current frame on scene changes. If True, the frame is left unchanged. If False, the reference frame is copied.

  • thsad

    (int | None, default: None ) –

    SAD threshold for safe compensation. If block SAD is above thsad, the source block is used instead of the compensated block.

  • thsad2

    (int | None, default: None ) –

    Define the SAD soft threshold for frames with the largest temporal distance. The actual SAD threshold for each reference frame is interpolated between thsad (nearest frames) and thsad2 (furthest frames). Only used with the FLOAT MVTools plugin.

  • time

    (float | None, default: None ) –

    Time position between frames as a percentage (0.0-100.0). Controls the interpolation position between frames.

  • thscd

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

    Scene change detection thresholds. First value is the block change threshold between frames. Second value is the number of changed blocks needed for a scene change.

  • interleave

    (bool, default: True ) –

    Whether to interleave the compensated frames with the input.

  • temporal_func

    (VSFunction | None, default: None ) –

    Temporal function to apply to the motion compensated frames.

Returns:

  • VideoNode | tuple[list[VideoNode], list[VideoNode]] | tuple[VideoNode, tuple[int, int]]

    Motion compensated frames if func is provided, otherwise returns a tuple containing: - The interleaved compensated frames. - A tuple of (total_frames, center_offset) for manual frame selection.

Source code
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
524
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
def compensate(
    self, clip: vs.VideoNode | None = None, super: vs.VideoNode | None = None,
    vectors: MotionVectors | MVTools | None = None, direction: MVDirection = MVDirection.BOTH,
    tr: int | None = None, scbehavior: bool | None = None,
    thsad: int | None = None, thsad2: int | None = None,
    time: float | None = None, thscd: int | tuple[int | None, int | None] | None = None,
    interleave: bool = True, temporal_func: VSFunction | None = None
) -> vs.VideoNode | tuple[list[vs.VideoNode], list[vs.VideoNode]] | tuple[vs.VideoNode, tuple[int, int]]:
    """
    Perform motion compensation by moving blocks from reference frames to the current frame according to motion vectors.
    This creates a prediction of the current frame by taking blocks from neighboring frames and moving them along their estimated motion paths.

    :param clip:             The clip to process.
    :param super:            The multilevel super clip prepared by :py:attr:`super`.
                             If None, super will be obtained from clip.
    :param vectors:          Motion vectors to use. Can be a MotionVectors object or another MVTools instance.
                             If None, uses the vectors from this instance.
    :param direction:        Motion vector direction to use.
    :param tr:               The temporal radius. This determines how many frames are analyzed before/after the current frame.
    :param scbehavior:       Whether to keep the current frame on scene changes.
                             If True, the frame is left unchanged. If False, the reference frame is copied.
    :param thsad:            SAD threshold for safe compensation.
                             If block SAD is above thsad, the source block is used instead of the compensated block.
    :param thsad2:           Define the SAD soft threshold for frames with the largest temporal distance.
                             The actual SAD threshold for each reference frame is interpolated between thsad (nearest frames)
                             and thsad2 (furthest frames).
                             Only used with the FLOAT MVTools plugin.
    :param time:             Time position between frames as a percentage (0.0-100.0).
                             Controls the interpolation position between frames.
    :param thscd:            Scene change detection thresholds.
                             First value is the block change threshold between frames.
                             Second value is the number of changed blocks needed for a scene change.
    :param interleave:       Whether to interleave the compensated frames with the input.
    :param temporal_func:    Temporal function to apply to the motion compensated frames.

    :return:                 Motion compensated frames if func is provided, otherwise returns a tuple containing:
                             - The interleaved compensated frames.
                             - A tuple of (total_frames, center_offset) for manual frame selection.
    """

    if self.disable_compensate:
        raise CustomRuntimeError('Motion analysis was performed without block overlap!', self.compensate)

    clip = fallback(clip, self.clip)
    super_clip = self.get_super(fallback(super, clip))

    if isinstance(vectors, MVTools):
        vectors = vectors.vectors
    elif vectors is None:
        vectors = self.vectors

    tr = fallback(tr, self.tr)

    vect_b, vect_f = self.get_vectors(self.vectors, direction=direction, tr=tr)

    thscd1, thscd2 = normalize_thscd(thscd)

    compensate_args = self.compensate_args | KwargsNotNone(
        scbehavior=scbehavior, thsad=thsad, thsad2=thsad2, time=time, fields=self.fieldbased.is_inter,
        thscd1=thscd1, thscd2=thscd2, tff=self.fieldbased.is_tff
    )

    comp_back, comp_fwrd = [
        [self.mvtools.Compensate(clip, super_clip, vectors=vect, **compensate_args) for vect in vectors]
        for vectors in (reversed(vect_b), vect_f)
    ]

    if not interleave:
        return (comp_back, comp_fwrd)

    comp_clips = [*comp_fwrd, clip, *comp_back]
    n_clips = len(comp_clips)
    offset = (n_clips - 1) // 2

    interleaved = core.std.Interleave(comp_clips)

    if temporal_func:
        processed = temporal_func(interleaved)

        return processed.std.SelectEvery(n_clips, offset)

    return interleaved, (n_clips, offset)

degrain

degrain(
    clip: VideoNode | None = None,
    super: VideoNode | None = None,
    vectors: MotionVectors | MVTools | None = None,
    tr: int | None = None,
    thsad: int | tuple[int | None, int | None] | None = None,
    thsad2: int | tuple[int | None, int | None] | None = None,
    limit: int | tuple[int | None, int | None] | None = None,
    thscd: int | tuple[int | None, int | None] | None = None,
) -> VideoNode

Perform temporal denoising using motion compensation.

Motion compensated blocks from previous and next frames are averaged with the current frame. The weighting factors for each block depend on their SAD from the current frame.

Parameters:

  • clip

    (VideoNode | None, default: None ) –

    The clip to process. If None, the :py:attr:workclip attribute is used.

  • super

    (VideoNode | None, default: None ) –

    The multilevel super clip prepared by :py:attr:super. If None, super will be obtained from clip.

  • vectors

    (MotionVectors | MVTools | None, default: None ) –

    Motion vectors to use. Can be a MotionVectors object or another MVTools instance. If None, uses the vectors from this instance.

  • tr

    (int | None, default: None ) –

    The temporal radius. This determines how many frames are analyzed before/after the current frame.

  • thsad

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

    Defines the soft threshold of block sum absolute differences. Blocks with SAD above this threshold have zero weight for averaging (denoising). Blocks with low SAD have highest weight. The remaining weight is taken from pixels of source clip.

  • thsad2

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

    Define the SAD soft threshold for frames with the largest temporal distance. The actual SAD threshold for each reference frame is interpolated between thsad (nearest frames) and thsad2 (furthest frames). Only used with the FLOAT MVTools plugin.

  • limit

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

    Maximum allowed change in pixel values.

  • thscd

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

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

Returns:

  • VideoNode

    Motion compensated and temporally filtered clip with reduced noise.

Source code
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
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
742
def degrain(
    self, clip: vs.VideoNode | None = None, super: vs.VideoNode | None = None,
    vectors: MotionVectors | MVTools | None = None, tr: int | None = None,
    thsad: int | tuple[int | None, int | None] | None = None,
    thsad2: int | tuple[int | None, int | None] | None = None,
    limit: int | tuple[int | None, int | None] | None = None,
    thscd: int | tuple[int | None, int | None] | None = None,
) -> vs.VideoNode:
    """
    Perform temporal denoising using motion compensation.

    Motion compensated blocks from previous and next frames are averaged with the current frame.
    The weighting factors for each block depend on their SAD from the current frame.

    :param clip:       The clip to process.
                       If None, the :py:attr:`workclip` attribute is used.
    :param super:      The multilevel super clip prepared by :py:attr:`super`.
                       If None, super will be obtained from clip.
    :param vectors:    Motion vectors to use. Can be a MotionVectors object or another MVTools instance.
                       If None, uses the vectors from this instance.
    :param tr:         The temporal radius. This determines how many frames are analyzed before/after the current frame.
    :param thsad:      Defines the soft threshold of block sum absolute differences.
                       Blocks with SAD above this threshold have zero weight for averaging (denoising).
                       Blocks with low SAD have highest weight.
                       The remaining weight is taken from pixels of source clip.
    :param thsad2:     Define the SAD soft threshold for frames with the largest temporal distance.
                       The actual SAD threshold for each reference frame is interpolated between thsad (nearest frames)
                       and thsad2 (furthest frames).
                       Only used with the FLOAT MVTools plugin.
    :param limit:      Maximum allowed change in pixel values.
    :param thscd:      Scene change detection thresholds:
                       - First value: SAD threshold for considering a block changed between frames.
                       - Second value: Number of changed blocks needed to trigger a scene change.

    :return:           Motion compensated and temporally filtered clip with reduced noise.
    """

    if self.disable_degrain:
        raise CustomRuntimeError('Motion analysis was performed with a temporal radius of 1!', self.degrain)

    clip = fallback(clip, self.clip)
    super_clip = self.get_super(fallback(super, clip))

    if isinstance(vectors, MVTools):
        vectors = vectors.vectors
    elif vectors is None:
        vectors = self.vectors

    tr = fallback(tr, self.tr)

    thscd1, thscd2 = normalize_thscd(thscd)

    degrain_args = dict[str, Any](thscd1=thscd1, thscd2=thscd2, plane=self.mv_plane)

    if self.mvtools is MVToolsPlugin.FLOAT:
        degrain_args.update(thsad=thsad, thsad2=thsad2, limit=limit)
    else:
        vect_b, vect_f = self.get_vectors(vectors, tr=tr)

        thsad, thsadc = normalize_seq(thsad, 2)
        limit, limitc = normalize_seq(limit, 2)

        if limit is not None:
            limit = scale_delta(limit, 8, clip)  # type: ignore[assignment]

        if limitc is not None:
            limitc = scale_delta(limitc, 8, clip)  # type: ignore[assignment]

        degrain_args.update(thsad=thsad, thsadc=thsadc, limit=limit, limitc=limitc)

    degrain_args = self.degrain_args | KwargsNotNone(degrain_args)

    if self.mvtools is MVToolsPlugin.FLOAT:
        output = self.mvtools.Degrain()(clip, super_clip, vectors.vmulti, **degrain_args)
    else:
        output = self.mvtools.Degrain(tr)(
            clip, super_clip, *chain.from_iterable(zip(vect_b, vect_f)), **degrain_args
        )

    return output

expand_analysis_data

expand_analysis_data(vectors: MotionVectors | MVTools | None = None) -> None

Expands the binary MVTools_MVAnalysisData frame prop into separate frame props for convenience.

Parameters:

  • vectors

    (MotionVectors | MVTools | None, default: None ) –

    Motion vectors to use. Can be a MotionVectors object or another MVTools instance. If None, uses the vectors from this instance.

Source code
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
def expand_analysis_data(self, vectors: MotionVectors | MVTools | None = None) -> None:
    """
    Expands the binary MVTools_MVAnalysisData frame prop into separate frame props for convenience.

    :param vectors:    Motion vectors to use. Can be a MotionVectors object or another MVTools instance.
                       If None, uses the vectors from this instance.
    """

    if self.disable_manipmv:
        raise CustomRuntimeError(
            f'Motion vector manipulation not supported with {self.mvtools}!', self.expand_analysis_data
        )

    if isinstance(vectors, MVTools):
        vectors = vectors.vectors
    elif vectors is None:
        vectors = self.vectors

    props_list = (
        'Analysis_BlockSize', 'Analysis_Pel', 'Analysis_LevelCount', 'Analysis_CpuFlags', 'Analysis_MotionFlags',
        'Analysis_FrameSize', 'Analysis_Overlap', 'Analysis_BlockCount', 'Analysis_BitsPerSample',
        'Analysis_ChromaRatio', 'Analysis_Padding'
    )

    if not vectors.analysis_data:
        analysis_props = dict[str, Any]()

        with vectors.get_mv(MVDirection.BACK, 1).manipmv.ExpandAnalysisData().get_frame(0) as clip_props:
            for i in props_list:
                analysis_props[i] = get_prop(clip_props, i, int | list)  # type: ignore

        vectors.analysis_data = analysis_props

flow

flow(
    clip: VideoNode | None = None,
    super: VideoNode | None = None,
    vectors: MotionVectors | MVTools | None = None,
    direction: MVDirection = BOTH,
    tr: int | None = None,
    time: float | None = None,
    mode: FlowMode | None = None,
    thscd: int | tuple[int | None, int | None] | None = None,
    interleave: Literal[True] = True,
    temporal_func: None = None,
) -> VideoNode
flow(
    clip: VideoNode | None = None,
    super: VideoNode | None = None,
    vectors: MotionVectors | MVTools | None = None,
    direction: MVDirection = BOTH,
    tr: int | None = None,
    time: float | None = None,
    mode: FlowMode | None = None,
    thscd: int | tuple[int | None, int | None] | None = None,
    interleave: Literal[True] = True,
    temporal_func: VSFunction = ...,
) -> tuple[VideoNode, tuple[int, int]]
flow(
    clip: VideoNode | None = None,
    super: VideoNode | None = None,
    vectors: MotionVectors | MVTools | None = None,
    direction: MVDirection = BOTH,
    tr: int | None = None,
    time: float | None = None,
    mode: FlowMode | None = None,
    thscd: int | tuple[int | None, int | None] | None = None,
    interleave: Literal[False] = False,
) -> tuple[list[VideoNode], list[VideoNode]]
flow(
    clip: VideoNode | None = None,
    super: VideoNode | None = None,
    vectors: MotionVectors | MVTools | None = None,
    direction: MVDirection = BOTH,
    tr: int | None = None,
    time: float | None = None,
    mode: FlowMode | None = None,
    thscd: int | tuple[int | None, int | None] | None = None,
    interleave: bool = True,
    temporal_func: VSFunction | None = None,
) -> (
    VideoNode
    | tuple[list[VideoNode], list[VideoNode]]
    | tuple[VideoNode, tuple[int, int]]
)

Performs motion compensation using pixel-level motion vectors interpolated from block vectors.

Unlike block-based compensation, this calculates a unique motion vector for each pixel by bilinearly interpolating between the motion vectors of the current block and its neighbors based on the pixel's position. The pixels in the reference frame are then moved along these interpolated vectors to their estimated positions in the current frame.

Parameters:

  • clip

    (VideoNode | None, default: None ) –

    The clip to process.

  • super

    (VideoNode | None, default: None ) –

    The multilevel super clip prepared by :py:attr:super. If None, super will be obtained from clip.

  • vectors

    (MotionVectors | MVTools | None, default: None ) –

    Motion vectors to use. Can be a MotionVectors object or another MVTools instance. If None, uses the vectors from this instance.

  • direction

    (MVDirection, default: BOTH ) –

    Motion vector direction to use.

  • tr

    (int | None, default: None ) –

    The temporal radius. This determines how many frames are analyzed before/after the current frame.

  • time

    (float | None, default: None ) –

    Time position between frames as a percentage (0.0-100.0). Controls the interpolation position between frames.

  • mode

    (FlowMode | None, default: None ) –

    Method for positioning pixels during motion compensation. See :py:class:FlowMode for options.

  • thscd

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

    Scene change detection thresholds as a tuple of (threshold1, threshold2). threshold1: SAD difference threshold between frames to consider a block changed threshold2: Number of changed blocks needed to trigger a scene change

  • interleave

    (bool, default: True ) –

    Whether to interleave the compensated frames with the input.

  • temporal_func

    (VSFunction | None, default: None ) –

    Optional function to process the motion compensated frames. Takes the interleaved frames as input and returns processed frames.

Returns:

  • VideoNode | tuple[list[VideoNode], list[VideoNode]] | tuple[VideoNode, tuple[int, int]]

    Motion compensated frames if func is provided, otherwise returns a tuple containing: - The interleaved compensated frames. - A tuple of (total_frames, center_offset) for manual frame selection.

Source code
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
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
660
661
def flow(
    self, clip: vs.VideoNode | None = None, super: vs.VideoNode | None = None,
    vectors: MotionVectors | MVTools | None = None,
    direction: MVDirection = MVDirection.BOTH,
    tr: int | None = None, time: float | None = None, mode: FlowMode | None = None,
    thscd: int | tuple[int | None, int | None] | None = None,
    interleave: bool = True, temporal_func: VSFunction | None = None
) -> vs.VideoNode | tuple[list[vs.VideoNode], list[vs.VideoNode]] | tuple[vs.VideoNode, tuple[int, int]]:
    """
    Performs motion compensation using pixel-level motion vectors interpolated from block vectors.

    Unlike block-based compensation, this calculates a unique motion vector for each pixel by bilinearly interpolating
    between the motion vectors of the current block and its neighbors based on the pixel's position.
    The pixels in the reference frame are then moved along these interpolated vectors to their estimated positions in the current frame.

    :param clip:             The clip to process.
    :param super:            The multilevel super clip prepared by :py:attr:`super`.
                             If None, super will be obtained from clip.
    :param vectors:          Motion vectors to use. Can be a MotionVectors object or another MVTools instance.
                             If None, uses the vectors from this instance.
    :param direction:        Motion vector direction to use.
    :param tr:               The temporal radius. This determines how many frames are analyzed before/after the current frame.
    :param time:             Time position between frames as a percentage (0.0-100.0).
                             Controls the interpolation position between frames.
    :param mode:             Method for positioning pixels during motion compensation.
                             See :py:class:`FlowMode` for options.
    :param thscd:            Scene change detection thresholds as a tuple of (threshold1, threshold2).
                             threshold1: SAD difference threshold between frames to consider a block changed
                             threshold2: Number of changed blocks needed to trigger a scene change
    :param interleave:       Whether to interleave the compensated frames with the input.
    :param temporal_func:    Optional function to process the motion compensated frames.
                             Takes the interleaved frames as input and returns processed frames.

    :return:                 Motion compensated frames if func is provided, otherwise returns a tuple containing:
                             - The interleaved compensated frames.
                             - A tuple of (total_frames, center_offset) for manual frame selection.
    """

    clip = fallback(clip, self.clip)
    super_clip = self.get_super(fallback(super, clip))

    if isinstance(vectors, MVTools):
        vectors = vectors.vectors
    elif vectors is None:
        vectors = self.vectors

    tr = fallback(tr, self.tr)

    vect_b, vect_f = self.get_vectors(self.vectors, direction=direction, tr=tr)

    thscd1, thscd2 = normalize_thscd(thscd)

    flow_args = self.flow_args | KwargsNotNone(
        time=time, mode=mode, fields=self.fieldbased.is_inter,
        thscd1=thscd1, thscd2=thscd2, tff=self.fieldbased.is_tff
    )

    flow_back, flow_fwrd = [
        [self.mvtools.Flow(clip, super_clip, vectors=vect, **flow_args) for vect in vectors]
        for vectors in (reversed(vect_b), vect_f)
    ]

    if not interleave:
        return (flow_back, flow_fwrd)

    flow_clips = [*flow_fwrd, clip, *flow_back]
    n_clips = len(flow_clips)
    offset = (n_clips - 1) // 2

    interleaved = core.std.Interleave(flow_clips)

    if temporal_func:
        processed = temporal_func(interleaved)

        return processed.std.SelectEvery(n_clips, offset)

    return interleaved, (n_clips, offset)

flow_blur

flow_blur(
    clip: VideoNode | None = None,
    super: VideoNode | None = None,
    vectors: MotionVectors | MVTools | None = None,
    blur: float | None = None,
    prec: int | None = None,
    thscd: int | tuple[int | None, int | None] | None = None,
) -> VideoNode

Creates a motion blur effect by simulating finite shutter time, similar to film cameras.

Uses backward and forward motion vectors to create and overlay multiple copies of motion compensated pixels at intermediate time positions within a blurring interval around the current frame.

Parameters:

  • clip

    (VideoNode | None, default: None ) –

    The clip to process.

  • super

    (VideoNode | None, default: None ) –

    The multilevel super clip prepared by :py:attr:super. If None, super will be obtained from clip.

  • vectors

    (MotionVectors | MVTools | None, default: None ) –

    Motion vectors to use. Can be a MotionVectors object or another MVTools instance. If None, uses the vectors from this instance.

  • blur

    (float | None, default: None ) –

    Blur time interval between frames as a percentage (0.0-100.0). Controls the simulated shutter time/motion blur strength.

  • prec

    (int | None, default: None ) –

    Blur precision in pixel units. Controls the accuracy of the motion blur.

  • thscd

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

    Scene change detection thresholds. First value is the block change threshold between frames. Second value is the number of changed blocks needed for a scene change.

Returns:

  • VideoNode

    Motion blurred clip.

Source code
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
def flow_blur(
    self, clip: vs.VideoNode | None = None, super: vs.VideoNode | None = None,
    vectors: MotionVectors | MVTools | None = None, blur: float | None = None,
    prec: int | None = None, thscd: int | tuple[int | None, int | None] | None = None
) -> vs.VideoNode:
    """
    Creates a motion blur effect by simulating finite shutter time, similar to film cameras.

    Uses backward and forward motion vectors to create and overlay multiple copies of motion compensated pixels
    at intermediate time positions within a blurring interval around the current frame.

    :param clip:       The clip to process.
    :param super:      The multilevel super clip prepared by :py:attr:`super`.
                       If None, super will be obtained from clip.
    :param vectors:    Motion vectors to use. Can be a MotionVectors object or another MVTools instance.
                       If None, uses the vectors from this instance.
    :param blur:       Blur time interval between frames as a percentage (0.0-100.0).
                       Controls the simulated shutter time/motion blur strength.
    :param prec:       Blur precision in pixel units. Controls the accuracy of the motion blur.
    :param thscd:      Scene change detection thresholds.
                       First value is the block change threshold between frames.
                       Second value is the number of changed blocks needed for a scene change.

    :return:           Motion blurred clip.
    """

    clip = fallback(clip, self.clip)
    super_clip = self.get_super(fallback(super, clip))

    if isinstance(vectors, MVTools):
        vectors = vectors.vectors
    elif vectors is None:
        vectors = self.vectors

    vect_b, vect_f = self.get_vectors(self.vectors, tr=1)

    thscd1, thscd2 = normalize_thscd(thscd)

    flow_blur_args = self.flow_blur_args | KwargsNotNone(blur=blur, prec=prec, thscd1=thscd1, thscd2=thscd2)

    return self.mvtools.FlowBlur(clip, super_clip, vect_b, vect_f, **flow_blur_args)

flow_fps

flow_fps(
    clip: VideoNode | None = None,
    super: VideoNode | None = None,
    vectors: MotionVectors | MVTools | None = None,
    fps: Fraction | None = None,
    mask: int | None = None,
    ml: float | None = None,
    blend: bool | None = None,
    thscd: int | tuple[int | None, int | None] | None = None,
) -> VideoNode

Changes the framerate of the clip by interpolating frames between existing frames.

Uses both backward and forward motion vectors to estimate motion and create frames at any time position between the current and next frame. Occlusion masks are used to handle areas where motion estimation fails, and time weighting ensures smooth blending between frames to minimize artifacts.

Parameters:

  • clip

    (VideoNode | None, default: None ) –

    The clip to process.

  • super

    (VideoNode | None, default: None ) –

    The multilevel super clip prepared by :py:attr:super. If None, super will be obtained from clip.

  • vectors

    (MotionVectors | MVTools | None, default: None ) –

    Motion vectors to use. Can be a MotionVectors object or another MVTools instance. If None, uses the vectors from this instance.

  • fps

    (Fraction | None, default: None ) –

    Target output framerate as a Fraction.

  • mask

    (int | None, default: None ) –

    Processing mask mode for handling occlusions and motion failures.

  • ml

    (float | None, default: None ) –

    Mask scale parameter that controls occlusion mask strength. Higher values produce weaker occlusion masks. Used in MakeVectorOcclusionMaskTime for modes 3-5. Used in MakeSADMaskTime for modes 6-8.

  • blend

    (bool | None, default: None ) –

    Whether to blend frames at scene changes. If True, frames will be blended. If False, frames will be copied.

  • thscd

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

    Scene change detection thresholds. First value is the block change threshold between frames. Second value is the number of changed blocks needed for a scene change.

Returns:

  • VideoNode

    Clip with its framerate resampled.

Source code
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
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
def flow_fps(
    self, clip: vs.VideoNode | None = None, super: vs.VideoNode | None = None,
    vectors: MotionVectors | MVTools | None = None, fps: Fraction | None = None,
    mask: int | None = None, ml: float | None = None, blend: bool | None = None,
    thscd: int | tuple[int | None, int | None] | None = None
) -> vs.VideoNode:
    """
    Changes the framerate of the clip by interpolating frames between existing frames.

    Uses both backward and forward motion vectors to estimate motion and create frames at any time position between
    the current and next frame. Occlusion masks are used to handle areas where motion estimation fails, and time
    weighting ensures smooth blending between frames to minimize artifacts.

    :param clip:       The clip to process.
    :param super:      The multilevel super clip prepared by :py:attr:`super`.
                       If None, super will be obtained from clip.
    :param vectors:    Motion vectors to use. Can be a MotionVectors object or another MVTools instance.
                       If None, uses the vectors from this instance.
    :param fps:        Target output framerate as a Fraction.
    :param mask:       Processing mask mode for handling occlusions and motion failures.
    :param ml:         Mask scale parameter that controls occlusion mask strength.
                       Higher values produce weaker occlusion masks.
                       Used in MakeVectorOcclusionMaskTime for modes 3-5.
                       Used in MakeSADMaskTime for modes 6-8.
    :param blend:      Whether to blend frames at scene changes.
                       If True, frames will be blended. If False, frames will be copied.
    :param thscd:      Scene change detection thresholds.
                       First value is the block change threshold between frames.
                       Second value is the number of changed blocks needed for a scene change.

    :return:           Clip with its framerate resampled.
    """

    clip = fallback(clip, self.clip)
    super_clip = self.get_super(fallback(super, clip))

    if isinstance(vectors, MVTools):
        vectors = vectors.vectors
    elif vectors is None:
        vectors = self.vectors

    vect_b, vect_f = self.get_vectors(self.vectors, tr=1)

    thscd1, thscd2 = normalize_thscd(thscd)

    flow_fps_args: dict[str, Any] = KwargsNotNone(mask=mask, ml=ml, blend=blend, thscd1=thscd1, thscd2=thscd2)

    if fps is not None:
        flow_fps_args.update(num=fps.numerator, den=fps.denominator)

    flow_fps_args = self.flow_fps_args | flow_fps_args

    return self.mvtools.FlowFPS(clip, super_clip, vect_b, vect_f, **flow_fps_args)

flow_interpolate

flow_interpolate(
    clip: VideoNode | None = None,
    super: VideoNode | None = None,
    vectors: MotionVectors | MVTools | None = None,
    time: float | None = None,
    ml: float | None = None,
    blend: bool | None = None,
    thscd: int | tuple[int | None, int | None] | None = None,
    interleave: bool = True,
) -> VideoNode

Motion interpolation function that creates an intermediate frame between two frames.

Uses both backward and forward motion vectors to estimate motion and create a frame at any time position between the current and next frame. Occlusion masks are used to handle areas where motion estimation fails, and time weighting ensures smooth blending between frames to minimize artifacts.

Parameters:

  • clip

    (VideoNode | None, default: None ) –

    The clip to process.

  • super

    (VideoNode | None, default: None ) –

    The multilevel super clip prepared by :py:attr:super. If None, super will be obtained from clip.

  • vectors

    (MotionVectors | MVTools | None, default: None ) –

    Motion vectors to use. Can be a MotionVectors object or another MVTools instance. If None, uses the vectors from this instance.

  • time

    (float | None, default: None ) –

    Time position between frames as a percentage (0.0-100.0). Controls the interpolation position between frames.

  • ml

    (float | None, default: None ) –

    Mask scale parameter that controls occlusion mask strength. Higher values produce weaker occlusion masks. Used in MakeVectorOcclusionMaskTime for modes 3-5. Used in MakeSADMaskTime for modes 6-8.

  • blend

    (bool | None, default: None ) –

    Whether to blend frames at scene changes. If True, frames will be blended. If False, frames will be copied.

  • thscd

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

    Scene change detection thresholds. First value is the block change threshold between frames. Second value is the number of changed blocks needed for a scene change.

  • interleave

    (bool, default: True ) –

    Whether to interleave the interpolated frames with the source clip.

Returns:

  • VideoNode

    Motion interpolated clip with frames created at the specified time position between input frames.

Source code
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
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
def flow_interpolate(
    self, clip: vs.VideoNode | None = None, super: vs.VideoNode | None = None,
    vectors: MotionVectors | MVTools | None = None, time: float | None = None,
    ml: float | None = None, blend: bool | None = None, thscd: int | tuple[int | None, int | None] | None = None,
    interleave: bool = True
) -> vs.VideoNode:
    """
    Motion interpolation function that creates an intermediate frame between two frames.

    Uses both backward and forward motion vectors to estimate motion and create a frame at any time position between
    the current and next frame. Occlusion masks are used to handle areas where motion estimation fails, and time
    weighting ensures smooth blending between frames to minimize artifacts.

    :param clip:          The clip to process.
    :param super:         The multilevel super clip prepared by :py:attr:`super`.
                          If None, super will be obtained from clip.
    :param vectors:       Motion vectors to use. Can be a MotionVectors object or another MVTools instance.
                          If None, uses the vectors from this instance.
    :param time:          Time position between frames as a percentage (0.0-100.0).
                          Controls the interpolation position between frames.
    :param ml:            Mask scale parameter that controls occlusion mask strength.
                          Higher values produce weaker occlusion masks.
                          Used in MakeVectorOcclusionMaskTime for modes 3-5.
                          Used in MakeSADMaskTime for modes 6-8.
    :param blend:         Whether to blend frames at scene changes.
                          If True, frames will be blended. If False, frames will be copied.
    :param thscd:         Scene change detection thresholds.
                          First value is the block change threshold between frames.
                          Second value is the number of changed blocks needed for a scene change.
    :param interleave:    Whether to interleave the interpolated frames with the source clip.

    :return:              Motion interpolated clip with frames created
                          at the specified time position between input frames.
    """

    clip = fallback(clip, self.clip)
    super_clip = self.get_super(fallback(super, clip))

    if isinstance(vectors, MVTools):
        vectors = vectors.vectors
    elif vectors is None:
        vectors = self.vectors

    vect_b, vect_f = self.get_vectors(self.vectors, tr=1)

    thscd1, thscd2 = normalize_thscd(thscd)

    flow_interpolate_args = self.flow_interpolate_args | KwargsNotNone(
        time=time, ml=ml, blend=blend, thscd1=thscd1, thscd2=thscd2
    )

    interpolated = self.mvtools.FlowInter(clip, super_clip, vect_b, vect_f, **flow_interpolate_args)

    if interleave:
        interpolated = core.std.Interleave([clip, interpolated])

    return interpolated

get_super

get_super(clip: VideoNode | None = None) -> VideoNode

Get the super clips from the specified clip.

If :py:attr:super wasn't previously called, it will do so here with default values or kwargs specified in the constructor.

Parameters:

  • clip

    (VideoNode | None, default: None ) –

    The clip to get the super clip from.

Returns:

  • VideoNode

    VideoNode containing the super clip.

Source code
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
def get_super(self, clip: vs.VideoNode | None = None) -> vs.VideoNode:
    """
    Get the super clips from the specified clip.

    If :py:attr:`super` wasn't previously called,
    it will do so here with default values or kwargs specified in the constructor.

    :param clip:    The clip to get the super clip from.

    :return:        VideoNode containing the super clip.
    """

    clip = fallback(clip, self.clip)

    try:
        super_clip = clip.std.PropToClip(prop='MSuper')
    except vs.Error:
        clip = self.super(clip)
        super_clip = clip.std.PropToClip(prop='MSuper')

    return super_clip

get_vectors

get_vectors(
    vectors: MotionVectors,
    *,
    direction: MVDirection = BOTH,
    tr: int | None = None
) -> tuple[list[VideoNode], list[VideoNode]]

Get the backwards and forward vectors.

Parameters:

  • vectors

    (MotionVectors) –

    The motion vectors to get the backwards and forward vectors from.

  • tr

    (int | None, default: None ) –

    The number of frames to get the vectors for.

Returns:

  • tuple[list[VideoNode], list[VideoNode]]

    A tuple containing two lists of motion vectors. The first list contains backward vectors and the second contains forward vectors.

Source code
1178
1179
1180
1181
1182
1183
1184
1185
1186
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
def get_vectors(
    self, vectors: MotionVectors, *,
    direction: MVDirection = MVDirection.BOTH,
    tr: int | None = None
) -> tuple[list[vs.VideoNode], list[vs.VideoNode]]:
    """
    Get the backwards and forward vectors.

    :param vectors:    The motion vectors to get the backwards and forward vectors from.
    :param tr:         The number of frames to get the vectors for.

    :return:           A tuple containing two lists of motion vectors.
                       The first list contains backward vectors and the second contains forward vectors.
    """

    if not vectors.has_vectors:
        raise CustomRuntimeError('You need to run analyze before getting motion vectors!', self.get_vectors)

    tr = fallback(tr, self.tr)

    vectors_backward = list[vs.VideoNode]()
    vectors_forward = list[vs.VideoNode]()

    if self.mvtools is MVToolsPlugin.FLOAT:
        vmulti = vectors.vmulti

        for i in range(0, tr * 2, 2):
            if direction in [MVDirection.BACK, MVDirection.BOTH]:
                vectors_backward.append(vmulti.std.SelectEvery(tr * 2, i))
            if direction in [MVDirection.FWRD, MVDirection.BOTH]:
                vectors_forward.append(vmulti.std.SelectEvery(tr * 2, i + 1))
    else:
        for i in range(1, tr + 1):
            if direction in [MVDirection.BACK, MVDirection.BOTH]:
                vectors_backward.append(vectors.get_mv(MVDirection.BACK, i))
            if direction in [MVDirection.FWRD, MVDirection.BOTH]:
                vectors_forward.append(vectors.get_mv(MVDirection.FWRD, i))

    return (vectors_backward, vectors_forward)

mask

mask(
    clip: VideoNode | None = None,
    vectors: MotionVectors | MVTools | None = None,
    direction: Literal[FWRD] | Literal[BACK] = BACK,
    delta: int = 1,
    ml: float | None = None,
    gamma: float | None = None,
    kind: MaskMode | None = None,
    time: float | None = None,
    ysc: int | None = None,
    thscd: int | tuple[int | None, int | None] | None = None,
) -> VideoNode

Creates a mask clip from motion vectors data.

Parameters:

  • clip

    (VideoNode | None, default: None ) –

    The clip to process. If None, the :py:attr:workclip attribute is used.

  • vectors

    (MotionVectors | MVTools | None, default: None ) –

    Motion vectors to use. Can be a MotionVectors object or another MVTools instance. If None, uses the vectors from this instance.

  • direction

    (Literal[FWRD] | Literal[BACK], default: BACK ) –

    Motion vector direction to use.

  • delta

    (int, default: 1 ) –

    Motion vector delta to use.

  • ml

    (float | None, default: None ) –

    Motion length scale factor. When the vector's length (or other mask value) is greater than or equal to ml, the output is saturated to 255.

  • gamma

    (float | None, default: None ) –

    Exponent for the relation between input and output values. 1.0 gives a linear relation, 2.0 gives a quadratic relation.

  • kind

    (MaskMode | None, default: None ) –

    Type of mask to generate. See :py:class:MaskMode for options.

  • time

    (float | None, default: None ) –

    Time position between frames as a percentage (0.0-100.0).

  • ysc

    (int | None, default: None ) –

    Value assigned to the mask on scene changes.

  • thscd

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

    Scene change detection thresholds. First value is the block change threshold between frames. Second value is the number of changed blocks needed for a scene change.

Returns:

  • VideoNode

    Motion mask clip.

Source code
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
def mask(
    self, clip: vs.VideoNode | None = None, vectors: MotionVectors | MVTools | None = None,
    direction: Literal[MVDirection.FWRD] | Literal[MVDirection.BACK] = MVDirection.BACK,
    delta: int = 1, ml: float | None = None, gamma: float | None = None,
    kind: MaskMode | None = None, time: float | None = None, ysc: int | None = None,
    thscd: int | tuple[int | None, int | None] | None = None
) -> vs.VideoNode:
    """
    Creates a mask clip from motion vectors data.

    :param clip:         The clip to process.
                         If None, the :py:attr:`workclip` attribute is used.
    :param vectors:      Motion vectors to use. Can be a MotionVectors object or another MVTools instance.
                         If None, uses the vectors from this instance.
    :param direction:    Motion vector direction to use.
    :param delta:        Motion vector delta to use.
    :param ml:           Motion length scale factor. When the vector's length (or other mask value)
                         is greater than or equal to ml, the output is saturated to 255.
    :param gamma:        Exponent for the relation between input and output values.
                         1.0 gives a linear relation, 2.0 gives a quadratic relation.
    :param kind:         Type of mask to generate. See :py:class:`MaskMode` for options.
    :param time:         Time position between frames as a percentage (0.0-100.0).
    :param ysc:          Value assigned to the mask on scene changes.
    :param thscd:        Scene change detection thresholds.
                         First value is the block change threshold between frames.
                         Second value is the number of changed blocks needed for a scene change.

    :return:             Motion mask clip.
    """

    clip = fallback(clip, self.clip)

    if isinstance(vectors, MVTools):
        vectors = vectors.vectors
    elif vectors is None:
        vectors = self.vectors

    vect = vectors.get_mv(direction, delta)

    thscd1, thscd2 = normalize_thscd(thscd)

    mask_args = self.mask_args | KwargsNotNone(
        ml=ml, gamma=gamma, kind=kind, time=time, ysc=ysc, thscd1=thscd1, thscd2=thscd2
    )

    mask_clip = depth(clip, 8) if self.mvtools is MVToolsPlugin.INTEGER else clip

    mask_clip = self.mvtools.Mask(mask_clip, vect, **mask_args)

    return depth(mask_clip, clip, range_in=ColorRange.FULL, range_out=ColorRange.FULL)

recalculate

recalculate(
    super: VideoNode | None = None,
    vectors: MotionVectors | MVTools | None = None,
    thsad: int | None = None,
    smooth: SmoothMode | None = None,
    blksize: int | tuple[int | None, int | None] | None = None,
    search: SearchMode | None = None,
    searchparam: int | None = None,
    lambda_: int | None = None,
    truemotion: MotionMode | None = None,
    pnew: int | None = None,
    overlap: int | tuple[int | None, int | None] | None = None,
    divide: bool | None = None,
    meander: bool | None = None,
    dct: SADMode | None = None,
) -> None

Refines and recalculates motion vectors that were previously estimated, optionally using a different super clip or parameters. This two-stage approach can provide more stable and robust motion estimation.

The refinement only occurs at the finest hierarchical level. It uses the interpolated vectors from the original blocks as predictors for the new vectors, and recalculates their SAD values.

Only vectors with poor quality (SAD above threshold) will be re-estimated through a new search. The SAD threshold is normalized to an 8x8 block size. Vectors with good quality are preserved, though their SAD values are still recalculated and updated.

Parameters:

  • super

    (VideoNode | None, default: None ) –

    The multilevel super clip prepared by :py:attr:super. If None, super will be obtained from clip.

  • vectors

    (MotionVectors | MVTools | None, default: None ) –

    Motion vectors to use. Can be a MotionVectors object or another MVTools instance. If None, uses the vectors from this instance.

  • thsad

    (int | None, default: None ) –

    Only bad quality new vectors with a SAD above thid will be re-estimated by search. thsad value is scaled to 8x8 block size.

  • blksize

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

    Size of blocks for motion estimation. Can be an int or tuple of (width, height). Larger blocks are less sensitive to noise and faster to process, but will produce less accurate vectors.

  • smooth

    (SmoothMode | None, default: None ) –

    This is method for dividing coarse blocks into smaller ones. Only used with the FLOAT MVTools plugin.

  • search

    (SearchMode | None, default: None ) –

    Search algorithm to use at the finest level. See :py:class:SearchMode for options.

  • searchparam

    (int | None, default: None ) –

    Additional parameter for the search algorithm. For NSTEP, this is the step size. For EXHAUSTIVE, EXHAUSTIVE_H, EXHAUSTIVE_V, HEXAGON and UMH, this is the search radius.

  • lambda_

    (int | None, default: None ) –

    Controls the coherence of the motion vector field. Higher values enforce more coherent/smooth motion between blocks. Too high values may cause the algorithm to miss the optimal vectors.

  • truemotion

    (MotionMode | None, default: None ) –

    Preset that controls the default values of motion estimation parameters to optimize for true motion. For more information, see :py:class:MotionMode.

  • pnew

    (int | None, default: None ) –

    Penalty multiplier (relative to 256) applied to the SAD cost when evaluating new candidate vectors. Higher values make the search more conservative.

  • overlap

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

    Block overlap value. Can be a single integer for both dimensions or a tuple of (horizontal, vertical) overlap values. Each value must be even and less than its corresponding block size dimension.

  • divide

    (bool | None, default: None ) –

    Whether to divide each block into 4 subblocks during post-processing. This may improve accuracy at the cost of performance.

  • meander

    (bool | None, default: None ) –

    Whether to use a meandering scan pattern when processing blocks. If True, alternates between left-to-right and right-to-left scanning between rows to improve motion coherence.

  • dct

    (SADMode | None, default: None ) –

    SAD calculation mode using block DCT (frequency spectrum) for comparing blocks. For more information, see :py:class:SADMode.

Source code
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
380
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
def recalculate(
    self, super: vs.VideoNode | None = None, vectors: MotionVectors | MVTools | None = None,
    thsad: int | None = None, smooth: SmoothMode | None = None,
    blksize: int | tuple[int | None, int | None] | None = None, search: SearchMode | None = None,
    searchparam: int | None = None, lambda_: int | None = None, truemotion: MotionMode | None = None,
    pnew: int | None = None, overlap: int | tuple[int | None, int | None] | None = None,
    divide: bool | None = None, meander: bool | None = None, dct: SADMode | None = None
) -> None:
    """
    Refines and recalculates motion vectors that were previously estimated, optionally using a different super clip or parameters.
    This two-stage approach can provide more stable and robust motion estimation.

    The refinement only occurs at the finest hierarchical level. It uses the interpolated vectors from the original blocks
    as predictors for the new vectors, and recalculates their SAD values.

    Only vectors with poor quality (SAD above threshold) will be re-estimated through a new search.
    The SAD threshold is normalized to an 8x8 block size. Vectors with good quality are preserved,
    though their SAD values are still recalculated and updated.

    :param super:          The multilevel super clip prepared by :py:attr:`super`.
                           If None, super will be obtained from clip.
    :param vectors:        Motion vectors to use. Can be a MotionVectors object or another MVTools instance.
                           If None, uses the vectors from this instance.
    :param thsad:          Only bad quality new vectors with a SAD above thid will be re-estimated by search.
                           thsad value is scaled to 8x8 block size.
    :param blksize:        Size of blocks for motion estimation. Can be an int or tuple of (width, height).
                           Larger blocks are less sensitive to noise and faster to process, but will produce less accurate vectors.
    :param smooth:         This is method for dividing coarse blocks into smaller ones.
                           Only used with the FLOAT MVTools plugin.
    :param search:         Search algorithm to use at the finest level. See :py:class:`SearchMode` for options.
    :param searchparam:    Additional parameter for the search algorithm. For NSTEP, this is the step size.
                           For EXHAUSTIVE, EXHAUSTIVE_H, EXHAUSTIVE_V, HEXAGON and UMH, this is the search radius.
    :param lambda_:        Controls the coherence of the motion vector field.
                           Higher values enforce more coherent/smooth motion between blocks.
                           Too high values may cause the algorithm to miss the optimal vectors.
    :param truemotion:     Preset that controls the default values of motion estimation parameters to optimize for true motion.
                           For more information, see :py:class:`MotionMode`.
    :param pnew:           Penalty multiplier (relative to 256) applied to the SAD cost when evaluating new candidate vectors.
                           Higher values make the search more conservative.
    :param overlap:        Block overlap value. Can be a single integer for both dimensions or a tuple of (horizontal, vertical) overlap values.
                           Each value must be even and less than its corresponding block size dimension.
    :param divide:         Whether to divide each block into 4 subblocks during post-processing.
                           This may improve accuracy at the cost of performance.
    :param meander:        Whether to use a meandering scan pattern when processing blocks.
                           If True, alternates between left-to-right and right-to-left scanning between rows to improve motion coherence.
    :param dct:            SAD calculation mode using block DCT (frequency spectrum) for comparing blocks.
                           For more information, see :py:class:`SADMode`.
    """

    super_clip = self.get_super(fallback(super, self.search_clip))

    if isinstance(vectors, MVTools):
        vectors = vectors.vectors
    elif vectors is None:
        vectors = self.vectors

    if not vectors.has_vectors:
        raise CustomRuntimeError('You must run `analyze` before `recalculate`!', self.recalculate)

    blksize, blksizev = normalize_seq(blksize, 2)
    overlap, overlapv = normalize_seq(overlap, 2)

    recalculate_args = self.recalculate_args | KwargsNotNone(
        thsad=thsad, smooth=smooth, blksize=blksize, blksizev=blksizev, search=search, searchparam=searchparam,
        lambda_=lambda_, chroma=self.chroma, truemotion=truemotion, pnew=pnew, overlap=overlap, overlapv=overlapv,
        divide=divide, meander=meander, fields=self.fieldbased.is_inter, tff=self.fieldbased.is_tff, dct=dct
    )

    if self.mvtools is MVToolsPlugin.INTEGER and not any(
        (recalculate_args.get('overlap'), recalculate_args.get('overlapv'))
    ):
        self.disable_compensate = True

    if self.mvtools is MVToolsPlugin.FLOAT:
        vectors.vmulti = self.mvtools.Recalculate(super_clip, vectors=vectors.vmulti, **recalculate_args)
    else:
        for i in range(1, self.tr + 1):
            for direction in MVDirection:
                vector = self.mvtools.Recalculate(super_clip, vectors.get_mv(direction, i), **recalculate_args)
                vectors.set_mv(direction, i, vector)

        vectors.analysis_data.clear()

sc_detection

sc_detection(
    clip: VideoNode | None = None,
    vectors: MotionVectors | MVTools | None = None,
    delta: int = 1,
    thscd: int | tuple[int | None, int | None] | None = None,
) -> VideoNode

Creates scene detection mask clip from motion vectors data.

Parameters:

  • clip

    (VideoNode | None, default: None ) –

    The clip to process. If None, the :py:attr:workclip attribute is used.

  • vectors

    (MotionVectors | MVTools | None, default: None ) –

    Motion vectors to use. Can be a MotionVectors object or another MVTools instance. If None, uses the vectors from this instance.

  • delta

    (int, default: 1 ) –

    Motion vector delta to use.

  • thscd

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

    Scene change detection thresholds. First value is the block change threshold between frames. Second value is the number of changed blocks needed for a scene change.

Returns:

  • VideoNode

    Clip with scene change properties set.

Source code
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
def sc_detection(
    self, clip: vs.VideoNode | None = None, vectors: MotionVectors | MVTools | None = None,
    delta: int = 1, thscd: int | tuple[int | None, int | None] | None = None
) -> vs.VideoNode:
    """
    Creates scene detection mask clip from motion vectors data.

    :param clip:       The clip to process.
                       If None, the :py:attr:`workclip` attribute is used.
    :param vectors:    Motion vectors to use. Can be a MotionVectors object or another MVTools instance.
                       If None, uses the vectors from this instance.
    :param delta:      Motion vector delta to use.
    :param thscd:      Scene change detection thresholds.
                       First value is the block change threshold between frames.
                       Second value is the number of changed blocks needed for a scene change.

    :return:           Clip with scene change properties set.
    """

    clip = fallback(clip, self.clip)

    if isinstance(vectors, MVTools):
        vectors = vectors.vectors
    elif vectors is None:
        vectors = self.vectors

    thscd1, thscd2 = normalize_thscd(thscd)

    sc_detection_args = self.sc_detection_args | KwargsNotNone(thscd1=thscd1, thscd2=thscd2)

    detect = clip
    for direction in MVDirection:
        detect = self.mvtools.SCDetection(detect, vectors.get_mv(direction, delta), **sc_detection_args)

    return detect

scale_vectors

scale_vectors(
    scale: int | tuple[int, int],
    vectors: MotionVectors | MVTools | None = None,
    strict: bool = True,
) -> None

Scales image_size, block_size, overlap, padding, and the individual motion_vectors contained in Analyse output by arbitrary and independent x and y factors.

Parameters:

  • scale

    (int | tuple[int, int]) –

    Factor to scale motion vectors by.

  • vectors

    (MotionVectors | MVTools | None, default: None ) –

    Motion vectors to use. Can be a MotionVectors object or another MVTools instance. If None, uses the vectors from this instance.

Source code
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
def scale_vectors(
        self, scale: int | tuple[int, int], vectors: MotionVectors | MVTools | None = None, strict: bool = True
    ) -> None:
    """
    Scales image_size, block_size, overlap, padding, and the individual motion_vectors contained in Analyse output
    by arbitrary and independent x and y factors.

    :param scale:      Factor to scale motion vectors by.
    :param vectors:    Motion vectors to use. Can be a MotionVectors object or another MVTools instance.
                       If None, uses the vectors from this instance.
    """

    if self.disable_manipmv:
        raise CustomRuntimeError(
            f'Motion vector manipulation not supported with {self.mvtools}!', self.scale_vectors
        )

    if isinstance(vectors, MVTools):
        vectors = vectors.vectors
    elif vectors is None:
        vectors = self.vectors

    scalex, scaley = normalize_seq(scale, 2)

    supported_blksize = (
        (4, 4), (8, 4), (8, 8), (16, 2), (16, 8), (16, 16), (32, 16),
        (32, 32), (64, 32), (64, 64), (128, 64), (128, 128)
    )

    if scalex > 1 and scaley > 1:
        self.expand_analysis_data(vectors)

        blksize, blksizev = vectors.analysis_data['Analysis_BlockSize']

        scaled_blksize = (blksize * scalex, blksizev * scaley)

        if strict and scaled_blksize not in supported_blksize:
            raise CustomRuntimeError('Unsupported block size!', self.scale_vectors)

        for i in range(1, self.tr + 1):
            for direction in MVDirection:
                vector = vectors.get_mv(direction, i).manipmv.ScaleVect(scalex, scaley)
                vectors.set_mv(direction, i, vector)

        self.clip = self.clip.std.RemoveFrameProps('MSuper')
        self.search_clip = self.search_clip.std.RemoveFrameProps('MSuper')

        vectors.analysis_data.clear()
        vectors.scaled = True

show_vector

show_vector(
    clip: VideoNode | None = None,
    vectors: MotionVectors | MVTools | None = None,
    direction: Literal[FWRD] | Literal[BACK] = BACK,
    delta: int = 1,
    scenechange: bool | None = None,
) -> VideoNode

Draws generated vectors onto a clip.

Parameters:

  • clip

    (VideoNode | None, default: None ) –

    The clip to overlay the motion vectors on.

  • vectors

    (MotionVectors | MVTools | None, default: None ) –

    Motion vectors to use. Can be a MotionVectors object or another MVTools instance. If None, uses the vectors from this instance.

  • direction

    (Literal[FWRD] | Literal[BACK], default: BACK ) –

    Motion vector direction to use.

  • delta

    (int, default: 1 ) –

    Motion vector delta to use.

  • scenechange

    (bool | None, default: None ) –

    Skips drawing vectors if frame props indicate they are from a different scene than the current frame of the clip.

Returns:

  • VideoNode

    Clip with motion vectors overlaid.

Source code
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
1115
1116
1117
1118
1119
1120
1121
def show_vector(
    self, clip: vs.VideoNode | None = None, vectors: MotionVectors | MVTools | None = None,
    direction: Literal[MVDirection.FWRD] | Literal[MVDirection.BACK] = MVDirection.BACK,
    delta: int = 1, scenechange: bool | None = None
) -> vs.VideoNode:
    """
    Draws generated vectors onto a clip.

    :param clip:           The clip to overlay the motion vectors on.
    :param vectors:        Motion vectors to use. Can be a MotionVectors object or another MVTools instance.
                           If None, uses the vectors from this instance.
    :param direction:      Motion vector direction to use.
    :param delta:          Motion vector delta to use.
    :param scenechange:    Skips drawing vectors if frame props indicate they are from a different scene
                           than the current frame of the clip.

    :return:               Clip with motion vectors overlaid.
    """

    if self.disable_manipmv:
        raise CustomRuntimeError(f'Motion vector manipulation not supported with {self.mvtools}!', self.show_vector)

    clip = fallback(clip, self.clip)

    if isinstance(vectors, MVTools):
        vectors = vectors.vectors
    elif vectors is None:
        vectors = self.vectors

    vect = vectors.get_mv(direction, delta)

    return clip.manipmv.ShowVect(vect, scenechange)

super

super(
    clip: VideoNode | None = None,
    vectors: MotionVectors | MVTools | None = None,
    levels: int | None = None,
    sharp: SharpMode | None = None,
    rfilter: RFilterMode | None = None,
    pelclip: VideoNode | VSFunction | None = None,
) -> VideoNode

Get source clip and prepare special "super" clip with multilevel (hierarchical scaled) frames data. The super clip is used by both :py:attr:analyze and motion compensation (client) functions.

You can use different Super clip for generation vectors with :py:attr:analyze and a different super clip format for the actual action. Source clip is appended to clip's frameprops, :py:attr:get_super can be used to extract the super clip if you wish to view it yourself.

Parameters:

  • clip

    (VideoNode | None, default: None ) –

    The clip to process. If None, the :py:attr:clip attribute is used.

  • vectors

    (MotionVectors | MVTools | None, default: None ) –

    Motion vectors to use. Can be a MotionVectors object or another MVTools instance. If None, uses the vectors from this instance.

  • levels

    (int | None, default: None ) –

    The number of hierarchical levels in super clip frames. More levels are needed for :py:attr:analyze to get better vectors, but fewer levels are needed for the actual motion compensation. 0 = auto, all possible levels are produced.

  • sharp

    (SharpMode | None, default: None ) –

    Subpixel interpolation method if pel is 2 or 4. For more information, see :py:class:SharpMode.

  • rfilter

    (RFilterMode | None, default: None ) –

    Hierarchical levels smoothing and reducing (halving) filter. For more information, see :py:class:RFilterMode.

  • pelclip

    (VideoNode | VSFunction | None, default: None ) –

    Optional upsampled source clip to use instead of internal subpixel interpolation (if pel > 1). The clip must contain the original source pixels at positions that are multiples of pel (e.g., positions 0, 2, 4, etc. for pel=2), with interpolated pixels in between. The clip should not be padded.

Returns:

  • VideoNode

    The original clip with the super clip attached as a frame property.

Source code
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
def super(
    self, clip: vs.VideoNode | None = None, vectors: MotionVectors | MVTools | None = None, 
    levels: int | None = None, sharp: SharpMode | None = None,
    rfilter: RFilterMode | None = None, pelclip: vs.VideoNode | VSFunction | None = None
) -> vs.VideoNode:
    """
    Get source clip and prepare special "super" clip with multilevel (hierarchical scaled) frames data.
    The super clip is used by both :py:attr:`analyze` and motion compensation (client) functions.

    You can use different Super clip for generation vectors with :py:attr:`analyze` and a different super clip format for the actual action.
    Source clip is appended to clip's frameprops, :py:attr:`get_super` can be used to extract the super clip if you wish to view it yourself.

    :param clip:       The clip to process. If None, the :py:attr:`clip` attribute is used.
    :param vectors:    Motion vectors to use. Can be a MotionVectors object or another MVTools instance.
                       If None, uses the vectors from this instance.
    :param levels:     The number of hierarchical levels in super clip frames.
                       More levels are needed for :py:attr:`analyze` to get better vectors,
                       but fewer levels are needed for the actual motion compensation.
                       0 = auto, all possible levels are produced.
    :param sharp:      Subpixel interpolation method if pel is 2 or 4.
                       For more information, see :py:class:`SharpMode`.
    :param rfilter:    Hierarchical levels smoothing and reducing (halving) filter.
                       For more information, see :py:class:`RFilterMode`.
    :param pelclip:    Optional upsampled source clip to use instead of internal subpixel interpolation (if pel > 1).
                       The clip must contain the original source pixels at positions that are multiples of pel
                       (e.g., positions 0, 2, 4, etc. for pel=2), with interpolated pixels in between.
                       The clip should not be padded.

    :return:           The original clip with the super clip attached as a frame property.
    """

    clip = fallback(clip, self.clip)

    if isinstance(vectors, MVTools):
        vectors = vectors.vectors
    elif vectors is None:
        vectors = self.vectors

    if vectors.scaled:
        self.expand_analysis_data(vectors)

        hpad, vpad = vectors.analysis_data['Analysis_Padding']
    else:
        hpad, vpad = self.pad

    if callable(pelclip):
        pelclip = pelclip(clip)

    super_args = self.super_args | KwargsNotNone(
        hpad=hpad, vpad=vpad, pel=self.pel, levels=levels, chroma=self.chroma,
        sharp=sharp, rfilter=rfilter, pelclip=pelclip
    )

    super_clip = self.mvtools.Super(clip, **super_args)

    super_clip = clip.std.ClipToProp(super_clip, prop='MSuper')

    if clip is self.clip:
        self.clip = super_clip
    if clip is self.search_clip:
        self.search_clip = super_clip

    return super_clip