Skip to content

motion

Classes:

  • MotionVectors –

    Class for storing and managing motion vectors for a video clip.

MotionVectors

MotionVectors(
    blksize: int | tuple[int, int] | None = None,
    overlap_div: int | tuple[int, int] | None = None,
)

Bases: VSObject, defaultdict[MVDirection, dict[int, VideoNode]]

Class for storing and managing motion vectors for a video clip.

Contains both backward and forward motion vectors.

Methods:

  • analysis_data –
  • clear –

    Clear all stored motion vectors.

  • get_vector –

    Get a single motion vector.

  • get_vectors –

    Get the backward and forward vectors.

  • scale_vectors –

    Scales image_size, block_size, overlap, padding, and the individual motion_vectors contained in Analyse output

  • set_vector –

    Store a motion vector.

  • show_vector –

    Draws generated vectors onto a clip.

Attributes:

Source code in vsdenoise/mvtools/motion.py
25
26
27
28
29
30
31
32
33
34
35
def __init__(
    self,
    blksize: int | tuple[int, int] | None = None,
    overlap_div: int | tuple[int, int] | None = None,
) -> None:
    super().__init__(None, {w: {} for w in MVDirection})
    self.scaled = False
    self._blksize: tuple[int, int] | None = None
    self._overlap_div: tuple[int, int] | None = None
    self.blksize = blksize
    self.overlap_div = overlap_div

blksize property writable

blksize: tuple[int, int] | None

deltas property

deltas: list[int]

List of active deltas.

has_vectors property

has_vectors: bool

Whether any motion vectors have been stored.

overlap_div property writable

overlap_div: tuple[int, int] | None

scaled instance-attribute

scaled = False

tr property

tr: int

Temporal radius of the motion vectors.

analysis_data

analysis_data() -> None
Source code in vsdenoise/mvtools/motion.py
194
195
196
@analysis_data.deleter  # type: ignore[no-redef]
def analysis_data(self) -> None:
    cachedproperty.clear_cache(self, "analysis_data")

clear

clear() -> None

Clear all stored motion vectors.

Source code in vsdenoise/mvtools/motion.py
81
82
83
84
85
86
87
88
89
90
91
def clear(self) -> None:
    """
    Clear all stored motion vectors.
    """

    for v in self.values():
        v.clear()

    self._blksize = None
    self._overlap_div = None
    cachedproperty.clear_cache(self)

get_vector

get_vector(direction: MVDirection, delta: int) -> VideoNode

Get a single motion vector.

Parameters:

  • direction

    (MVDirection) –

    Motion vector direction to get.

  • delta

    (int) –

    Motion vector delta to get.

Returns:

  • VideoNode –

    A single motion vector VideoNode

Source code in vsdenoise/mvtools/motion.py
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
def get_vector(self, direction: MVDirection, delta: int) -> vs.VideoNode:
    """
    Get a single motion vector.

    Args:
        direction: Motion vector direction to get.
        delta: Motion vector delta to get.

    Returns:
        A single motion vector VideoNode
    """

    if delta not in self[direction]:
        raise CustomRuntimeError(
            "Tried to get a motion vector delta that does not exist!", self.get_vector, f"{delta}"
        )

    return self[direction][delta]

get_vectors

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

Get the backward and forward vectors.

Parameters:

  • direction

    (MVDirection, default: BOTH ) –

    Motion vector direction to get.

  • tr

    (int | None, default: None ) –

    The number of frames to get the vectors for.

  • delta

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

    Specific delta(s) of motion vectors to retrieve.

Returns:

  • list[VideoNode] –

    A tuple containing two lists of motion vectors.

  • list[VideoNode] –

    The first list contains backward vectors and the second contains forward vectors.

Source code in vsdenoise/mvtools/motion.py
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
def get_vectors(
    self,
    direction: MVDirection = MVDirection.BOTH,
    tr: int | None = None,
    delta: int | Sequence[int] | None = None,
) -> tuple[list[vs.VideoNode], list[vs.VideoNode]]:
    """
    Get the backward and forward vectors.

    Args:
        direction: Motion vector direction to get.
        tr: The number of frames to get the vectors for.
        delta: Specific delta(s) of motion vectors to retrieve.

    Returns:
        A tuple containing two lists of motion vectors.
        The first list contains backward vectors and the second contains forward vectors.
    """
    if delta is not None:
        deltas = to_arr(delta)
    elif tr is not None:
        deltas = range(1, tr + 1)
    else:
        deltas = self.deltas

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

    for d in deltas:
        if direction in [MVDirection.BACKWARD, MVDirection.BOTH] and d in self[MVDirection.BACKWARD]:
            vectors_backward.append(self[MVDirection.BACKWARD][d])
        if direction in [MVDirection.FORWARD, MVDirection.BOTH] and d in self[MVDirection.FORWARD]:
            vectors_forward.append(self[MVDirection.FORWARD][d])

    if not vectors_backward and not vectors_forward:
        raise CustomRuntimeError(
            "No motion vectors available! Did you forget to call analyze()?",
            func=self.get_vectors,
            reason={"direction": direction, "deltas": list(deltas)},
        )

    return (vectors_backward, vectors_forward)

scale_vectors

scale_vectors(scale: int | tuple[int, int], 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:

Source code in vsdenoise/mvtools/motion.py
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
def scale_vectors(self, scale: int | tuple[int, int], 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.

    Args:
        scale: Factor to scale motion vectors by.
    """
    # 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),
    # )

    # scalex, scaley = normalize_seq(scale, 2)

    # if scalex > 1 or scaley > 1:
    #     blksizex, blksizev = self.analysis_data["Analysis_BlockSize"]

    #     scaled_blksize = (blksizex * scalex, blksizev * scaley)

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

    #     del self.analysis_data
    #     self.scaled = True

    #     for delta in range(1, self.tr + 1):
    #         for direction in MVDirection:
    #             self[direction][delta] = self[direction][delta].manipmv.ScaleVect(scalex, scaley)
    raise NotImplementedError("scale_vectors is not supported with MVUtensils.")

set_vector

set_vector(vector: VideoNode, direction: MVDirection, delta: int) -> None

Store a motion vector.

Parameters:

  • vector

    (VideoNode) –

    Motion vector clip to store.

  • direction

    (MVDirection) –

    Direction of the motion vector (forward or backward).

  • delta

    (int) –

    Frame distance for the motion vector.

Source code in vsdenoise/mvtools/motion.py
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
def set_vector(self, vector: vs.VideoNode, direction: MVDirection, delta: int) -> None:
    """
    Store a motion vector.

    Args:
        vector: Motion vector clip to store.
        direction: Direction of the motion vector (forward or backward).
        delta: Frame distance for the motion vector.
    """

    self[direction][delta] = vector

show_vector

show_vector(
    clip: VideoNode,
    direction: Literal[FORWARD, BACKWARD] = FORWARD,
    delta: int = 1,
    scenechange: bool | None = None,
) -> VideoNode

Draws generated vectors onto a clip.

Parameters:

  • clip

    (VideoNode) –

    The clip to overlay the motion vectors on.

  • direction

    (Literal[FORWARD, BACKWARD], default: FORWARD ) –

    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 in vsdenoise/mvtools/motion.py
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
def show_vector(
    self,
    clip: vs.VideoNode,
    direction: Literal[MVDirection.FORWARD, MVDirection.BACKWARD] = MVDirection.FORWARD,
    delta: int = 1,
    scenechange: bool | None = None,
) -> vs.VideoNode:
    """
    Draws generated vectors onto a clip.

    Args:
        clip: The clip to overlay the motion vectors on.
        direction: Motion vector direction to use.
        delta: Motion vector delta to use.
        scenechange: Skips drawing vectors if frame props indicate they are from a different scene than the current
            frame of the clip.

    Returns:
        Clip with motion vectors overlaid.
    """
    # vect = self.get_vector(direction, delta)

    # return clip.manipmv.ShowVect(vect, scenechange)

    raise NotImplementedError("show_vector is not supported with MVUtensils.")