vsavd 0.4.0__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vsavd/__init__.py +237 -0
- vsavd/_avdenoise_vs.pyd +0 -0
- vsavd/_plugin.py +48 -0
- vsavd/_types.py +7 -0
- vsavd/py.typed +0 -0
- vsavd-0.4.0.dist-info/METADATA +248 -0
- vsavd-0.4.0.dist-info/RECORD +9 -0
- vsavd-0.4.0.dist-info/WHEEL +5 -0
- vsavd-0.4.0.dist-info/top_level.txt +1 -0
vsavd/__init__.py
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
|
+
|
|
5
|
+
from . import _plugin
|
|
6
|
+
from ._types import Accelerators, ChannelMode, Preset
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
# vapoursynth ships a vapoursynth.pyi stub but no py.typed marker, so mypy
|
|
10
|
+
# refuses to read it. The `ignore_missing_imports` override in pyproject.toml
|
|
11
|
+
# covers both that and the case where the package is absent entirely.
|
|
12
|
+
import vapoursynth as vs
|
|
13
|
+
|
|
14
|
+
__all__ = ["Nlm", "NlmHQ", "Nl4d", "Preset", "ChannelMode"]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _nlmeans_filter() -> "vs.Function":
|
|
18
|
+
"""Returns the bound `avd.NLMeans` plugin function, loading the plugin first."""
|
|
19
|
+
import vapoursynth as vs
|
|
20
|
+
|
|
21
|
+
core = vs.core
|
|
22
|
+
_plugin.ensure_loaded(core)
|
|
23
|
+
return core.avd.NLMeans
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _nl4d_filter() -> "vs.Function":
|
|
27
|
+
"""Returns the bound `avd.NL4D` plugin function, loading the plugin first."""
|
|
28
|
+
import vapoursynth as vs
|
|
29
|
+
|
|
30
|
+
core = vs.core
|
|
31
|
+
_plugin.ensure_loaded(core)
|
|
32
|
+
return core.avd.NL4D
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _forward(fn: "vs.Function", clip: "vs.VideoNode", /, **params: Any) -> "vs.VideoNode":
|
|
36
|
+
"""Calls `fn` with only the parameters the caller actually set."""
|
|
37
|
+
return fn(clip, **{k: v for k, v in params.items() if v is not None})
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def Nlm(
|
|
41
|
+
clip: "vs.VideoNode",
|
|
42
|
+
*,
|
|
43
|
+
preset: Preset | None = None,
|
|
44
|
+
channel_mode: ChannelMode | None = None,
|
|
45
|
+
device: str | None = None,
|
|
46
|
+
strength: float | None = None,
|
|
47
|
+
luma_strength: float | None = None,
|
|
48
|
+
chroma_strength: float | None = None,
|
|
49
|
+
motion_compensation: bool | None = None,
|
|
50
|
+
accelerators: list[Accelerators] | None = None,
|
|
51
|
+
**kwargs: Any,
|
|
52
|
+
) -> "vs.VideoNode":
|
|
53
|
+
"""
|
|
54
|
+
Runs the NLMeans denoiser.
|
|
55
|
+
|
|
56
|
+
`Nlm` is the regular NLMeans algorithm as originally defined in the paper.
|
|
57
|
+
See https://github.com/ChillFish8/av-denoise/docs/CHOOSING_AN_ALGORITHM.md for working
|
|
58
|
+
out what algorithm is right for you.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
clip: The input video node to denoise.
|
|
62
|
+
preset: Preset name. Unset dials fall back to whatever the av-denoise binary defaults to.
|
|
63
|
+
channel_mode: Which planes to filter, one of `"luma"`, `"chroma"`, `"lumachroma"` or `"yuv"`.
|
|
64
|
+
device: Compute device to run on. `"cpu"` selects a software device where the platform offers one,
|
|
65
|
+
useful for testing, not for real encodes. Example: `"discrete:0"` for discrete GPU 0.
|
|
66
|
+
strength: Overall filter strength. Mirrors FFmpeg's scaling.
|
|
67
|
+
luma_strength: Strength override for the luma plane. Mirrors FFmpeg's scaling.
|
|
68
|
+
chroma_strength: Strength override for the chroma planes. Mirrors FFmpeg's scaling.
|
|
69
|
+
motion_compensation: Whether to motion-compensate neighbour frames before matching.
|
|
70
|
+
accelerators: The accelerators to try and use in the order to attempt.
|
|
71
|
+
**kwargs: Further parameters reachable by name. Not recommended
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
A new `vs.VideoNode` holding the denoised clip.
|
|
75
|
+
|
|
76
|
+
Raises:
|
|
77
|
+
vs.Error: If a parameter that does not apply to the fast variant is passed, or if the clip's format
|
|
78
|
+
is not supported.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
accelerators_string: str | None = None
|
|
82
|
+
if accelerators is not None:
|
|
83
|
+
accelerators_string = ",".join(accelerators)
|
|
84
|
+
|
|
85
|
+
return _forward(
|
|
86
|
+
_nlmeans_filter(),
|
|
87
|
+
clip,
|
|
88
|
+
variant="fast",
|
|
89
|
+
preset=preset,
|
|
90
|
+
channel_mode=channel_mode,
|
|
91
|
+
device=device,
|
|
92
|
+
strength=strength,
|
|
93
|
+
luma_strength=luma_strength,
|
|
94
|
+
chroma_strength=chroma_strength,
|
|
95
|
+
motion_compensation=motion_compensation,
|
|
96
|
+
accelerators=accelerators_string,
|
|
97
|
+
**kwargs,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def NlmHQ(
|
|
102
|
+
clip: "vs.VideoNode",
|
|
103
|
+
*,
|
|
104
|
+
preset: Preset | None = None,
|
|
105
|
+
channel_mode: ChannelMode | None = None,
|
|
106
|
+
device: str | None = None,
|
|
107
|
+
sigma_scale: float | None = None,
|
|
108
|
+
strength: float | None = None,
|
|
109
|
+
luma_strength: float | None = None,
|
|
110
|
+
chroma_strength: float | None = None,
|
|
111
|
+
motion_compensation: bool | None = None,
|
|
112
|
+
accelerators: list[Accelerators] | None = None,
|
|
113
|
+
**kwargs: Any,
|
|
114
|
+
) -> "vs.VideoNode":
|
|
115
|
+
"""
|
|
116
|
+
Runs the NLMeans-HQ denoiser.
|
|
117
|
+
|
|
118
|
+
`NlmHQ` measures the noise level per scene and uses that to drive filtering.
|
|
119
|
+
See https://github.com/ChillFish8/av-denoise/docs/CHOOSING_AN_ALGORITHM.md for working
|
|
120
|
+
out what algorithm is right for you.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
clip: The input video node to denoise.
|
|
124
|
+
preset: Preset name. Unset dials fall back to whatever the av-denoise binary defaults to.
|
|
125
|
+
channel_mode: Which planes to filter, one of `"luma"`, `"chroma"`, `"lumachroma"` or `"yuv"`.
|
|
126
|
+
device: Compute device to run on. `"cpu"` selects a software device where the platform offers one,
|
|
127
|
+
useful for testing, not for real encodes. Example: `"discrete:0"` for discrete GPU 0.
|
|
128
|
+
sigma_scale: Multiplier nudging the measured noise level up or down.
|
|
129
|
+
This is the right dial to reach for when leftover grain survives filtering,
|
|
130
|
+
rather than raising `strength`.
|
|
131
|
+
strength: Overall filter strength. Raising this to fight leftover grain is the wrong move, grain
|
|
132
|
+
that survives usually means the noise level read low, correcting `sigma_scale` is the right
|
|
133
|
+
move instead.
|
|
134
|
+
luma_strength: Strength override for the luma plane.
|
|
135
|
+
chroma_strength: Strength override for the chroma planes.
|
|
136
|
+
motion_compensation: Whether to motion-compensate neighbour frames before matching.
|
|
137
|
+
accelerators: The accelerators to try and use in the order to attempt.
|
|
138
|
+
**kwargs: Further parameters reachable by name, documented in the
|
|
139
|
+
`av-denoise` CLI documentation under their flag names.
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
A new `vs.VideoNode` holding the denoised clip.
|
|
143
|
+
|
|
144
|
+
Raises:
|
|
145
|
+
vs.Error: If a parameter that does not apply to the hq variant is
|
|
146
|
+
passed, or if the clip's format is not supported.
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
accelerators_string: str | None = None
|
|
150
|
+
if accelerators is not None:
|
|
151
|
+
accelerators_string = ",".join(accelerators)
|
|
152
|
+
|
|
153
|
+
return _forward(
|
|
154
|
+
_nlmeans_filter(),
|
|
155
|
+
clip,
|
|
156
|
+
variant="hq",
|
|
157
|
+
preset=preset,
|
|
158
|
+
channel_mode=channel_mode,
|
|
159
|
+
device=device,
|
|
160
|
+
sigma_scale=sigma_scale,
|
|
161
|
+
strength=strength,
|
|
162
|
+
luma_strength=luma_strength,
|
|
163
|
+
chroma_strength=chroma_strength,
|
|
164
|
+
motion_compensation=motion_compensation,
|
|
165
|
+
accelerators=accelerators_string,
|
|
166
|
+
**kwargs,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def Nl4d(
|
|
171
|
+
clip: "vs.VideoNode",
|
|
172
|
+
*,
|
|
173
|
+
preset: Preset | None = None,
|
|
174
|
+
channel_mode: ChannelMode | None = None,
|
|
175
|
+
device: str | None = None,
|
|
176
|
+
lambda_ht_scale: float | None = None,
|
|
177
|
+
lambda_ht: float | None = None,
|
|
178
|
+
sigma_scale: float | None = None,
|
|
179
|
+
spatial_radius: int | None = None,
|
|
180
|
+
refine: int | None = None,
|
|
181
|
+
accelerators: list[Accelerators] | None = None,
|
|
182
|
+
**kwargs: Any,
|
|
183
|
+
) -> "vs.VideoNode":
|
|
184
|
+
"""
|
|
185
|
+
Runs the NL4D spatio-temporal denoiser.
|
|
186
|
+
|
|
187
|
+
See https://github.com/ChillFish8/av-denoise/docs/CHOOSING_AN_ALGORITHM.md for working
|
|
188
|
+
out what algorithm is right for you.
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
clip: The input video node to denoise.
|
|
192
|
+
preset: Preset name. Unset dials fall back to whatever the av-denoise binary defaults to.
|
|
193
|
+
channel_mode: Which planes to filter, one of `"luma"`, `"chroma"`, `"lumachroma"` or `"yuv"`.
|
|
194
|
+
device: Compute device to run on. `"cpu"` selects a software device where the platform offers one,
|
|
195
|
+
useful for testing, not for real encodes. Example: `"discrete:0"` for discrete GPU 0.
|
|
196
|
+
lambda_ht_scale: Threshold multiplier a transform coefficient's estimated-noise standard deviations
|
|
197
|
+
must clear to survive. This is the main dial, raising it removes more noise and takes more
|
|
198
|
+
fine detail with it. Try it in steps of about 0.05.
|
|
199
|
+
lambda_ht: Pins luma and chroma's thresholds to the same absolute number instead of
|
|
200
|
+
their separate defaults, losing that separation. Prefer `lambda_ht_scale` first.
|
|
201
|
+
sigma_scale: Multiplier nudging the measured noise level up or down, keeping the per-scene
|
|
202
|
+
measurement rather than pinning it.
|
|
203
|
+
spatial_radius: The speed dial. `preset` already resolves it, so setting this explicitly overrides
|
|
204
|
+
whatever the preset picked. The centre-frame search covers `(2 * radius + 1)^2` positions,
|
|
205
|
+
so it dominates the work, lowering it is the fastest way to speed a run-up.
|
|
206
|
+
refine: Half-width of the window searched around each neighbour frame's motion-predicted position.
|
|
207
|
+
Raise it when motion tracking lands close but not exact.
|
|
208
|
+
accelerators: The accelerators to try and use in the order to attempt.
|
|
209
|
+
**kwargs: Further parameters reachable by name, documented in the
|
|
210
|
+
`av-denoise` CLI documentation under their flag names.
|
|
211
|
+
|
|
212
|
+
Returns:
|
|
213
|
+
A new `vs.VideoNode` holding the denoised clip.
|
|
214
|
+
|
|
215
|
+
Raises:
|
|
216
|
+
vs.Error: If a parameter that does not apply to this filter is
|
|
217
|
+
passed, or if the clip's format is not supported.
|
|
218
|
+
"""
|
|
219
|
+
|
|
220
|
+
accelerators_string: str | None = None
|
|
221
|
+
if accelerators is not None:
|
|
222
|
+
accelerators_string = ",".join(accelerators)
|
|
223
|
+
|
|
224
|
+
return _forward(
|
|
225
|
+
_nl4d_filter(),
|
|
226
|
+
clip,
|
|
227
|
+
preset=preset,
|
|
228
|
+
channel_mode=channel_mode,
|
|
229
|
+
device=device,
|
|
230
|
+
lambda_ht_scale=lambda_ht_scale,
|
|
231
|
+
lambda_ht=lambda_ht,
|
|
232
|
+
sigma_scale=sigma_scale,
|
|
233
|
+
spatial_radius=spatial_radius,
|
|
234
|
+
refine=refine,
|
|
235
|
+
accelerators=accelerators_string,
|
|
236
|
+
**kwargs,
|
|
237
|
+
)
|
vsavd/_avdenoise_vs.pyd
ADDED
|
Binary file
|
vsavd/_plugin.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import pathlib
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
# vapoursynth ships a vapoursynth.pyi stub but no py.typed marker, so mypy
|
|
8
|
+
# refuses to read it. The `ignore_missing_imports` override in pyproject.toml
|
|
9
|
+
# covers both that and the case where the package is absent entirely.
|
|
10
|
+
import vapoursynth as vs
|
|
11
|
+
|
|
12
|
+
_NAMESPACE = "avd"
|
|
13
|
+
_ARTEFACT_GLOB = "_avdenoise_vs*"
|
|
14
|
+
# setuptools-rust names the artefact with the platform's Python extension suffix,
|
|
15
|
+
# which on Windows is `.pyd` rather than `.dll`. `.dll` and `.dylib` stay for a
|
|
16
|
+
# plugin built by hand and copied into a source checkout.
|
|
17
|
+
_ARTEFACT_SUFFIXES = (".so", ".dll", ".dylib", ".pyd")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def plugin_path() -> pathlib.Path:
|
|
21
|
+
"""
|
|
22
|
+
The bundled plugin's absolute path.
|
|
23
|
+
|
|
24
|
+
setuptools-rust names the compiled artefact after the ext-module target
|
|
25
|
+
and picks its suffix based on whether the extension opted into the
|
|
26
|
+
limited API, so this helper globs for it instead of matching one fixed name.
|
|
27
|
+
"""
|
|
28
|
+
here = pathlib.Path(__file__).parent
|
|
29
|
+
candidates = sorted(p for p in here.glob(_ARTEFACT_GLOB) if p.suffix in _ARTEFACT_SUFFIXES)
|
|
30
|
+
if not candidates:
|
|
31
|
+
raise RuntimeError(
|
|
32
|
+
f"no bundled av-denoise plugin found in {here}. "
|
|
33
|
+
"A source checkout needs the plugin built and copied in, which the wheel does at build time."
|
|
34
|
+
)
|
|
35
|
+
if len(candidates) > 1:
|
|
36
|
+
joined = ", ".join(str(c) for c in candidates)
|
|
37
|
+
raise RuntimeError(
|
|
38
|
+
f"multiple candidate av-denoise plugin artefacts found in {here}: {joined}. "
|
|
39
|
+
"Remove the stale build output and rebuild the wheel."
|
|
40
|
+
)
|
|
41
|
+
return candidates[0]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def ensure_loaded(core: "vs.Core") -> None:
|
|
45
|
+
"""Registers the plugin with `core` unless it is already there."""
|
|
46
|
+
if any(p.namespace == _NAMESPACE for p in core.plugins()):
|
|
47
|
+
return
|
|
48
|
+
core.std.LoadPlugin(str(plugin_path()))
|
vsavd/_types.py
ADDED
vsavd/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vsavd
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: VapourSynth plugin for av-denoise, with typed Python wrappers.
|
|
5
|
+
Author: ChillFish8
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/ChillFish8/av-denoise
|
|
8
|
+
Project-URL: Repository, https://github.com/ChillFish8/av-denoise
|
|
9
|
+
Project-URL: Issues, https://github.com/ChillFish8/av-denoise/issues
|
|
10
|
+
Keywords: vapoursynth,denoise,video,gpu,nlmeans
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Topic :: Multimedia :: Video
|
|
13
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
14
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
15
|
+
Classifier: Operating System :: MacOS
|
|
16
|
+
Requires-Python: >=3.12
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
Requires-Dist: vapoursynth
|
|
19
|
+
Dynamic: description
|
|
20
|
+
Dynamic: description-content-type
|
|
21
|
+
|
|
22
|
+
# av-denoise VapourSynth plugin (`vsavd`)
|
|
23
|
+
|
|
24
|
+
This is the home of [av-denoise](https://github.com/ChillFish8/av-denoise) exposed as a VapourSynth plugin to fit within existing filtering
|
|
25
|
+
pipelines. With caveats.
|
|
26
|
+
|
|
27
|
+
We provide typed interfaces for all the [supported algorithms](https://github.com/ChillFish8/av-denoise/blob/HEAD/docs/CHOOSING_AN_ALGORITHM.md):
|
|
28
|
+
|
|
29
|
+
- `vsavd.Nl4d(...)` for our best in class _NL4D_ denoiser offering higher quality and more effective denoising over V-BM3D.
|
|
30
|
+
- `vsavd.NlmHQ(...)` for our _NLMeans-HQ_ algorithm which provides a higher quality and smarter denoising experience over base NLMeans.
|
|
31
|
+
- `vsavd.Nlm(...)` for quick and dirt NLMeans mirroring FFmpeg's strength scaling.
|
|
32
|
+
|
|
33
|
+
_All_ algorithms are temporal aware and have inbuilt motion compensation kernels.
|
|
34
|
+
|
|
35
|
+
### _Here be dragons!_ 🐉
|
|
36
|
+
|
|
37
|
+
VapourSynth's API significantly restricts how av-denoise can operate and as a result, can produce a worse
|
|
38
|
+
denoising experience compared to the CLI or direct Rust library usage. Primarily because noise estimation
|
|
39
|
+
cannot be incrementally refined over all frames and instead has to be performed only over the temporal
|
|
40
|
+
window.
|
|
41
|
+
|
|
42
|
+
Performance is a _best effort_ situation, if you have anything which causes frames to arrive to the filter out of order
|
|
43
|
+
your performance can drop by 70-80%.
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
## Table of contents
|
|
47
|
+
|
|
48
|
+
- [Installing](#installing)
|
|
49
|
+
- [Choosing an algorithm](#choosing-an-algorithm)
|
|
50
|
+
- [Nl4d](#nl4d)
|
|
51
|
+
- [NlmHQ](#nlmhq-nlmeans-hq)
|
|
52
|
+
- [Nlm](#nlm-nlmeans)
|
|
53
|
+
- [Presets](#presets)
|
|
54
|
+
- [Channel modes](#channel-modes)
|
|
55
|
+
- [Devices and accelerators](#devices-and-accelerators)
|
|
56
|
+
- [Shared conventions](#shared-conventions)
|
|
57
|
+
- [Tuning guide](https://github.com/ChillFish8/av-denoise/blob/HEAD/docs/TUNING-VS.md)
|
|
58
|
+
|
|
59
|
+
## Installing
|
|
60
|
+
|
|
61
|
+
Pre-built wheels are available for Linux, macOS and Windows, published to PyPI.
|
|
62
|
+
|
|
63
|
+
_Please note that the wheels for **Linux** and **Windows** are compiled for `vulkan` and `cuda` only. **macOS** is compiled for `metal`.
|
|
64
|
+
ROCm is not recommended and requires manual compilation._
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pip install vsavd
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
or, with `uv`:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
uv add vsavd
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Installing `vsavd` bundles the compiled plugin inside the wheel, so there is nothing else to build or load.
|
|
77
|
+
|
|
78
|
+
## [Choosing an algorithm](https://github.com/ChillFish8/av-denoise/blob/HEAD/docs/CHOOSING_AN_ALGORITHM.md)
|
|
79
|
+
|
|
80
|
+
Please have a read of the linked page for info about what each algorithm does and its tradeoffs.
|
|
81
|
+
|
|
82
|
+
**TL;DR: Use NL4D if you're unsure**
|
|
83
|
+
|
|
84
|
+
## [_Don't do this!_](https://github.com/ChillFish8/av-denoise/blob/HEAD/docs/DONT_DO_THIS.md)
|
|
85
|
+
|
|
86
|
+
We recommend reading this before deciding how to integrate this into your existing filtering pipeline
|
|
87
|
+
as some things differ quiet heavily to what you are likely used to.
|
|
88
|
+
|
|
89
|
+
## [Nl4d](https://github.com/ChillFish8/av-denoise/blob/HEAD/docs/CHOOSING_AN_ALGORITHM.md#nl4d)
|
|
90
|
+
|
|
91
|
+
`Nl4d` is the spatio-temporal denoiser, wrapping `avd.NL4D`. It gives the best noise
|
|
92
|
+
removal and detail retention of the three, at the cost of time.
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
import vapoursynth as vs
|
|
96
|
+
import vsavd as avd
|
|
97
|
+
|
|
98
|
+
core = vs.core
|
|
99
|
+
clip = core.lsmas.LWLibavSource("noisy.mkv")
|
|
100
|
+
clean = avd.Nl4d(clip)
|
|
101
|
+
clean.set_output()
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
| Parameter | Type | CLI equivalent | Recommended |
|
|
105
|
+
|-------------------|-----------------|-------------------------|------------------------|
|
|
106
|
+
| `lambda_ht_scale` | float | `--lambda-ht-scale` | yes, the main dial |
|
|
107
|
+
| `sigma_scale` | float | `--sigma-scale` | yes |
|
|
108
|
+
| `preset` | string | `--preset` | yes |
|
|
109
|
+
| `refine` | int | `--refine` | yes |
|
|
110
|
+
| `spatial_radius` | int | `--spatial-radius` | yes, the speed dial |
|
|
111
|
+
| `lambda_ht` | float | `--lambda-ht` | situational, see below |
|
|
112
|
+
| `channel_mode` | string | channel-mode flags | situational |
|
|
113
|
+
| `device` | string | `--device` | situational |
|
|
114
|
+
| `accelerators` | list of strings | `-A`, `--accelerators` | situational |
|
|
115
|
+
|
|
116
|
+
`lambda_ht_scale` is the threshold multiplier a transform coefficient's estimated-noise
|
|
117
|
+
standard deviations must clear to survive. Raising it removes more noise and takes more
|
|
118
|
+
fine detail with it. Try it in steps of about 0.05 before reaching for `lambda_ht`,
|
|
119
|
+
which pins luma and chroma's thresholds (5.2 and 3.4 by default, these values have been
|
|
120
|
+
manually tuned to provide the subjectively best image for a given grain strength across
|
|
121
|
+
real clips rather than synthetic benchmarks).
|
|
122
|
+
|
|
123
|
+
`spatial_radius` is the speed dial. `preset` already resolves it, so setting
|
|
124
|
+
`spatial_radius` explicitly overrides whatever the preset would have picked. The
|
|
125
|
+
centre-frame search covers `(2 * radius + 1)^2` positions, so it dominates the work.
|
|
126
|
+
Dropping it is the fastest way to speed a run up.
|
|
127
|
+
|
|
128
|
+
`refine` is the half-width of the window searched around each neighbour frame's
|
|
129
|
+
motion-predicted position. Raise it when motion tracking lands close but not exact.
|
|
130
|
+
|
|
131
|
+
`sigma_scale` keeps the per-scene noise measurement and nudges it, which is almost
|
|
132
|
+
always what you actually want.
|
|
133
|
+
|
|
134
|
+
## [NlmHQ (NLMeans-HQ)](https://github.com/ChillFish8/av-denoise/blob/HEAD/docs/CHOOSING_AN_ALGORITHM.md#nlmeans-hq-nlmeans-high-quality)
|
|
135
|
+
|
|
136
|
+
`NlmHQ` is the high-quality NLMeans variant, wrapping `avd.NLMeans` with `variant="hq"`.
|
|
137
|
+
It runs a per-scene noise estimator and reads its result into `sigma_scale` rather than
|
|
138
|
+
leaving noise level to a hand-set `strength`. Use it over `Nlm` when you want the
|
|
139
|
+
estimator to pick the noise level for you.
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
import vapoursynth as vs
|
|
143
|
+
import vsavd as avd
|
|
144
|
+
|
|
145
|
+
core = vs.core
|
|
146
|
+
clip = core.lsmas.LWLibavSource("noisy.mkv")
|
|
147
|
+
clean = avd.NlmHQ(clip)
|
|
148
|
+
clean.set_output()
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
| Parameter | Type | CLI equivalent | Recommended |
|
|
152
|
+
|-----------------------|-----------------|-------------------------|------------------------|
|
|
153
|
+
| `preset` | string | `--preset` | yes |
|
|
154
|
+
| `motion_compensation` | bool | `--motion-compensation` | yes |
|
|
155
|
+
| `sigma_scale` | float | `--hq-sigma-scale` | yes, the main dial |
|
|
156
|
+
| `chroma_strength` | float | `--chroma-strength` | yes |
|
|
157
|
+
| `channel_mode` | string | channel-mode flags | situational |
|
|
158
|
+
| `strength` | float | `--strength` | situational, see below |
|
|
159
|
+
| `luma_strength` | float | `--luma-strength` | situational |
|
|
160
|
+
| `device` | string | `--device` | situational |
|
|
161
|
+
| `accelerators` | list of strings | `-A`, `--accelerators` | situational |
|
|
162
|
+
|
|
163
|
+
Raising `strength` to fight leftover grain is the wrong move. Grain that survives means
|
|
164
|
+
the noise level read low, and extra strength scrubs detail before it removes grain.
|
|
165
|
+
Correcting `sigma_scale` instead is the right move.
|
|
166
|
+
|
|
167
|
+
## [Nlm (NLMeans)](https://github.com/ChillFish8/av-denoise/blob/HEAD/docs/CHOOSING_AN_ALGORITHM.md#nlmeans)
|
|
168
|
+
|
|
169
|
+
`Nlm` is the fast NLMeans variant, wrapping `avd.NLMeans` with `variant="fast"`. It has no
|
|
170
|
+
noise estimator, so it runs quickly and expects you to set `strength` yourself. Reach for
|
|
171
|
+
it when speed matters more than squeezing out the last bit of noise.
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
import vapoursynth as vs
|
|
175
|
+
import vsavd as avd
|
|
176
|
+
|
|
177
|
+
core = vs.core
|
|
178
|
+
clip = core.lsmas.LWLibavSource("noisy.mkv")
|
|
179
|
+
clean = avd.Nlm(clip, strength=1.2)
|
|
180
|
+
clean.set_output()
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
| Parameter | Type | CLI equivalent | Recommended |
|
|
184
|
+
|-----------------------|-----------------|-------------------------|-------------|
|
|
185
|
+
| `preset` | string | `--preset` | yes |
|
|
186
|
+
| `motion_compensation` | bool | `--motion-compensation` | yes |
|
|
187
|
+
| `chroma_strength` | float | `--chroma-strength` | yes |
|
|
188
|
+
| `channel_mode` | string | channel-mode flags | situational |
|
|
189
|
+
| `strength` | float | `--strength` | yes |
|
|
190
|
+
| `luma_strength` | float | `--luma-strength` | situational |
|
|
191
|
+
| `device` | string | `--device` | situational |
|
|
192
|
+
| `accelerators` | list of strings | `-A`, `--accelerators` | situational |
|
|
193
|
+
|
|
194
|
+
`Nlm` has no noise estimator, so `strength` is the dial that sets the noise level. Use
|
|
195
|
+
`NlmHQ` if you would rather have it measured for you.
|
|
196
|
+
|
|
197
|
+
## Presets
|
|
198
|
+
|
|
199
|
+
`preset` is the main quality-versus-speed dial. It takes one of five values, from
|
|
200
|
+
fastest to slowest and best-quality: `veryfast`, `fast`, `base`, `slow`, `veryslow`.
|
|
201
|
+
Each preset resolves every unset numeric and string parameter to a value tuned for that speed tier.
|
|
202
|
+
|
|
203
|
+
Any parameter you set explicitly overrides what the preset would have chosen for it,
|
|
204
|
+
other fields still fall back to the preset's values. This lets you take a preset as a
|
|
205
|
+
starting point and adjust just the dial you care about, as the examples above do.
|
|
206
|
+
|
|
207
|
+
> [!TIP]
|
|
208
|
+
> Presets exist to be easy levers to adjust, but you can probably still get the quality you want
|
|
209
|
+
> using the `base` preset on NLMeans-HQ and NL4D by tweaking the `*-scale` parameters.
|
|
210
|
+
|
|
211
|
+
## Channel modes
|
|
212
|
+
|
|
213
|
+
`channel_mode` selects which planes get denoised, and takes one of four values:
|
|
214
|
+
|
|
215
|
+
- `luma` denoises the luma plane only, leaving chroma untouched.
|
|
216
|
+
- `chroma` denoises the chroma planes only, leaving luma untouched.
|
|
217
|
+
- `lumachroma` denoises both, luma and chroma independently.
|
|
218
|
+
- `yuv` denoises luma and chroma together as a single pass. It needs a 4:4:4 source,
|
|
219
|
+
since it requires the chroma planes to be full resolution.
|
|
220
|
+
|
|
221
|
+
## Devices and accelerators
|
|
222
|
+
|
|
223
|
+
`device` is typed on all three functions and selects which GPU device runs the filter.
|
|
224
|
+
`device="cpu"` selects a software device where the platform offers one, such as
|
|
225
|
+
lavapipe under Vulkan. It is for testing the pipeline, not for real encodes.
|
|
226
|
+
|
|
227
|
+
`accelerators` selects which GPU backend to use, for example `["vulkan"]` or `["cuda"]`.
|
|
228
|
+
Multiple accelerators can be provided and the system will try each accelerator in the order
|
|
229
|
+
provided, choosing the first accelerator which can work on the host hardware.
|
|
230
|
+
|
|
231
|
+
> [!IMPORTANT]
|
|
232
|
+
> You can only use accelerators the plugin was compiled with, for example the wheels for
|
|
233
|
+
> Linux and Windows only support `"vulkan"` and `"cuda"`, requesting `"rocm"` would result
|
|
234
|
+
> in an error.
|
|
235
|
+
|
|
236
|
+
```python
|
|
237
|
+
clean = avd.Nl4d(clip, preset="slow", accelerators=["cuda", "vulkan"])
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Shared conventions
|
|
241
|
+
|
|
242
|
+
- Every numeric script argument is optional, an unset one falls back to the algorithm's own default, or to
|
|
243
|
+
whatever `preset` resolves for that field.
|
|
244
|
+
- `device` and `accelerators` are unset by default rather than pinned to a literal string.
|
|
245
|
+
|
|
246
|
+
## [Tuning guide](https://github.com/ChillFish8/av-denoise/blob/HEAD/docs/TUNING-VS.md)
|
|
247
|
+
|
|
248
|
+
For more information about how to adjust the algorithms to best fit your needs.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
vsavd/__init__.py,sha256=ZdHvVS4h05MB6k4UsSmyqbl4_uSylxeXlpWenwamtbw,9728
|
|
2
|
+
vsavd/_avdenoise_vs.pyd,sha256=upNucZB2kVFnshSNbrcBlR1a1vumKw4e4dLWa7f_T9U,19316224
|
|
3
|
+
vsavd/_plugin.py,sha256=6jvQi8QvkuTinEtd6jMZ7qpFp1fSHKl7RHYdJDKHF8E,1974
|
|
4
|
+
vsavd/_types.py,sha256=nVnIQLbWKotIe_7r631X3T0Gx8ZBCFLsmNqX0nUobMQ,255
|
|
5
|
+
vsavd/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
vsavd-0.4.0.dist-info/METADATA,sha256=qBd3jA-41W3kkca1jPt-3fLTRHOm-0IFi44wx8nUQZ0,12040
|
|
7
|
+
vsavd-0.4.0.dist-info/WHEEL,sha256=Zx98gwb_dQKckJK3HEOVKnxxD52EfU_PXDG_usMJ2ng,98
|
|
8
|
+
vsavd-0.4.0.dist-info/top_level.txt,sha256=BHlJose3JtWPZ8c-Jz8vkJkB9dosC1zn74TYRlaSNAg,6
|
|
9
|
+
vsavd-0.4.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
vsavd
|