vsdirty 0.2.2__tar.gz → 0.4.0__tar.gz
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.
- vsdirty-0.4.0/PKG-INFO +56 -0
- vsdirty-0.4.0/README.md +40 -0
- {vsdirty-0.2.2 → vsdirty-0.4.0}/pyproject.toml +4 -5
- {vsdirty-0.2.2 → vsdirty-0.4.0}/vsdirty/adfunc.py +109 -62
- {vsdirty-0.2.2 → vsdirty-0.4.0}/vsdirty/admask.py +19 -15
- {vsdirty-0.2.2 → vsdirty-0.4.0}/vsdirty/adutils.py +68 -0
- vsdirty-0.4.0/vsdirty.egg-info/PKG-INFO +56 -0
- vsdirty-0.4.0/vsdirty.egg-info/requires.txt +2 -0
- vsdirty-0.2.2/PKG-INFO +0 -221
- vsdirty-0.2.2/README.md +0 -204
- vsdirty-0.2.2/vsdirty.egg-info/PKG-INFO +0 -221
- vsdirty-0.2.2/vsdirty.egg-info/requires.txt +0 -3
- {vsdirty-0.2.2 → vsdirty-0.4.0}/LICENSE +0 -0
- {vsdirty-0.2.2 → vsdirty-0.4.0}/setup.cfg +0 -0
- {vsdirty-0.2.2 → vsdirty-0.4.0}/vsdirty/__init__.py +0 -0
- {vsdirty-0.2.2 → vsdirty-0.4.0}/vsdirty/dirtyfixer.py +0 -0
- {vsdirty-0.2.2 → vsdirty-0.4.0}/vsdirty.egg-info/SOURCES.txt +0 -0
- {vsdirty-0.2.2 → vsdirty-0.4.0}/vsdirty.egg-info/dependency_links.txt +0 -0
- {vsdirty-0.2.2 → vsdirty-0.4.0}/vsdirty.egg-info/top_level.txt +0 -0
vsdirty-0.4.0/PKG-INFO
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vsdirty
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: VapourSynth wrappers for denoising, masking and edge fixing
|
|
5
|
+
Author: PingWer, Mhanz3500
|
|
6
|
+
Project-URL: Homepage, https://github.com/PingWer/vs-dirty
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Requires-Python: >=3.12
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Requires-Dist: vsjetpack
|
|
14
|
+
Requires-Dist: vapoursynth==73
|
|
15
|
+
Dynamic: license-file
|
|
16
|
+
|
|
17
|
+
# vs-dirty
|
|
18
|
+
|
|
19
|
+
A collection of VapourSynth wrappers and utility functions focused on advanced denoising, masking, and edge fixing.
|
|
20
|
+
|
|
21
|
+
Follow the docstring for more information about the parameters.
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
You can install `vsdirty` via pip:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install vsdirty
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Or build from source:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
git clone https://github.com/PingWer/vs-dirty
|
|
35
|
+
cd vs-dirty
|
|
36
|
+
pip install .
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Dependencies
|
|
40
|
+
|
|
41
|
+
This package relies on several external VapourSynth plugins. Ensure these are installed and available in your VapourSynth plugins folder.
|
|
42
|
+
|
|
43
|
+
| Plugin | URL |
|
|
44
|
+
| :--- | :--- |
|
|
45
|
+
| **fmtc** | [GitLab](https://gitlab.com/EleonoreMizo/fmtconv/) |
|
|
46
|
+
| **akarin** | [GitHub](https://github.com/AkarinVS/vapoursynth-plugin) |
|
|
47
|
+
| **cas** | [GitHub](https://github.com/HomeOfVapourSynthEvolution/VapourSynth-CAS) |
|
|
48
|
+
| **bore** | [GitHub](https://github.com/OpusGang/bore) |
|
|
49
|
+
| **mvtools** | [GitHub](https://github.com/dubhater/vapoursynth-mvtools) |
|
|
50
|
+
| **BM3DCuda** | [GitHub](https://github.com/WolframRhodium/VapourSynth-BM3DCUDA) |
|
|
51
|
+
| **nlm-cuda** | [GitHub](https://github.com/AmusementClub/vs-nlm-cuda) |
|
|
52
|
+
| **vsmlrt** | [GitHub](https://github.com/AmusementClub/vs-mlrt) |
|
|
53
|
+
|
|
54
|
+
## License
|
|
55
|
+
|
|
56
|
+
MIT License
|
vsdirty-0.4.0/README.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# vs-dirty
|
|
2
|
+
|
|
3
|
+
A collection of VapourSynth wrappers and utility functions focused on advanced denoising, masking, and edge fixing.
|
|
4
|
+
|
|
5
|
+
Follow the docstring for more information about the parameters.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
You can install `vsdirty` via pip:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install vsdirty
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Or build from source:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
git clone https://github.com/PingWer/vs-dirty
|
|
19
|
+
cd vs-dirty
|
|
20
|
+
pip install .
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Dependencies
|
|
24
|
+
|
|
25
|
+
This package relies on several external VapourSynth plugins. Ensure these are installed and available in your VapourSynth plugins folder.
|
|
26
|
+
|
|
27
|
+
| Plugin | URL |
|
|
28
|
+
| :--- | :--- |
|
|
29
|
+
| **fmtc** | [GitLab](https://gitlab.com/EleonoreMizo/fmtconv/) |
|
|
30
|
+
| **akarin** | [GitHub](https://github.com/AkarinVS/vapoursynth-plugin) |
|
|
31
|
+
| **cas** | [GitHub](https://github.com/HomeOfVapourSynthEvolution/VapourSynth-CAS) |
|
|
32
|
+
| **bore** | [GitHub](https://github.com/OpusGang/bore) |
|
|
33
|
+
| **mvtools** | [GitHub](https://github.com/dubhater/vapoursynth-mvtools) |
|
|
34
|
+
| **BM3DCuda** | [GitHub](https://github.com/WolframRhodium/VapourSynth-BM3DCUDA) |
|
|
35
|
+
| **nlm-cuda** | [GitHub](https://github.com/AmusementClub/vs-nlm-cuda) |
|
|
36
|
+
| **vsmlrt** | [GitHub](https://github.com/AmusementClub/vs-mlrt) |
|
|
37
|
+
|
|
38
|
+
## License
|
|
39
|
+
|
|
40
|
+
MIT License
|
|
@@ -4,15 +4,14 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "vsdirty"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.4.0"
|
|
8
8
|
description = "VapourSynth wrappers for denoising, masking and edge fixing"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [{ name = "PingWer" }, { name = "Mhanz3500" }]
|
|
11
11
|
requires-python = ">=3.12"
|
|
12
12
|
dependencies = [
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"vsjetpack==1.1.0",
|
|
13
|
+
"vsjetpack",
|
|
14
|
+
"vapoursynth==73", # For 0.4.0 we need to force r73, we will support APIv4 in the next update
|
|
16
15
|
]
|
|
17
16
|
classifiers = [
|
|
18
17
|
"Programming Language :: Python :: 3",
|
|
@@ -21,7 +20,7 @@ classifiers = [
|
|
|
21
20
|
]
|
|
22
21
|
|
|
23
22
|
[project.urls]
|
|
24
|
-
Homepage = "https://github.com/
|
|
23
|
+
Homepage = "https://github.com/PingWer/vs-dirty"
|
|
25
24
|
|
|
26
25
|
[tool.setuptools.packages.find]
|
|
27
26
|
include = ["vsdirty*"]
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import vapoursynth as vs
|
|
2
2
|
|
|
3
|
-
from typing import Optional
|
|
3
|
+
from typing import Optional, Any
|
|
4
4
|
from vstools import PlanesT
|
|
5
|
+
from vsmlrt import BackendV2
|
|
5
6
|
|
|
6
7
|
core = vs.core
|
|
7
8
|
|
|
@@ -149,20 +150,7 @@ def mini_BM3D(
|
|
|
149
150
|
refS,
|
|
150
151
|
fulls=True,
|
|
151
152
|
fulld=True,
|
|
152
|
-
coef=[
|
|
153
|
-
1 / 3,
|
|
154
|
-
1 / 3,
|
|
155
|
-
1 / 3,
|
|
156
|
-
0,
|
|
157
|
-
1 / 2,
|
|
158
|
-
0,
|
|
159
|
-
-1 / 2,
|
|
160
|
-
0,
|
|
161
|
-
1 / 4,
|
|
162
|
-
-1 / 2,
|
|
163
|
-
1 / 4,
|
|
164
|
-
0,
|
|
165
|
-
],
|
|
153
|
+
coef=[1 / 3, 1 / 3, 1 / 3, 0, 1 / 2, 0, -1 / 2, 0, 1 / 4, -1 / 2, 1 / 4, 0],
|
|
166
154
|
col_fam=vs.YUV,
|
|
167
155
|
)
|
|
168
156
|
else:
|
|
@@ -255,9 +243,9 @@ class adenoise:
|
|
|
255
243
|
:param thsad: Thsad for mc_degrain (luma denoise strength and chroma ref).
|
|
256
244
|
Recommended values: 300-800
|
|
257
245
|
:param tr: Temporal radius for temporal consistency across al the filter involved.
|
|
258
|
-
Recommended values: 2-3
|
|
246
|
+
Recommended values: 2-3.
|
|
259
247
|
:param sigma: Sigma for BM3D (luma denoise strength).
|
|
260
|
-
Recommended values:
|
|
248
|
+
Recommended values: 3-6.
|
|
261
249
|
:param luma_mask_weaken: Controls how much dark spots should be denoised. Lower values mean stronger overall denoise.
|
|
262
250
|
Recommended values: 0.6-0.9
|
|
263
251
|
:param luma_mask_thr: Threshold that determines what is considered bright and what is dark in the luma mask.
|
|
@@ -297,6 +285,7 @@ class adenoise:
|
|
|
297
285
|
luma_over_texture: float = 0.4,
|
|
298
286
|
kwargs_flatmask: Optional[dict] = {},
|
|
299
287
|
show_mask: int = 0,
|
|
288
|
+
backend: Optional[BackendV2] = None,
|
|
300
289
|
**kwargs,
|
|
301
290
|
) -> tuple[vs.VideoNode, vs.VideoNode]:
|
|
302
291
|
|
|
@@ -331,7 +320,7 @@ class adenoise:
|
|
|
331
320
|
selected_mask = darken_luma_mask
|
|
332
321
|
|
|
333
322
|
# Degrain
|
|
334
|
-
if "
|
|
323
|
+
if "is_bm3d_only" not in kwargs:
|
|
335
324
|
mvtools = MVTools(clip)
|
|
336
325
|
vectors = mvtools.analyze(
|
|
337
326
|
blksize=16,
|
|
@@ -370,21 +359,17 @@ class adenoise:
|
|
|
370
359
|
if show_mask == 2:
|
|
371
360
|
selected_mask = flatmask
|
|
372
361
|
|
|
373
|
-
|
|
374
|
-
raise ValueError("luma_over_texture must be less than 1")
|
|
375
|
-
elif luma_over_texture < 0.0:
|
|
376
|
-
raise ValueError("luma_over_texture must be greater than 0")
|
|
377
|
-
final_mask = core.akarin.Expr(
|
|
378
|
-
[darken_luma_mask, flatmask],
|
|
379
|
-
f"x {luma_over_texture} * y {abs(luma_over_texture - 1)} * +",
|
|
380
|
-
)
|
|
362
|
+
final_mask = core.std.Merge(flatmask, darken_luma_mask, weight=luma_over_texture)
|
|
381
363
|
else:
|
|
382
364
|
final_mask = darken_luma_mask
|
|
383
365
|
|
|
384
366
|
if show_mask == 3:
|
|
385
367
|
selected_mask = final_mask
|
|
386
368
|
|
|
387
|
-
|
|
369
|
+
if "is_digital" in kwargs:
|
|
370
|
+
denoised = mini_BM3D(plane(clip, 0), ref=plane(degrain, 0), sigma=sigma, radius=tr, profile="HIGH")
|
|
371
|
+
else:
|
|
372
|
+
denoised = mini_BM3D(plane(degrain, 0), sigma=sigma, radius=tr, profile="HIGH")
|
|
388
373
|
y_denoised = core.std.MaskedMerge(
|
|
389
374
|
denoised, plane(clip, 0), final_mask
|
|
390
375
|
) # denoise applied to darker areas
|
|
@@ -414,7 +399,7 @@ class adenoise:
|
|
|
414
399
|
elif chroma_denoise[1] == "artcnn":
|
|
415
400
|
from vsscale import ArtCNN
|
|
416
401
|
|
|
417
|
-
chroma_denoised = ArtCNN.R8F64_JPEG420().scale(clip)
|
|
402
|
+
chroma_denoised = ArtCNN.R8F64_JPEG420(backend=backend).scale(clip)
|
|
418
403
|
weights = [
|
|
419
404
|
0,
|
|
420
405
|
chroma_denoise[0]
|
|
@@ -478,12 +463,13 @@ class adenoise:
|
|
|
478
463
|
fast: bool = True,
|
|
479
464
|
luma_mask_weaken: float = 0.9,
|
|
480
465
|
luma_mask_thr: float = 0.196,
|
|
481
|
-
chroma_denoise: float | tuple[float, str] = [0.5, "nlm"],
|
|
466
|
+
chroma_denoise: float | str | tuple[float, str] = [0.5, "nlm"],
|
|
482
467
|
precision: bool = True,
|
|
483
468
|
chroma_masking: bool = False,
|
|
484
469
|
show_mask: int = 0,
|
|
485
470
|
luma_over_texture: float = 0.4,
|
|
486
471
|
kwargs_flatmask: dict = {},
|
|
472
|
+
backend: Optional[BackendV2] = None,
|
|
487
473
|
) -> vs.VideoNode:
|
|
488
474
|
"""changes: thsad=200, sigma=2, luma_mask_weaken=0.9, chroma_strength=0.5"""
|
|
489
475
|
denoised = adenoise._adaptive_denoiser(
|
|
@@ -500,6 +486,7 @@ class adenoise:
|
|
|
500
486
|
luma_over_texture,
|
|
501
487
|
kwargs_flatmask,
|
|
502
488
|
show_mask,
|
|
489
|
+
backend=backend,
|
|
503
490
|
)
|
|
504
491
|
if show_mask in [1, 2, 3, 4, 5]:
|
|
505
492
|
return denoised
|
|
@@ -514,12 +501,13 @@ class adenoise:
|
|
|
514
501
|
fast: bool = True,
|
|
515
502
|
luma_mask_weaken: float = 0.8,
|
|
516
503
|
luma_mask_thr: float = 0.196,
|
|
517
|
-
chroma_denoise: float | tuple[float, str] = [0.7, "nlm"],
|
|
504
|
+
chroma_denoise: float | str | tuple[float, str] = [0.7, "nlm"],
|
|
518
505
|
precision: bool = True,
|
|
519
506
|
chroma_masking: bool = False,
|
|
520
507
|
show_mask: int = 0,
|
|
521
508
|
luma_over_texture: float = 0.4,
|
|
522
509
|
kwargs_flatmask: dict = {},
|
|
510
|
+
backend: Optional[BackendV2] = None,
|
|
523
511
|
) -> vs.VideoNode:
|
|
524
512
|
"""changes: thsad=400, sigma=4, luma_mask_weaken=0.8, chroma_strength=0.7"""
|
|
525
513
|
denoised = adenoise._adaptive_denoiser(
|
|
@@ -536,6 +524,7 @@ class adenoise:
|
|
|
536
524
|
luma_over_texture,
|
|
537
525
|
kwargs_flatmask,
|
|
538
526
|
show_mask,
|
|
527
|
+
backend=backend,
|
|
539
528
|
)
|
|
540
529
|
if show_mask in [1, 2, 3, 4, 5]:
|
|
541
530
|
return denoised
|
|
@@ -550,12 +539,13 @@ class adenoise:
|
|
|
550
539
|
fast: bool = True,
|
|
551
540
|
luma_mask_weaken: float = 0.75,
|
|
552
541
|
luma_mask_thr: float = 0.196,
|
|
553
|
-
chroma_denoise: float | tuple[float, str] = [1.0, "nlm"],
|
|
542
|
+
chroma_denoise: float | str | tuple[float, str] = [1.0, "nlm"],
|
|
554
543
|
precision: bool = True,
|
|
555
544
|
chroma_masking: bool = False,
|
|
556
545
|
show_mask: int = 0,
|
|
557
546
|
luma_over_texture: float = 0.4,
|
|
558
547
|
kwargs_flatmask: dict = {},
|
|
548
|
+
backend: Optional[BackendV2] = None,
|
|
559
549
|
) -> vs.VideoNode:
|
|
560
550
|
denoised = adenoise._adaptive_denoiser(
|
|
561
551
|
clip,
|
|
@@ -571,6 +561,7 @@ class adenoise:
|
|
|
571
561
|
luma_over_texture,
|
|
572
562
|
kwargs_flatmask,
|
|
573
563
|
show_mask,
|
|
564
|
+
backend=backend,
|
|
574
565
|
)
|
|
575
566
|
if show_mask in [1, 2, 3, 4, 5]:
|
|
576
567
|
return denoised
|
|
@@ -585,12 +576,13 @@ class adenoise:
|
|
|
585
576
|
fast: bool = False,
|
|
586
577
|
luma_mask_weaken: float = 0.75,
|
|
587
578
|
luma_mask_thr: float = 0.196,
|
|
588
|
-
chroma_denoise: float | tuple[float, str] = [1.5, "nlm"],
|
|
579
|
+
chroma_denoise: float | str | tuple[float, str] = [1.5, "nlm"],
|
|
589
580
|
precision: bool = True,
|
|
590
581
|
chroma_masking: bool = False,
|
|
591
582
|
show_mask: int = 0,
|
|
592
583
|
luma_over_texture: float = 0.4,
|
|
593
584
|
kwargs_flatmask: dict = {},
|
|
585
|
+
backend: Optional[BackendV2] = None,
|
|
594
586
|
) -> vs.VideoNode:
|
|
595
587
|
"""changes: thsad=800, sigma=12, luma_over_texture=0.4, fast=False"""
|
|
596
588
|
denoised = adenoise._adaptive_denoiser(
|
|
@@ -607,11 +599,12 @@ class adenoise:
|
|
|
607
599
|
luma_over_texture,
|
|
608
600
|
kwargs_flatmask,
|
|
609
601
|
show_mask,
|
|
602
|
+
backend=backend,
|
|
610
603
|
)
|
|
611
604
|
if show_mask in [1, 2, 3, 4, 5]:
|
|
612
605
|
return denoised
|
|
613
606
|
return denoised[0]
|
|
614
|
-
|
|
607
|
+
|
|
615
608
|
@staticmethod
|
|
616
609
|
def digital(
|
|
617
610
|
clip: vs.VideoNode,
|
|
@@ -621,12 +614,13 @@ class adenoise:
|
|
|
621
614
|
fast: bool = True,
|
|
622
615
|
luma_mask_weaken: float = 0.75,
|
|
623
616
|
luma_mask_thr: float = 0.196,
|
|
624
|
-
chroma_denoise: float | tuple[float, str] = [1.0, "nlm"],
|
|
617
|
+
chroma_denoise: float | str | tuple[float, str] = [1.0, "nlm"],
|
|
625
618
|
precision: bool = True,
|
|
626
619
|
chroma_masking: bool = False,
|
|
627
620
|
show_mask: int = 0,
|
|
628
621
|
luma_over_texture: float = 0.2,
|
|
629
622
|
kwargs_flatmask: dict = {},
|
|
623
|
+
backend: Optional[BackendV2] = None,
|
|
630
624
|
) -> vs.VideoNode:
|
|
631
625
|
"""changes: thsad=300, sigma=3, luma_over_texture=0.2"""
|
|
632
626
|
denoised = adenoise._adaptive_denoiser(
|
|
@@ -644,6 +638,46 @@ class adenoise:
|
|
|
644
638
|
kwargs_flatmask,
|
|
645
639
|
show_mask,
|
|
646
640
|
is_digital=True,
|
|
641
|
+
backend=backend,
|
|
642
|
+
)
|
|
643
|
+
if show_mask in [1, 2, 3, 4, 5]:
|
|
644
|
+
return denoised
|
|
645
|
+
return denoised[0]
|
|
646
|
+
|
|
647
|
+
@staticmethod
|
|
648
|
+
def bm3d(
|
|
649
|
+
clip: vs.VideoNode,
|
|
650
|
+
thsad: int = 500,
|
|
651
|
+
tr: int = 2,
|
|
652
|
+
sigma: float = 3,
|
|
653
|
+
fast: bool = True,
|
|
654
|
+
luma_mask_weaken: float = 0.75,
|
|
655
|
+
luma_mask_thr: float = 0.196,
|
|
656
|
+
chroma_denoise: float | str | tuple[float, str] = [1.0, "nlm"],
|
|
657
|
+
precision: bool = True,
|
|
658
|
+
chroma_masking: bool = False,
|
|
659
|
+
show_mask: int = 0,
|
|
660
|
+
luma_over_texture: float = 0.2,
|
|
661
|
+
kwargs_flatmask: dict = {},
|
|
662
|
+
backend: Optional[BackendV2] = None,
|
|
663
|
+
) -> vs.VideoNode:
|
|
664
|
+
"""changes: sigma=3, luma_over_texture=0.2"""
|
|
665
|
+
denoised = adenoise._adaptive_denoiser(
|
|
666
|
+
clip,
|
|
667
|
+
thsad,
|
|
668
|
+
tr,
|
|
669
|
+
sigma,
|
|
670
|
+
luma_mask_weaken,
|
|
671
|
+
luma_mask_thr,
|
|
672
|
+
chroma_denoise,
|
|
673
|
+
precision,
|
|
674
|
+
fast,
|
|
675
|
+
chroma_masking,
|
|
676
|
+
luma_over_texture,
|
|
677
|
+
kwargs_flatmask,
|
|
678
|
+
show_mask,
|
|
679
|
+
is_bm3d_only=True,
|
|
680
|
+
backend=backend,
|
|
647
681
|
)
|
|
648
682
|
if show_mask in [1, 2, 3, 4, 5]:
|
|
649
683
|
return denoised
|
|
@@ -658,12 +692,13 @@ class adenoise:
|
|
|
658
692
|
fast: bool = True,
|
|
659
693
|
luma_mask_weaken: float = 0.75,
|
|
660
694
|
luma_mask_thr: float = 0.196,
|
|
661
|
-
chroma_denoise: float | tuple[float, str] = [1.0, "nlm"],
|
|
695
|
+
chroma_denoise: float | str | tuple[float, str] = [1.0, "nlm"],
|
|
662
696
|
precision: bool = True,
|
|
663
697
|
chroma_masking: bool = False,
|
|
664
698
|
show_mask: int = 0,
|
|
665
699
|
luma_over_texture: float = 0.4,
|
|
666
700
|
kwargs_flatmask: dict = {},
|
|
701
|
+
backend: Optional[BackendV2] = None,
|
|
667
702
|
) -> vs.VideoNode:
|
|
668
703
|
"""default profile"""
|
|
669
704
|
denoised = adenoise._adaptive_denoiser(
|
|
@@ -680,6 +715,7 @@ class adenoise:
|
|
|
680
715
|
luma_over_texture,
|
|
681
716
|
kwargs_flatmask,
|
|
682
717
|
show_mask,
|
|
718
|
+
backend=backend,
|
|
683
719
|
)
|
|
684
720
|
if show_mask in [1, 2, 3, 4, 5]:
|
|
685
721
|
return denoised
|
|
@@ -738,21 +774,26 @@ def auto_deblock(
|
|
|
738
774
|
def msaa2x(
|
|
739
775
|
clip: vs.VideoNode,
|
|
740
776
|
ref: Optional[vs.VideoNode] = None,
|
|
741
|
-
|
|
777
|
+
show_mask: bool = False,
|
|
778
|
+
edgemask: Optional[vs.VideoNode] = None,
|
|
742
779
|
sigma: float = 3,
|
|
743
780
|
thr: float = None,
|
|
781
|
+
strength: float = None,
|
|
744
782
|
planes: PlanesT = 0,
|
|
783
|
+
backend: Optional[BackendV2] = None,
|
|
745
784
|
**kwargs,
|
|
746
|
-
) -> vs.VideoNode:
|
|
785
|
+
) -> vs.VideoNode | tuple[vs.VideoNode, vs.VideoNode]:
|
|
747
786
|
"""
|
|
748
787
|
Upscales only the edges with AI (ArtCNN DN) and downscales them.
|
|
749
788
|
|
|
750
789
|
:param clip: Clip to process (YUV or Grayscale).
|
|
751
790
|
:param planes: Which planes to process. Defaults to Y.
|
|
752
791
|
:param ref: Reference clip used to create the edgemask (should be a denoised clip). If None, clip will be used and will be denoised with adenoise.digital to prevent edge detail loss, but remove grain and noise.
|
|
753
|
-
:param
|
|
792
|
+
:param show_mask: If True, returns a tuple containing the processed clip and the mask used.
|
|
793
|
+
:param edgemask: Pre-computed edgemask. If None, it will be computed internally.
|
|
754
794
|
:param sigma: Sigma used for edge fixing during antialiasing (remove dirty spots and blocking) only if ref is None.
|
|
755
795
|
:param thr: Threshold used for Binarize the clip, only 0-1 value area allowed. If None, no Binarize will be applied.
|
|
796
|
+
:param strength: Strength of the final merge between the original clip and the upscaled clip. 0-1 values accepted.
|
|
756
797
|
:param kwargs: Accepts advanced_edgemask arguments.
|
|
757
798
|
"""
|
|
758
799
|
from vsscale import ArtCNN
|
|
@@ -770,35 +811,35 @@ def msaa2x(
|
|
|
770
811
|
|
|
771
812
|
clip = depth(clip, 16, dither_type="none")
|
|
772
813
|
|
|
773
|
-
if
|
|
774
|
-
ref
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
814
|
+
if edgemask is None:
|
|
815
|
+
if ref is None:
|
|
816
|
+
ref = adenoise.digital(
|
|
817
|
+
clip,
|
|
818
|
+
sigma=sigma,
|
|
819
|
+
precision=False,
|
|
820
|
+
chroma_denoise=[(0 if (1 in planes or 2 in planes) else 2), "cbm3d"],
|
|
821
|
+
backend=backend,
|
|
822
|
+
)
|
|
823
|
+
|
|
824
|
+
if len(planes) == 1:
|
|
825
|
+
edgemask = advanced_edgemask(plane(ref, 0), **kwargs)
|
|
826
|
+
else:
|
|
827
|
+
masks = [
|
|
828
|
+
advanced_edgemask(plane(ref, p), **kwargs)
|
|
829
|
+
if p in planes
|
|
830
|
+
else plane(ref, p).std.BlankClip()
|
|
831
|
+
for p in range(3)
|
|
832
|
+
]
|
|
833
|
+
edgemask = core.std.ShufflePlanes(
|
|
834
|
+
masks, planes=[0, 0, 0], colorfamily=ref.format.color_family
|
|
835
|
+
)
|
|
793
836
|
|
|
794
837
|
if thr is not None and thr != 0:
|
|
795
838
|
edgemask = edgemask.std.Binarize(
|
|
796
839
|
threshold=scale_binary_value(edgemask, thr, return_int=True)
|
|
797
840
|
)
|
|
798
|
-
if mask:
|
|
799
|
-
return edgemask
|
|
800
841
|
|
|
801
|
-
upscaled = ArtCNN.C4F32_DN().
|
|
842
|
+
upscaled = ArtCNN.C4F32_DN(backend=backend).supersample(clip, 2)
|
|
802
843
|
downscaled = core.resize.Bicubic(upscaled, clip.width, clip.height)
|
|
803
844
|
aa = core.std.MaskedMerge(clip, downscaled, edgemask, planes=0)
|
|
804
845
|
|
|
@@ -807,7 +848,7 @@ def msaa2x(
|
|
|
807
848
|
aa = core.std.ShufflePlanes(
|
|
808
849
|
[aa, lefted, lefted], planes=[0, 1, 2], colorfamily=clip.format.color_family
|
|
809
850
|
)
|
|
810
|
-
aa = ArtCNN.R8F64_Chroma().scale(aa)
|
|
851
|
+
aa = ArtCNN.R8F64_Chroma(backend=backend).scale(aa)
|
|
811
852
|
chroma_downscaled = core.resize.Bicubic(aa, clip.width / 2, clip.height / 2)
|
|
812
853
|
u = plane(chroma_downscaled, 1)
|
|
813
854
|
v = plane(chroma_downscaled, 2)
|
|
@@ -818,4 +859,10 @@ def msaa2x(
|
|
|
818
859
|
)
|
|
819
860
|
aa = core.std.MaskedMerge(clip, all_downscaled, edgemask, planes=planes)
|
|
820
861
|
|
|
862
|
+
if strength is not None or strength != 0:
|
|
863
|
+
aa = core.std.Merge(aa, clip, weight=strength)
|
|
864
|
+
|
|
865
|
+
if show_mask:
|
|
866
|
+
return aa, edgemask
|
|
867
|
+
|
|
821
868
|
return aa
|
|
@@ -11,6 +11,16 @@ if not (
|
|
|
11
11
|
)
|
|
12
12
|
|
|
13
13
|
|
|
14
|
+
def _morpho_radius(clip: vs.VideoNode, radius: int, **kwargs) -> vs.VideoNode:
|
|
15
|
+
"""Helper to dynamically switch between expand and inpand based on sign."""
|
|
16
|
+
from vsmasktools import Morpho, XxpandMode
|
|
17
|
+
|
|
18
|
+
if radius == 0:
|
|
19
|
+
return clip
|
|
20
|
+
op = Morpho.expand if radius > 0 else Morpho.inpand
|
|
21
|
+
return op(clip, sw=abs(radius), sh=abs(radius), mode=XxpandMode.ELLIPSE, **kwargs)
|
|
22
|
+
|
|
23
|
+
|
|
14
24
|
def _soft_threshold(
|
|
15
25
|
clip: vs.VideoNode, thr: float, steepness: float = 20.0
|
|
16
26
|
) -> vs.VideoNode:
|
|
@@ -293,7 +303,7 @@ def advanced_edgemask(
|
|
|
293
303
|
:param kirsch_weight: Weight for Kirsch edges in final blend (0-1). Default: 0.7.
|
|
294
304
|
:param kirsch_thr: Kirsch threshold. Default: 0.25.
|
|
295
305
|
:param edge_thr: Threshold for edge combination logic (0-1). Default: 0.02.
|
|
296
|
-
:param expand: Expand the mask by a given number of pixels. Default: 0.
|
|
306
|
+
:param expand: Expand or inpand the mask by a given number of pixels. Default: 0.
|
|
297
307
|
:param kwargs: Additional arguments for Retinex.
|
|
298
308
|
:return: Edge mask (Gray clip).
|
|
299
309
|
"""
|
|
@@ -386,11 +396,7 @@ def advanced_edgemask(
|
|
|
386
396
|
f"x y + {edge_thr_scaled} < x y + z {kirsch_weight} * + x y + ?",
|
|
387
397
|
)
|
|
388
398
|
|
|
389
|
-
return (
|
|
390
|
-
mask
|
|
391
|
-
if expand == 0
|
|
392
|
-
else Morpho.expand(mask, mode=XxpandMode.ELLIPSE, sw=expand, sh=expand)
|
|
393
|
-
)
|
|
399
|
+
return _morpho_radius(mask, expand)
|
|
394
400
|
|
|
395
401
|
|
|
396
402
|
def hd_flatmask(
|
|
@@ -398,7 +404,7 @@ def hd_flatmask(
|
|
|
398
404
|
ref: Optional[vs.VideoNode] = None,
|
|
399
405
|
sigma1: float = 3,
|
|
400
406
|
retinex_sigma: list[float] = [50, 200, 350],
|
|
401
|
-
sigma2: float = 1,
|
|
407
|
+
sigma2: float = 1.5,
|
|
402
408
|
sharpness: float = 0.8,
|
|
403
409
|
edge_thr: float = 0.55,
|
|
404
410
|
texture_strength: float = 2,
|
|
@@ -418,16 +424,16 @@ def hd_flatmask(
|
|
|
418
424
|
:param ref: Optional reference clip for denoising.
|
|
419
425
|
:param sigma1: BM3D sigma for initial denoising. Default: 3.
|
|
420
426
|
:param retinex_sigma: Sigma values for Multi-Scale Retinex. Default: [50, 200, 350].
|
|
421
|
-
:param sigma2: Nlmeans strength for post-Retinex denoising. Default: 1.
|
|
427
|
+
:param sigma2: Nlmeans strength for post-Retinex denoising. Default: 1.5.
|
|
422
428
|
:param sharpness: CAS sharpening amount (0-1). Default: 0.8.
|
|
423
429
|
:param edge_thr: Threshold for edge combination logic (0-1). This allows to separate edges from texture. Default: 0.55.
|
|
424
430
|
:param texture_strength: Texture strength for mask (0-inf). Values above 1 decrese the strength of the texture in the mask, lower values increase it. The max value is theoretical infinite, but there is no gain after some point. Default: 0.8.
|
|
425
431
|
:param edges_strength: Edges strength for mask (0-1). Basic multiplier for edges strength. Default: 0.03.
|
|
426
|
-
:param blur:
|
|
427
|
-
:param expand: Expand amount for mask
|
|
432
|
+
:param blur: Gauss blur sigma for mask. Default: 2.
|
|
433
|
+
:param expand: Expand or inpand (idk why you'd want to do this) amount for mask. Higher value expands the size of the texture in the mask. Default: 3.
|
|
428
434
|
:param kwargs: Additional arguments for Retinex.
|
|
429
435
|
|
|
430
|
-
:return: Edge mask (Gray clip) where
|
|
436
|
+
:return: Edge mask (Gray clip) where bright values are texture and edges, dark values are flat areas.
|
|
431
437
|
"""
|
|
432
438
|
|
|
433
439
|
from vstools import depth
|
|
@@ -485,7 +491,7 @@ def hd_flatmask(
|
|
|
485
491
|
dither_type="none",
|
|
486
492
|
)
|
|
487
493
|
|
|
488
|
-
msrcp = nl_means(msrcpa, h=sigma2, a=
|
|
494
|
+
msrcp = nl_means(msrcpa, h=sigma2, a=3)
|
|
489
495
|
|
|
490
496
|
if sharpness > 0:
|
|
491
497
|
msrcp = core.cas.CAS(msrcp, sharpness=sharpness, opt=0, planes=0)
|
|
@@ -521,9 +527,7 @@ def hd_flatmask(
|
|
|
521
527
|
|
|
522
528
|
edges_expanded = Morpho.expand(edgescombo, mode=XxpandMode.ELLIPSE, sw=1, sh=1)
|
|
523
529
|
kirco_diff = core.akarin.Expr([kirco, edges_expanded], "x y -")
|
|
524
|
-
kirco_expanded =
|
|
525
|
-
kirco_diff, mode=XxpandMode.ELLIPSE, sw=expand, sh=expand
|
|
526
|
-
)
|
|
530
|
+
kirco_expanded = _morpho_radius(kirco_diff, expand)
|
|
527
531
|
|
|
528
532
|
edgescombo = core.akarin.Expr(
|
|
529
533
|
edgescombo.std.Invert(),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import vapoursynth as vs
|
|
2
2
|
from typing import SupportsIndex, Optional, List, Tuple, Union
|
|
3
|
+
from vstools import PlanesT
|
|
3
4
|
|
|
4
5
|
|
|
5
6
|
def plane(clip: vs.VideoNode, index: SupportsIndex) -> vs.VideoNode:
|
|
@@ -224,3 +225,70 @@ def diff_and_swap(
|
|
|
224
225
|
selected = None
|
|
225
226
|
|
|
226
227
|
return merged, selected
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def smart_CAS(
|
|
231
|
+
clip: vs.VideoNode,
|
|
232
|
+
sharpness: float = 0.5,
|
|
233
|
+
strength: float = 0.5,
|
|
234
|
+
texture: bool = False,
|
|
235
|
+
mask: Union[vs.VideoNode, int, None] = None,
|
|
236
|
+
# character_masking: bool = False,
|
|
237
|
+
planes: PlanesT = 0,
|
|
238
|
+
show_mask: bool = False,
|
|
239
|
+
**kwargs,
|
|
240
|
+
) -> vs.VideoNode:
|
|
241
|
+
"""
|
|
242
|
+
Applies Contrast Adaptive Sharpening (CAS) with optional masking and strength control.
|
|
243
|
+
|
|
244
|
+
:param clip: Input video clip.
|
|
245
|
+
:param sharpness: Sharpening intensity (0.0 - 1.0). Default is 0.5.
|
|
246
|
+
:param strength: Mixing factor to dilute the sharpening effect (0.0 - 1.0).
|
|
247
|
+
0.0 means full CAS force, while 1.0 returns the original clip.
|
|
248
|
+
Default is 0.5.
|
|
249
|
+
:param texture: If True, uses hd_flatmask for masking. If False, uses advanced_edgemask.
|
|
250
|
+
Ignored if a custom mask is provided. Default is False.
|
|
251
|
+
:param mask: Custom mask for sharpening. If None, a mask is generated.
|
|
252
|
+
The sharpened clip is applied where the mask is white (light).
|
|
253
|
+
If set to 0 (int), returns the sharpened clip without any masking.
|
|
254
|
+
:param planes: List of planes to process. Default is plane 0 (Luma).
|
|
255
|
+
:param show_mask: If True, returns the mask instead of the sharpened clip.
|
|
256
|
+
:param kwargs: Additional arguments passed to the mask generation functions.
|
|
257
|
+
|
|
258
|
+
:return: Sharpened video clip with masking applied to detail areas (unless mask=0).
|
|
259
|
+
"""
|
|
260
|
+
core = vs.core
|
|
261
|
+
from vsrgtools import gauss_blur
|
|
262
|
+
|
|
263
|
+
cassed = core.cas.CAS(clip, sharpness=sharpness, planes=planes, opt=0)
|
|
264
|
+
|
|
265
|
+
if strength != 0.0:
|
|
266
|
+
cassed = core.std.Merge(cassed, clip, weight=strength)
|
|
267
|
+
|
|
268
|
+
if isinstance(mask, vs.VideoNode):
|
|
269
|
+
if show_mask:
|
|
270
|
+
return mask
|
|
271
|
+
return core.std.MaskedMerge(clip, cassed, mask, planes=planes)
|
|
272
|
+
elif mask is None:
|
|
273
|
+
mask_expand = kwargs.pop("expand", -1)
|
|
274
|
+
|
|
275
|
+
if texture:
|
|
276
|
+
from .admask import hd_flatmask
|
|
277
|
+
|
|
278
|
+
mask = hd_flatmask(clip, expand=mask_expand, **kwargs)
|
|
279
|
+
mask = gauss_blur(mask, sigma=1, planes=planes)
|
|
280
|
+
if show_mask:
|
|
281
|
+
return mask
|
|
282
|
+
return core.std.MaskedMerge(clip, cassed, mask, planes=planes)
|
|
283
|
+
else:
|
|
284
|
+
from .admask import advanced_edgemask
|
|
285
|
+
|
|
286
|
+
mask = advanced_edgemask(clip, expand=mask_expand, **kwargs)
|
|
287
|
+
mask = gauss_blur(mask, sigma=1, planes=planes)
|
|
288
|
+
if show_mask:
|
|
289
|
+
return mask
|
|
290
|
+
return core.std.MaskedMerge(clip, cassed, mask, planes=planes)
|
|
291
|
+
elif isinstance(mask, int) and mask == 0:
|
|
292
|
+
return cassed
|
|
293
|
+
else:
|
|
294
|
+
raise vs.Error("smart_CAS: mask must be a VideoNode or None")
|