Skip to content

fft

FilterTypeT module-attribute

Frequency module-attribute

Frequency: TypeAlias = float

SLocBoundT module-attribute

SLocBoundT = TypeVar('SLocBoundT', bound=SLocation)

SLocT module-attribute

SLocT = SLocationT | MultiDim

SLocationT module-attribute

Sigma module-attribute

Sigma: TypeAlias = float

SynthesisTypeT module-attribute

BackendInfo

BackendInfo(backend: Backend, **kwargs: Any)

Bases: KwargsT

Source code
357
358
359
360
def __init__(self, backend: DFTTest.Backend, **kwargs: Any) -> None:
    super().__init__(**kwargs)

    self.backend = backend

backend instance-attribute

backend: Backend = backend

num_streams instance-attribute

num_streams: int

resolved_backend property

resolved_backend: Backend

__call__

__call__(
    clip: VideoNode,
    sloc: SLocT | None = None,
    ftype: FilterTypeT | None = None,
    block_size: int | None = None,
    overlap: int | None = None,
    tr: int | None = None,
    tr_overlap: int | None = None,
    swin: SynthesisTypeT | None = None,
    twin: SynthesisTypeT | None = None,
    zmean: bool | None = None,
    alpha: float | None = None,
    ssystem: int | None = None,
    blockwise: bool = True,
    planes: PlanesT = None,
    *,
    func: FuncExceptT | None = None,
    default_args: KwargsT | None = None,
    **dkwargs: Any
) -> VideoNode
Source code
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
def __call__(
    self, clip: vs.VideoNode, sloc: SLocT | None = None,
    ftype: FilterTypeT | None = None,
    block_size: int | None = None, overlap: int | None = None,
    tr: int | None = None, tr_overlap: int | None = None,
    swin: SynthesisTypeT | None = None,
    twin: SynthesisTypeT | None = None,
    zmean: bool | None = None, alpha: float | None = None, ssystem: int | None = None,
    blockwise: bool = True, planes: PlanesT = None, *, func: FuncExceptT | None = None,
    default_args: KwargsT | None = None, **dkwargs: Any
) -> vs.VideoNode:
    func = func or self.__class__

    assert check_variable(clip, func)

    Backend = DFTTest.Backend

    kwargs: KwargsT = KwargsT(
        ftype=ftype, swin=swin, sbsize=block_size, sosize=overlap, tbsize=((tr or 0) * 2) + 1,
        tosize=tr_overlap, twin=twin, zmean=zmean, alpha=alpha, ssystem=ssystem,
        planes=planes, smode=int(blockwise)
    )

    if isinstance(sloc, SLocation.MultiDim):
        kwargs |= KwargsT(ssx=sloc._horizontal, ssy=sloc._vertical, sst=sloc._temporal)
    else:
        kwargs |= KwargsT(slocation=SLocation.from_param(sloc))

    clean_dft_args = KwargsNotNone(default_args or {}) | KwargsNotNone(kwargs)

    dft_args: KwargsT = KwargsT()

    for key, value in clean_dft_args.items():
        if isinstance(value, Enum) and callable(value):
            value = value()

        if isinstance(value, SynthesisTypeWithInfo):
            value = value.to_dict(key[0])

        if isinstance(value, dict):
            dft_args |= value
            continue

        if key == 'nlocation' and value:
            value = cast(Sequence[NLocation | int], value)
            value = list[int](flatten(value))

        if isinstance(value, SLocation):
            value = list(value)

        if isinstance(value, Enum):
            value = value.value

        dft_args[key] = value

    backend = self.resolved_backend

    if backend.is_dfttest2:
        from dfttest2 import Backend as DFTBackend
        from dfttest2 import DFTTest as DFTTest2  # noqa

        dft2_backend = None

        if backend is Backend.NVRTC:
            num_streams = dkwargs.pop('num_streams', self.num_streams if hasattr(self, 'num_streams') else 1)
            dft2_backend = DFTBackend.NVRTC(**(dict(**self) | dict(num_streams=num_streams)))
        elif backend is Backend.cuFFT:
            dft2_backend = DFTBackend.cuFFT(**self)
        elif backend is Backend.CPU:
            dft2_backend = DFTBackend.CPU(**self)
        elif backend is Backend.GCC:
            dft2_backend = DFTBackend.GCC(**self)

        if dft_args.get('tmode') is not None:
            raise CustomValueError('{backend} doesn\'t support tmode', func, backend=backend)

        if dft_args.pop('tosize'):
            raise CustomValueError('{backend} doesn\'t support tosize', func, backend=backend)

        return DFTTest2(clip, **dft_args | dkwargs, backend=dft2_backend)  # type: ignore[no-any-return]

    dft_args |= self

    if backend is Backend.OLD:
        return core.dfttest.DFTTest(clip, **dft_args)

    if backend is Backend.NEO:
        return core.neo_dfttest.DFTTest(clip, **dft_args)  # type: ignore

    if any(hasattr(core, x) for x in ('dfttest2_cpu', 'dfttest2_cuda', 'dfttest2_nvrtc')):
        raise CustomRuntimeError(
            'dfttest2 plugin is installed but is missing the python package, please install it.', self.__class__
        )

    raise CustomRuntimeError(
        'No implementation of DFTTest could be found, please install one. dfttest2 is recommended.', self.__class__
    )

from_param classmethod

from_param(value: Backend | BackendInfo) -> BackendInfo
Source code
362
363
364
@classmethod
def from_param(cls, value: DFTTest.Backend | BackendInfo) -> BackendInfo:
    return value() if isinstance(value, DFTTest.Backend) else value

DFTTest

DFTTest(
    clip: VideoNode | None = None,
    plugin: Backend | BackendInfo = AUTO,
    sloc: SLocT | None = None,
    **kwargs: Any
)

2D/3D frequency domain denoiser.

Source code
544
545
546
547
548
549
550
551
552
553
def __init__(
    self, clip: vs.VideoNode | None = None, plugin: Backend | BackendInfo = Backend.AUTO,
    sloc: SLocT | None = None, **kwargs: Any
) -> None:
    self.clip = clip

    self.plugin = BackendInfo.from_param(plugin)

    self.default_args = kwargs.copy()
    self.default_slocation = sloc

clip instance-attribute

clip = clip

default_args instance-attribute

default_args = copy()

default_slocation instance-attribute

default_slocation = sloc

plugin instance-attribute

plugin = from_param(plugin)

Backend

Bases: CustomIntEnum

AUTO class-attribute instance-attribute

AUTO = auto()

CPU class-attribute instance-attribute

CPU = auto()

GCC class-attribute instance-attribute

GCC = auto()

NEO class-attribute instance-attribute

NEO = auto()

NVRTC class-attribute instance-attribute

NVRTC = auto()

OLD class-attribute instance-attribute

OLD = auto()

cuFFT class-attribute instance-attribute

cuFFT = auto()

is_dfttest2 property

is_dfttest2: bool

__call__

__call__(*, opt: int = ...) -> BackendInfo
__call__(
    *,
    threads: int = ...,
    fft_threads: int = ...,
    opt: int = ...,
    dither: int = ...
) -> BackendInfo
__call__(*, device_id: int = 0, in_place: bool = True) -> BackendInfo
__call__(*, device_id: int = 0, num_streams: int = 1) -> BackendInfo
__call__() -> BackendInfo
__call__(**kwargs: Any) -> BackendInfo
__call__(**kwargs: Any) -> BackendInfo
Source code
537
538
def __call__(self, **kwargs: Any) -> BackendInfo:
    return BackendInfo(self, **kwargs)

denoise

denoise(
    ref: VideoNode,
    sloc: SLocT | None = None,
    /,
    ftype: FilterTypeT = WIENER,
    tr: int = 0,
    tr_overlap: int = 0,
    swin: SynthesisTypeT = HANNING,
    twin: SynthesisTypeT = RECTANGULAR,
    block_size: int = 16,
    overlap: int = 12,
    zmean: bool = True,
    alpha: float | None = None,
    ssystem: int = 0,
    blockwise: bool = True,
    planes: PlanesT = None,
    func: FuncExceptT | None = None,
    **kwargs: Any,
) -> VideoNode
denoise(
    sloc: SLocT,
    /,
    *,
    ftype: FilterTypeT = WIENER,
    tr: int = 0,
    tr_overlap: int = 0,
    swin: SynthesisTypeT = HANNING,
    twin: SynthesisTypeT = RECTANGULAR,
    block_size: int = 16,
    overlap: int = 12,
    zmean: bool = True,
    alpha: float | None = None,
    ssystem: int = 0,
    blockwise: bool = True,
    planes: PlanesT = None,
    func: FuncExceptT | None = None,
    **kwargs: Any,
) -> VideoNode
denoise(
    ref_or_sloc: VideoNode | SLocT,
    sloc: SLocT | None = None,
    /,
    ftype: FilterTypeT = WIENER,
    tr: int = 0,
    tr_overlap: int = 0,
    swin: SynthesisTypeT = HANNING,
    twin: SynthesisTypeT = RECTANGULAR,
    block_size: int = 16,
    overlap: int = 12,
    zmean: bool = True,
    alpha: float | None = None,
    ssystem: int = 0,
    blockwise: bool = True,
    planes: PlanesT = None,
    func: FuncExceptT | None = None,
    **kwargs: Any,
) -> VideoNode
Source code
584
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
@inject_self
def denoise(
    self, ref_or_sloc: vs.VideoNode | SLocT, sloc: SLocT | None = None, /,
    ftype: FilterTypeT = FilterType.WIENER,
    tr: int = 0, tr_overlap: int = 0,
    swin: SynthesisTypeT = SynthesisType.HANNING,
    twin: SynthesisTypeT = SynthesisType.RECTANGULAR,
    block_size: int = 16, overlap: int = 12,
    zmean: bool = True, alpha: float | None = None, ssystem: int = 0,
    blockwise: bool = True, planes: PlanesT = None, func: FuncExceptT | None = None, **kwargs: Any
) -> vs.VideoNode:
    func = func or self.denoise

    clip = self.clip
    nsloc = self.default_slocation

    if isinstance(ref_or_sloc, vs.VideoNode):
        clip = ref_or_sloc
    else:
        nsloc = ref_or_sloc

    if sloc is not None:
        nsloc = sloc

    if clip is None:
        raise CustomValueError('You must pass a clip!', func)

    if (fb := FieldBased.from_video(clip, False, func)).is_inter:
        raise UnsupportedFieldBasedError('Interlaced input is not supported!', func, fb)

    return self.plugin(
        clip, nsloc, func=func, **(self.default_args | dict(
            ftype=ftype, block_size=block_size, overlap=overlap, tr=tr, tr_overlap=tr_overlap, swin=swin,
            twin=twin, zmean=zmean, alpha=alpha, ssystem=ssystem, blockwise=blockwise, planes=planes
        ) | kwargs)
    )

extract_freq

extract_freq(clip: VideoNode, sloc: SLocT, **kwargs: Any) -> VideoNode
Source code
621
622
623
624
@inject_self
def extract_freq(self, clip: vs.VideoNode, sloc: SLocT, **kwargs: Any) -> vs.VideoNode:
    kwargs = dict(func=self.extract_freq) | kwargs
    return clip.std.MakeDiff(self.denoise(clip, sloc, **kwargs))

insert_freq

insert_freq(
    low: VideoNode, high: VideoNode, sloc: SLocT, **kwargs: Any
) -> VideoNode
Source code
626
627
628
@inject_self
def insert_freq(self, low: vs.VideoNode, high: vs.VideoNode, sloc: SLocT, **kwargs: Any) -> vs.VideoNode:
    return low.std.MergeDiff(self.extract_freq(high, sloc, **dict(func=self.insert_freq) | kwargs))

merge_freq

merge_freq(
    low: VideoNode, high: VideoNode, sloc: SLocT, **kwargs: Any
) -> VideoNode
Source code
630
631
632
633
634
@inject_self
def merge_freq(self, low: vs.VideoNode, high: vs.VideoNode, sloc: SLocT, **kwargs: Any) -> vs.VideoNode:
    return self.insert_freq(
        self.denoise(low, sloc, **kwargs), high, sloc, **dict(func=self.merge_freq) | kwargs
    )

FilterType

Bases: CustomIntEnum

Filtering types for DFTTest.

MULT class-attribute instance-attribute

MULT = 2

mult = sigma

MULT_PSD class-attribute instance-attribute

MULT_PSD = 3

mult = (psd >= pmin && psd <= pmax) ? sigma : sigma2

MULT_RANGE class-attribute instance-attribute

MULT_RANGE = 4

mult = sigma * sqrt((psd * pmax) / ((psd + pmin) * (psd + pmax)))

THR class-attribute instance-attribute

THR = 1

mult = psd < sigma ? 0.0 : 1.0

WIENER class-attribute instance-attribute

WIENER = 0

mult = max((psd - sigma) / psd, 0) ^ f0beta

__call__

__call__(**kwargs: Any) -> FilterTypeWithInfo
Source code
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
def __call__(self, **kwargs: Any) -> FilterTypeWithInfo:
    if self is FilterType.WIENER:
        def_kwargs = KwargsT(sigma=8.0, beta=1.0, nlocation=None)
    elif self in {FilterType.THR, FilterType.MULT}:
        def_kwargs = KwargsT(sigma=8.0, nlocation=None)
    elif self is FilterType.MULT_PSD:
        def_kwargs = KwargsT(sigma=8.0, pmin=0.0, sigma2=16.0, pmax=500.0)
    elif self is FilterType.MULT_RANGE:
        def_kwargs = KwargsT(sigma=8.0, pmin=0.0, pmax=500.0)
    else:
        def_kwargs = KwargsT()

    kwargs = def_kwargs | kwargs

    if 'beta' in kwargs:
        kwargs['f0beta'] = kwargs.pop('beta')

    return FilterTypeWithInfo(ftype=self.value, **kwargs)

FilterTypeWithInfo

Bases: KwargsT

NLocation

Bases: NamedTuple

frame_number instance-attribute

frame_number: int

plane instance-attribute

plane: int

xpos instance-attribute

xpos: int

ypos instance-attribute

ypos: int

SInterMode

Bases: CustomEnum

SLocation interpolation mode.

CUBIC class-attribute instance-attribute

CUBIC = 'cubic'

LINEAR class-attribute instance-attribute

LINEAR = 'linear'

NEAREST class-attribute instance-attribute

NEAREST = 'nearest'

NEAREST_UP class-attribute instance-attribute

NEAREST_UP = 'nearest-up'

QUADRATIC class-attribute instance-attribute

QUADRATIC = 'quadratic'

SPLINE class-attribute instance-attribute

SPLINE = 1

SPLINE_LINEAR class-attribute instance-attribute

SPLINE_LINEAR = 'slinear'

ZERO class-attribute instance-attribute

ZERO = 'zero'

__call__

__call__(location: SLocationT, /, res: int = 20, digits: int = 3) -> SLocation
__call__(
    h_loc: SLocationT | None = None,
    v_loc: SLocationT | None = None,
    t_loc: SLocationT | None = None,
    /,
    res: int = 20,
    digits: int = 3,
) -> MultiDim
__call__(
    *location: SLocationT, res: int = 20, digits: int = 3
) -> SLocation | MultiDim
__call__(
    *locations: SLocationT, res: int = 20, digits: int = 3
) -> SLocation | MultiDim
Source code
62
63
64
65
66
67
68
def __call__(  # type: ignore
    self, *locations: SLocationT, res: int = 20, digits: int = 3
) -> SLocation | SLocation.MultiDim:
    if len(locations) == 1:
        return SLocation.from_param(locations[0]).interpolate(self, res, digits)

    return SLocation.MultiDim(*(self(x, res, digits) for x in locations))

SLocation

SLocation(
    locations: (
        Sequence[Frequency | Sigma]
        | Sequence[tuple[Frequency, Sigma]]
        | Mapping[Frequency, Sigma]
    ),
    interpolate: SInterMode | None = None,
    strict: bool = True,
)

Specify a range of frequencies to target.

Source code
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
def __init__(
    self, locations: Sequence[Frequency | Sigma] | Sequence[tuple[Frequency, Sigma]] | Mapping[Frequency, Sigma],
    interpolate: SInterMode | None = None, strict: bool = True
) -> None:
    if isinstance(locations, Mapping):
        frequencies, sigmas = list(locations.keys()), list(locations.values())
    else:
        locations = list[float](flatten(locations))  # type: ignore [arg-type]

        if len(locations) % 2:
            raise CustomValueError(
                "slocations must resolve to an even number of items, pairing frequency and sigma respectively",
                self.__class__
            )

        frequencies, sigmas = list(locations[0::2]), list(locations[1::2])

    frequencies = self.boundsCheck(frequencies, (0, 1), strict)
    sigmas = self.boundsCheck(sigmas, (0, None), strict)

    self.frequencies, self.sigmas = (t for t in zip(*sorted(zip(frequencies, sigmas))))

    if interpolate:
        interpolated = self.interpolate(interpolate)

        self.frequencies, self.sigmas = interpolated.frequencies, interpolated.sigmas

NoProcess instance-attribute

NoProcess: SLocation

frequencies instance-attribute

frequencies: tuple[float, ...]

sigmas instance-attribute

sigmas: tuple[float, ...]

MultiDim dataclass

MultiDim(
    horizontal: SLocationT | Literal[False] | None = None,
    vertical: SLocationT | Literal[False] | None = None,
    temporal: SLocationT | Literal[False] | None = None,
)

horizontal class-attribute instance-attribute

horizontal: SLocationT | Literal[False] | None = None

temporal class-attribute instance-attribute

temporal: SLocationT | Literal[False] | None = None

vertical class-attribute instance-attribute

vertical: SLocationT | Literal[False] | None = None

boundsCheck classmethod

boundsCheck(
    values: list[float],
    bounds: tuple[float | None, float | None],
    strict: bool = False,
) -> list[float]
Source code
 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
@classmethod
def boundsCheck(
    cls, values: list[float], bounds: tuple[float | None, float | None], strict: bool = False
) -> list[float]:
    if not values:
        raise CustomValueError('"values" can\'t be empty!', cls)

    values = values.copy()

    bounds_str = iter('inf' if x is None else x for x in bounds)
    of_error = CustomOverflowError("Invalid value at index {i}, not in ({bounds})", cls, bounds=bounds_str)

    low_bound, up_bound = bounds

    for i, value in enumerate(values):
        if low_bound is not None and value < low_bound:
            if strict:
                raise of_error(i=i)

            values[i] = low_bound

        if up_bound is not None and value > up_bound:
            if strict:
                raise of_error(i=i)

            values[i] = up_bound

    return values

from_param classmethod

from_param(location: SLocationT | Literal[False]) -> SLocBoundT
from_param(location: SLocationT | Literal[False] | None) -> SLocBoundT | None
from_param(location: SLocationT | Literal[False] | None) -> SLocBoundT | None
Source code
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
@classmethod
def from_param(cls: type[SLocBoundT], location: SLocationT | Literal[False] | None) -> SLocBoundT | None:
    if isinstance(location, SupportsFloatOrIndex) and location is not False:
        location = float(location)
        location = {0: location, 1: location}

    if location is None:
        return None

    if location is False:
        location = SLocation.NoProcess

    if isinstance(location, SLocation):
        return cls(list(location))

    return cls(location)

interpolate

interpolate(
    method: SInterMode = LINEAR, res: int = 20, digits: int = 3
) -> SLocation
Source code
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
def interpolate(self, method: SInterMode = SInterMode.LINEAR, res: int = 20, digits: int = 3) -> SLocation:
    try:
        from scipy.interpolate import interp1d  # type: ignore
    except ModuleNotFoundError as e:
        raise DependencyNotFoundError(
            self.__class__, e, "scipy is required for interpolation. Use `pip install scipy`"
        )

    frequencies = list({round(x / (res - 1), digits) for x in range(res)})
    sigmas = interp1d(
        list(self.frequencies), list(self.sigmas), method.value, fill_value='extrapolate'
    )(frequencies)

    return SLocation(
        dict(zip(frequencies, sigmas)) | dict(zip(self.frequencies, self.sigmas)), strict=False
    )

SynthesisType

Bases: CustomIntEnum

Synthesis type for spatial processing.

BARLETT class-attribute instance-attribute

BARLETT = 8

BARLETT_HANN class-attribute instance-attribute

BARLETT_HANN = 9

BLACKMAN class-attribute instance-attribute

BLACKMAN = 2

BLACKMAN_HARRIS_4TERM class-attribute instance-attribute

BLACKMAN_HARRIS_4TERM = 3

BLACKMAN_HARRIS_7TERM class-attribute instance-attribute

BLACKMAN_HARRIS_7TERM = 5

BLACKMAN_NUTTALL class-attribute instance-attribute

BLACKMAN_NUTTALL = 11

FLAT_TOP class-attribute instance-attribute

FLAT_TOP = 6

HAMMING class-attribute instance-attribute

HAMMING = 1

HANNING class-attribute instance-attribute

HANNING = 0

KAISER_BESSEL class-attribute instance-attribute

KAISER_BESSEL = 4

NUTTALL class-attribute instance-attribute

NUTTALL = 10

RECTANGULAR class-attribute instance-attribute

RECTANGULAR = 7

__call__

__call__(**kwargs: Any) -> SynthesisTypeWithInfo
Source code
343
344
345
346
347
def __call__(self, **kwargs: Any) -> SynthesisTypeWithInfo:
    if self is SynthesisType.KAISER_BESSEL and 'beta' not in kwargs:
        kwargs['beta'] = 2.5

    return SynthesisTypeWithInfo(win=self.value, **kwargs)

SynthesisTypeWithInfo

Bases: KwargsT

to_dict

to_dict(otype: str) -> KwargsT
Source code
299
300
301
302
303
304
305
306
307
308
def to_dict(self, otype: str) -> KwargsT:
    value = self.copy()

    if 'beta' in value:
        value = value.copy()
        value[f'{otype}beta'] = value.pop('beta')

    value[f'{otype}win'] = value.pop('win')

    return value

fft3d

fft3d(
    clip: VideoNode, func: FuncExceptT | None = None, **kwargs: Any
) -> VideoNode
Source code
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
def fft3d(clip: vs.VideoNode, func: FuncExceptT | None = None, **kwargs: Any) -> vs.VideoNode:
    kwargs |= dict(interlaced=FieldBased.from_video(clip, False, fft3d).is_inter)

    if hasattr(core, 'fft3dfilter'):
        # fft3dfilter requires sigma values to be scaled to bit depth
        # https://github.com/myrsloik/VapourSynth-FFT3DFilter/blob/master/doc/fft3dfilter.md#scaling-parameters-according-to-bit-depth
        sigmaMultiplier = 1.0 / 256.0 if get_sample_type(clip) is vs.FLOAT else 1 << (get_depth(clip) - 8)

        for sigma in ['sigma', 'sigma2', 'sigma3', 'sigma4']:
            if sigma in kwargs:
                kwargs[sigma] *= sigmaMultiplier

        return core.fft3dfilter.FFT3DFilter(clip, **kwargs)  # type: ignore

    if hasattr(core, 'neo_fft3d'):
        return core.neo_fft3d.FFT3D(clip, **kwargs)  # type: ignore

    raise CustomImportError(
        func or fft3d, 'fft3d', "No fft3d plugin (fft3dfilter, neo_fft3d) found, please install one."
    )