vsdirty 0.1.0__py3-none-any.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.
- vsdirty/__init__.py +8 -0
- vsdirty/adfunc.py +554 -0
- vsdirty/admask.py +480 -0
- vsdirty/adutils.py +208 -0
- vsdirty/dirtyfixer.py +113 -0
- vsdirty-0.1.0.dist-info/METADATA +174 -0
- vsdirty-0.1.0.dist-info/RECORD +10 -0
- vsdirty-0.1.0.dist-info/WHEEL +5 -0
- vsdirty-0.1.0.dist-info/licenses/LICENSE +21 -0
- vsdirty-0.1.0.dist-info/top_level.txt +1 -0
vsdirty/dirtyfixer.py
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import vapoursynth as vs
|
|
2
|
+
from typing import List
|
|
3
|
+
from vstools import PlanesT
|
|
4
|
+
from vstools import depth
|
|
5
|
+
from .adutils import plane
|
|
6
|
+
|
|
7
|
+
core = vs.core
|
|
8
|
+
|
|
9
|
+
if not (hasattr(vs.core, 'fmtc') or hasattr(vs.core, 'bore')):
|
|
10
|
+
raise ImportError("'fmtc' and 'libbore' are mandatory. Make sure the DLLs are present in the plugins folder.")
|
|
11
|
+
|
|
12
|
+
def bore(
|
|
13
|
+
clip : vs.VideoNode,
|
|
14
|
+
ythickness: List[int] = None,
|
|
15
|
+
uthickness: List[int] = None,
|
|
16
|
+
vthickness: List[int] = None,
|
|
17
|
+
planes: PlanesT = 0,
|
|
18
|
+
singlePlane = True,
|
|
19
|
+
**kwargs
|
|
20
|
+
) -> vs.VideoNode:
|
|
21
|
+
"""
|
|
22
|
+
Apply bore filter to clip's edges to remove dirty lines.
|
|
23
|
+
|
|
24
|
+
Processes selected planes at their native resolution to avoid
|
|
25
|
+
unnecessary scaling artifacts. Uses full resolution for luma,
|
|
26
|
+
native chroma resolution for chroma planes.
|
|
27
|
+
|
|
28
|
+
Only bore.SinglePlane and bore.MultiPlane are implemented, the other functions will probably never be implemented.
|
|
29
|
+
|
|
30
|
+
:param clip: Input clip (YUV or GRAY, RGB not supported)
|
|
31
|
+
:param ythickness: List of luma border thicknesses to process. [top, bottom, left, right]. 0 means no processing.
|
|
32
|
+
:param uthickness: List of chroma U border thicknesses to process. [top, bottom, left, right]. 0 means no processing. if None, uses ythickness or vthickness if is not None.
|
|
33
|
+
:param vthickness: List of chroma V border thicknesses to process. [top, bottom, left, right]. 0 means no processing. if None, uses ythickness or uthickness if is not None.
|
|
34
|
+
:param planes: Plane(s) to process.
|
|
35
|
+
:param singlePlane: If True uses bore.SinglePlane, otherwise bore.MultiPlane. MultiPlane cannot be used with GRAY clips.
|
|
36
|
+
:return: Processed clip with corrected borders, same format as input
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
if ythickness is None:
|
|
40
|
+
ythickness = [1,1,1,1]
|
|
41
|
+
|
|
42
|
+
if clip.format.color_family == vs.RGB:
|
|
43
|
+
raise ValueError("bore: RGB clips are not supported.")
|
|
44
|
+
|
|
45
|
+
if planes is None:
|
|
46
|
+
raise ValueError("bore: planes cannot be None.")
|
|
47
|
+
|
|
48
|
+
if isinstance(planes, int):
|
|
49
|
+
planes = [planes]
|
|
50
|
+
|
|
51
|
+
def _get_tblr(thick):
|
|
52
|
+
if len(thick) == 2:
|
|
53
|
+
t, b = thick
|
|
54
|
+
l, r = 0, 0
|
|
55
|
+
elif len(thick) == 4:
|
|
56
|
+
t, b, l, r = thick
|
|
57
|
+
else:
|
|
58
|
+
t = thick[0] if len(thick) > 0 else 0
|
|
59
|
+
b = thick[1] if len(thick) > 1 else t
|
|
60
|
+
l = thick[2] if len(thick) > 2 else 0
|
|
61
|
+
r = thick[3] if len(thick) > 3 else l
|
|
62
|
+
return t, b, l, r
|
|
63
|
+
|
|
64
|
+
if uthickness is None:
|
|
65
|
+
if vthickness is not None:
|
|
66
|
+
uthickness = vthickness
|
|
67
|
+
else:
|
|
68
|
+
uthickness = ythickness
|
|
69
|
+
if vthickness is None:
|
|
70
|
+
if uthickness is not None:
|
|
71
|
+
vthickness = uthickness
|
|
72
|
+
else:
|
|
73
|
+
vthickness = ythickness
|
|
74
|
+
|
|
75
|
+
yt, yb, yl, yr = _get_tblr(ythickness)
|
|
76
|
+
ut, ub, ul, ur = _get_tblr(uthickness)
|
|
77
|
+
vt, vb, vl, vr = _get_tblr(vthickness)
|
|
78
|
+
|
|
79
|
+
if clip.format.color_family == vs.GRAY:
|
|
80
|
+
upclip = clip.resize.Bicubic(format=vs.YUV444PS)
|
|
81
|
+
fixY = plane(depth(core.bore.SinglePlane(upclip, top=yt, bottom=yb, left=yl, right=yr, plane=0), clip.format.bits_per_sample), 0)
|
|
82
|
+
return fixY
|
|
83
|
+
|
|
84
|
+
fixY = plane(clip, 0)
|
|
85
|
+
fixU = plane(clip, 1)
|
|
86
|
+
fixV = plane(clip, 2)
|
|
87
|
+
|
|
88
|
+
if 0 in planes:
|
|
89
|
+
upclip = clip.resize.Bicubic(format=vs.YUV444PS)
|
|
90
|
+
if singlePlane:
|
|
91
|
+
fixY = plane(depth(core.bore.SinglePlane(upclip, top=yt, bottom=yb, left=yl, right=yr, plane=0), clip.format.bits_per_sample), 0)
|
|
92
|
+
else:
|
|
93
|
+
fixY = plane(depth(core.bore.MultiPlane(upclip, top=yt, bottom=yb, left=yl, right=yr, plane=0), clip.format.bits_per_sample), 0)
|
|
94
|
+
|
|
95
|
+
if 1 in planes:
|
|
96
|
+
upclip = clip.resize.Bicubic(width=plane(clip, 1).width, height=plane(clip, 1).height, format=vs.YUV444PS)
|
|
97
|
+
upclip = core.std.ShufflePlanes([upclip, depth(clip,32), depth(clip,32)], planes=[0, 1, 2], colorfamily=vs.YUV)
|
|
98
|
+
if singlePlane:
|
|
99
|
+
fixU = plane(depth(core.bore.SinglePlane(upclip, top=ut, bottom=ub, left=ul, right=ur, plane=1), clip.format.bits_per_sample), 1)
|
|
100
|
+
else:
|
|
101
|
+
fixU = plane(depth(core.bore.MultiPlane(upclip, top=ut, bottom=ub, left=ul, right=ur, plane=1), clip.format.bits_per_sample), 1)
|
|
102
|
+
|
|
103
|
+
if 2 in planes:
|
|
104
|
+
upclip = clip.resize.Bicubic(width=plane(clip, 2).width, height=plane(clip, 2).height, format=vs.YUV444PS)
|
|
105
|
+
upclip = core.std.ShufflePlanes([upclip, depth(clip,32), depth(clip,32)], planes=[0, 1, 2], colorfamily=vs.YUV)
|
|
106
|
+
if singlePlane:
|
|
107
|
+
fixV = plane(depth(core.bore.SinglePlane(upclip, top=vt, bottom=vb, left=vl, right=vr, plane=2), clip.format.bits_per_sample), 2)
|
|
108
|
+
else:
|
|
109
|
+
fixV = plane(depth(core.bore.MultiPlane(upclip, top=vt, bottom=vb, left=vl, right=vr, plane=2), clip.format.bits_per_sample), 2)
|
|
110
|
+
|
|
111
|
+
merged = core.std.ShufflePlanes([fixY, fixU, fixV], planes=[0, 0, 0], colorfamily=vs.YUV)
|
|
112
|
+
|
|
113
|
+
return merged
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vsdirty
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: VapourSynth wrappers for denoising, masking and edge fixing
|
|
5
|
+
Author: PingWer, Mhanz3500
|
|
6
|
+
Project-URL: Homepage, https://github.com/r74mi/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.10
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Requires-Dist: vapoursynth>=70
|
|
14
|
+
Requires-Dist: vstools
|
|
15
|
+
Requires-Dist: vsjetpack==1.1.0
|
|
16
|
+
Dynamic: license-file
|
|
17
|
+
|
|
18
|
+
# vs-dirty
|
|
19
|
+
|
|
20
|
+
A collection of VapourSynth wrappers and utility functions focused on advanced denoising, masking, and edge fixing.
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
You can install `vsdirty` via pip:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install vsdirty
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Or build from source:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
git clone https://github.com/r74mi/vs-dirty.git
|
|
34
|
+
cd vs-dirty
|
|
35
|
+
pip install .
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Dependencies
|
|
39
|
+
|
|
40
|
+
This package relies on several external VapourSynth plugins. Ensure these are installed and available in your VapourSynth plugins folder.
|
|
41
|
+
|
|
42
|
+
| Plugin | URL |
|
|
43
|
+
| :--- | :--- |
|
|
44
|
+
| **fmtc** | [GitLab](https://gitlab.com/EleonoreMizo/fmtconv/) |
|
|
45
|
+
| **akarin** | [GitHub](https://github.com/AkarinVS/vapoursynth-plugin) |
|
|
46
|
+
| **cas** | [GitHub](https://github.com/HomeOfVapourSynthEvolution/VapourSynth-CAS) |
|
|
47
|
+
| **bore** | [GitHub](https://github.com/OpusGang/bore) |
|
|
48
|
+
| **mvtools** | [GitHub](https://github.com/dubhater/vapoursynth-mvtools) |
|
|
49
|
+
| **BM3DCuda** | [GitHub](https://github.com/WolframRhodium/VapourSynth-BM3DCUDA) |
|
|
50
|
+
| **nlm-cuda** | [GitHub](https://github.com/AmusementClub/vs-nlm-cuda) |
|
|
51
|
+
| **vsmlrt** | [GitHub](https://github.com/AmusementClub/vs-mlrt) |
|
|
52
|
+
|
|
53
|
+
## `adenoise`
|
|
54
|
+
|
|
55
|
+
Designed specifically for film content, this intensive adaptive denoiser removes noise while carefully preserving fine textures and small elements. It combines `mc_degrain` (luma), `NLMeans`/`CBM3D` (chroma), and `BM3D` (luma), all modulated by adaptive masking.
|
|
56
|
+
|
|
57
|
+
**Presets:**
|
|
58
|
+
- `scan65mm` (Light)
|
|
59
|
+
- `scan35mm` (Medium)
|
|
60
|
+
- `scan16mm` (Heavy)
|
|
61
|
+
- `scan8mm` (Very Heavy)
|
|
62
|
+
- `digital` (Optimized for digital sources)
|
|
63
|
+
- `default` (Generic)
|
|
64
|
+
|
|
65
|
+
**Parameters:**
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
adenoise.default(clip: vs.VideoNode,
|
|
69
|
+
thsad: int = 500,
|
|
70
|
+
tr: int = 2,
|
|
71
|
+
sigma: float = 6,
|
|
72
|
+
luma_mask_weaken: float = 0.75,
|
|
73
|
+
luma_mask_thr: float = 0.196,
|
|
74
|
+
chroma_denoise: float | tuple[float, str] = [1.0, "nlm"],
|
|
75
|
+
precision: bool = True,
|
|
76
|
+
chroma_masking: bool = False,
|
|
77
|
+
show_mask: int = 0,
|
|
78
|
+
luma_over_texture: float = 0.4,
|
|
79
|
+
kwargs_flatmask: dict = {})
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
- `clip`: Clip to process (YUV or GRAY 16bit, if not will be internally converted in 16bit).
|
|
83
|
+
- `thsad`: Thsad for mc_degrain (luma denoise strength and chroma ref).
|
|
84
|
+
Recommended values: 300-800
|
|
85
|
+
- `tr`: Temporal radius for temporal consistency across al the filter involved.
|
|
86
|
+
Recommended values: 2-3 (1 means no temporal denoise).
|
|
87
|
+
- `sigma`: Sigma for BM3D (luma denoise strength).
|
|
88
|
+
Recommended values: 1-5.
|
|
89
|
+
- `luma_mask_weaken`: Controls how much dark spots should be denoised. Lower values mean stronger overall denoise.
|
|
90
|
+
Recommended values: 0.6-0.9
|
|
91
|
+
- `luma_mask_thr`: Threshold that determines what is considered bright and what is dark in the luma mask.
|
|
92
|
+
Recommended values: 0.15-0.25
|
|
93
|
+
- `chroma_denoise`: Denoiser strength and type for chroma. NLMeans/CBM3D/ArtCNN.
|
|
94
|
+
Reccomended strength values: 0.5-2. If not given, 1.0 is used (or none for ArtCNN).
|
|
95
|
+
Accepted denoiser types: "nlm", "cbm3d", "artcnn". If not given, nlm is used.
|
|
96
|
+
- `precision`: If True, a flat mask is created to enhance the denoise strenght on flat areas avoiding textured area (95% accuracy).
|
|
97
|
+
- `chroma_masking`: If True, enables specific chroma masking for U/V planes.
|
|
98
|
+
- `show_mask`: 1 = Show the first luma mask, 2 = Show the textured luma mask, 3 = Show the complete luma mask, 4 = Show the Chroma U Plane mask (if chroma_masking = True), 5 = Show the Chroma V Plane mask (if chroma_masking = True). Any other value returns the denoised clip.
|
|
99
|
+
- `luma_over_texture`: Multiplier for the luma mask in precision mode. Lower value means more importance to textured areas, higher value means more importance to luma levels.
|
|
100
|
+
Accepted values: 0.0-1.0
|
|
101
|
+
- `kwargs_flatmask`: Additional arguments for flatmask creation.
|
|
102
|
+
dict values (check `hd_flatmask`'s docstring for more info):
|
|
103
|
+
- `sigma1`: This value should be decided based on the details level of the clip and how much grain and noise is present. Usually 1 for really textured clip, 2-3 for a normal clip, 4-5 for a clip with strong noise or grain.
|
|
104
|
+
- `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.
|
|
105
|
+
- `edges_strength`: Edges strength for mask (0-1). Basic multiplier for edges strength.
|
|
106
|
+
|
|
107
|
+
- `return`: 16bit denoised clip. If show_mask is 1, 2, 3, 4 or 5, returns a tuple (denoised_clip, mask).
|
|
108
|
+
|
|
109
|
+
**Usage:**
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
from vsdirty import adenoise
|
|
113
|
+
|
|
114
|
+
# Apply default adaptive denoising
|
|
115
|
+
denoised = adenoise.scan16mm(clip)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
## `bore`
|
|
120
|
+
|
|
121
|
+
A powerful edge cleaner (dirty line fixer) that processes borders at their native resolution to avoid scaling artifacts.
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from vsdirty import bore
|
|
125
|
+
|
|
126
|
+
# Fix dirty lines: Top=1px, Bottom=1px, Left=2px, Right=2px
|
|
127
|
+
clean = bore(clip, ythickness=[1, 1, 2, 2])
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## `msaa2x`
|
|
131
|
+
|
|
132
|
+
An antialiaser based on ArtCNN that targets specific edges to reduce aliasing without blurring textures.
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
from vsdirty import adfunc
|
|
136
|
+
|
|
137
|
+
# Apply antialiasing
|
|
138
|
+
aa_clip = adfunc.msaa2x(clip)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## `advanced_edgemask`
|
|
142
|
+
|
|
143
|
+
Generates a high-quality edge mask by combining Retinex preprocessing with multiple edge detectors (Kirsch, Sobel) to capture faint and complex edges.
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
from vsdirty import admask
|
|
147
|
+
|
|
148
|
+
emask = admask.advanced_edgemask(clip, luma_scaling=10)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## `hd_flatmask`
|
|
152
|
+
|
|
153
|
+
A specialized mask for flat areas, useful for protecting textures or targeting specific flat regions for filtering.
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
from vsdirty import admask
|
|
157
|
+
|
|
158
|
+
flat_mask = admask.hd_flatmask(clip)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## `diff_and_swap`
|
|
162
|
+
|
|
163
|
+
A utility to repair damaged frames in a "base" clip using a "correction" clip. It compares frames and swaps them if the difference exceeds a threshold.
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
from vsdirty import adutils
|
|
167
|
+
|
|
168
|
+
# automated patching
|
|
169
|
+
repaired, _ = adutils.diff_and_swap(correction_clip, base_clip, thr=30000)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## License
|
|
173
|
+
|
|
174
|
+
MIT License
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
vsdirty/__init__.py,sha256=zonL-cH2iKwEiu0TC3WKa-EQjyDmkKicN04NMIN5OnY,182
|
|
2
|
+
vsdirty/adfunc.py,sha256=-zXnWU76m-xZZWerAXLhWtWlBz90tUe3olhD18iqAew,28701
|
|
3
|
+
vsdirty/admask.py,sha256=cOqndbegtgnLBti6ABUrPXzby3xFqUNCq5GcAz-HJdI,17530
|
|
4
|
+
vsdirty/adutils.py,sha256=s9MHtFghwjZp9W160yWb5zVeBehC3KloK4kXDSBgFsc,7702
|
|
5
|
+
vsdirty/dirtyfixer.py,sha256=qAUvpliKHYp0Ivc6HIwkU9jFFnqv_VW7M12iuK4KLRQ,4934
|
|
6
|
+
vsdirty-0.1.0.dist-info/licenses/LICENSE,sha256=ytBUIbwDXahKm15kCB5kJy6kyFzwccf64igR1vKikNk,1075
|
|
7
|
+
vsdirty-0.1.0.dist-info/METADATA,sha256=9WusOZqR6z67-YXsf4H9x_KNcK8QlWlnkGjeQ2cxNj8,6612
|
|
8
|
+
vsdirty-0.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
9
|
+
vsdirty-0.1.0.dist-info/top_level.txt,sha256=2bWQbCuQp4y6_hKaWKvP8Ysc5-Z_0NRM01wKZYt8_7o,8
|
|
10
|
+
vsdirty-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 PingWer, Mhanz3500
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
vsdirty
|