-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d5529c9
commit 43f6e95
Showing
16 changed files
with
5,324 additions
and
162 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
[flake8] | ||
count = True | ||
ignore = W503,E226 | ||
max-line-length = 120 | ||
exclude = stubs/* | ||
show-source = True | ||
statistics = True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,28 @@ | ||
debandshit, a collection of wrappers and functions | ||
for debanding and masking. | ||
# debandshit, a collection of wrappers and functions for debanding | ||
|
||
This repository is intended to be an updated version of debandshit | ||
until Z4STIN continues updating it himself. | ||
This repository is intended to be a maintained version of `debandshit` until [Z4STIN](https://github.com/kgrabs) continues maintaining it himself. | ||
|
||
The original v0.3.0 of debandshit.py | ||
that this is built on from | ||
can be found [here](https://pastebin.com/NGFBhCCn). | ||
The original v0.3.0 of `debandshit.py` that this is built on from can be found [here](https://pastebin.com/NGFBhCCn). | ||
|
||
## How to install | ||
|
||
If you have the old `debandshit.py` module, | ||
remove that from your system first. | ||
|
||
Install `debandshit` with the following command: | ||
|
||
```sh | ||
$ pip install debandshit | ||
``` | ||
|
||
## Dependencies | ||
|
||
debandshit depends on the following third-party scripts: | ||
|
||
- [fvsfunc](https://github.com/Irrational-Encoding-Wizardry/fvsfunc) | ||
- [mvsfunc](https://github.com/HomeOfVapourSynthEvolution/mvsfunc) | ||
- [muvsfunc](https://github.com/WolframRhodium/muvsfunc) | ||
- [vardefunc](https://pypi.org/project/vardefunc/) | ||
- [vsutil](https://pypi.org/project/vsutil/) | ||
|
||
The following Vapoursynth libraries are also required for full functionality: | ||
And the following VapourSynth libraries: | ||
|
||
- [neo_f3kdb](https://github.com/HomeOfAviSynthPlusEvolution/neo_f3kdb) or [f3kdb](https://f3kdb.readthedocs.io/en/latest/) | ||
- [fmtconv](https://github.com/EleonoreMizo/fmtconv) | ||
- [rgsf](https://github.com/IFeelBloated/RGSF) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# flake8: noqa | ||
|
||
from . import debanders | ||
|
||
f3kbilateral = debanders.f3kbilateral | ||
f3kpf = debanders.f3kpf | ||
lfdeband = debanders.lfdeband | ||
dither_bilateral = debanders.dither_bilateral |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
""" | ||
Various functions used for debanding. | ||
This used to be the `debandshit` module written by Z4ST1N, | ||
with some functions that were rarely (if ever) used removed because I can't reasonably maintain them. | ||
""" | ||
from typing import Any, List, Optional, Union | ||
|
||
import vapoursynth as vs | ||
from vardefunc.deband import dumb3kdb | ||
from vsutil import depth | ||
|
||
core = vs.core | ||
|
||
|
||
def f3kbilateral(clip: vs.VideoNode, | ||
radius: int = 16, | ||
y: int = 64, c: int = 1, | ||
**kwargs: Any) -> vs.VideoNode: | ||
""" | ||
f3kbilateral: f3kdb multistage bilateral-esque filter from debandshit. | ||
This function is more of a last resort for extreme banding. | ||
Recommend values are ~40-60 for y and c strengths. | ||
:param clip: Input clip | ||
:param radius: Banding detection range | ||
:param y: Banding detection threshold for luma | ||
:param c: Banding detection threshold for chroma | ||
:param kwargs: Arguments passed to mvsfunc.LimitFilter | ||
:return: Debanded clip | ||
""" | ||
try: | ||
from mvsfunc import LimitFilter | ||
except ModuleNotFoundError: | ||
raise ModuleNotFoundError("f3kbilateral: missing dependency 'mvsfunc'") | ||
|
||
if clip.format is None: | ||
raise ValueError("f3kbilateral: 'Variable-format clips not supported'") | ||
|
||
bits = clip.format.bits_per_sample | ||
|
||
if bits < 16: | ||
clip = depth(clip, 16) | ||
|
||
lf_args: Any = dict(thr=0.6, elast=3.0, thrc=None) | ||
lf_args.update(kwargs) | ||
|
||
r1 = round(radius * 4 / 3) | ||
r2 = round(radius * 2 / 3) | ||
r3 = round(radius / 3) | ||
y1, y2, y3 = y // 2, y, y | ||
c1, c2, c3 = max(1, c // 2), c, c | ||
|
||
flt1 = dumb3kdb(clip, radius=r1, threshold=[y1, c1, c1]) | ||
flt2 = dumb3kdb(flt1, radius=r2, threshold=[y2, c2, c2]) | ||
flt3 = dumb3kdb(flt2, radius=r3, threshold=[y3, c3, c3]) | ||
|
||
lf = LimitFilter(flt3, flt2, ref=clip, **lf_args) | ||
return depth(lf, bits) if bits < 16 else lf | ||
|
||
|
||
def f3kpf(clip: vs.VideoNode, | ||
radius: int = 16, | ||
threshold: Union[int, List[int]] = 30, | ||
**kwargs: Any) -> vs.VideoNode: | ||
""" | ||
f3kdb with a simple prefilter by mawen1250 - https://www.nmm-hd.org/newbbs/viewtopic.php?f=7&t=1495#p12163. | ||
Since the prefilter is a straight gaussian+average blur, f3kdb's effect becomes very strong, very fast. | ||
Functions more or less like gradfun3 without the detail mask. | ||
:param clip: Input clip | ||
:param radius: Banding detection range | ||
:param threshold: Banding detection thresholds for multiple planes | ||
:param kwargs: Arguments passed to mvsfunc.LimitFilter | ||
:return: Debanded clip | ||
""" | ||
try: | ||
from mvsfunc import LimitFilter | ||
except ModuleNotFoundError: | ||
raise ModuleNotFoundError("f3kpf: missing dependency 'mvsfunc'") | ||
|
||
if clip.format is None: | ||
raise ValueError("f3kpf: 'Variable-format clips not supported'") | ||
|
||
lf_args: Any = dict(thr=0.3, elast=2.5, thrc=None) | ||
lf_args.update(kwargs) | ||
|
||
bits = clip.format.bits_per_sample | ||
|
||
if bits != 32: | ||
clip = depth(clip, 32) | ||
|
||
blur32 = core.std.Convolution(clip, [1, 2, 1, 2, 4, 2, 1, 2, 1]).std.Convolution([1] * 9, planes=0) | ||
blur16 = depth(blur32, 16) | ||
|
||
diff = core.std.MakeDiff(clip, blur32) | ||
f3k = dumb3kdb(blur16, radius, threshold) | ||
f3k = LimitFilter(f3k, blur16, **lf_args) | ||
f3k = depth(f3k, 32) | ||
|
||
out = core.std.MergeDiff(f3k, diff) | ||
return depth(out, bits) | ||
|
||
|
||
def lfdeband(clip: vs.VideoNode) -> vs.VideoNode: | ||
""" | ||
A simple debander ported from AviSynth. | ||
:param clip: Input clip | ||
:return: Debanded clip | ||
""" | ||
if clip.format is None: | ||
raise ValueError("lfdeband: 'Variable-format clips not supported'") | ||
|
||
bits = clip.format.bits_per_sample | ||
wss = 1 << clip.format.subsampling_w | ||
hss = 1 << clip.format.subsampling_h | ||
w, h = clip.width, clip.height | ||
dw, dh = round(w / 2), round(h / 2) | ||
|
||
clip = depth(clip, 32) | ||
dsc = core.resize.Spline64(clip, dw-dw % wss, dh-dh % hss) | ||
|
||
d3kdb_down = depth(dsc, 16) | ||
d3kdb = dumb3kdb(d3kdb_down, radius=30, threshold=80, grain=0) | ||
d3kdb_up = depth(d3kdb, 32) | ||
|
||
ddif = core.std.MakeDiff(d3kdb_up, dsc) | ||
|
||
dif = core.resize.Spline64(ddif, w, h) | ||
out = core.std.MergeDiff(clip, dif) | ||
return depth(out, bits) | ||
|
||
|
||
def dither_bilateral(clip: vs.VideoNode, ref: Optional[vs.VideoNode] = None, | ||
radius: Optional[float] = None, | ||
thr: float = 0.35, wmin: float = 1.0, | ||
subspl: float = 0) -> vs.VideoNode: | ||
""" | ||
Dither's Gradfun3 mode 2, for Vapoursynth | ||
Not much different from using core.avsw.Eval with Dither_bilateral_multistage, | ||
just with normal value rounding and without Dither_limit_dif16 | ||
If you want the rounding to be exactly the same, | ||
replace the applicable lines from here: https://pastebin.com/raw/gZKHCFkd | ||
Default setting of 'radius' changes to reflect the resolution | ||
Radius auto-adjust: 480p -> 9 | ||
720p -> 12 | ||
810p -> 13 | ||
900p -> 14 | ||
1080p -> 16 | ||
2K -> 20 | ||
4K -> 32 | ||
Basic usage: flt = db.Dither_bilateral(clip, thr=1/3) | ||
flt = mvf.LimitFilter(flt, clip, thr=1/3) | ||
""" | ||
if clip.format is None: | ||
raise ValueError("Dither_bilateral: 'Variable-format clips not supported'") | ||
|
||
if radius is None: | ||
radius = max((clip.width - 1280) / 160 + 12, (clip.height - 720) / 90 + 12) | ||
|
||
planes = list(range(clip.format.num_planes)) | ||
y, u, v = [3 if x in planes else 1 for x in range(3)] | ||
|
||
thr_1 = round(max(thr * 4.5, 1.25), 1) | ||
thr_2 = round(max(thr * 9, 5), 1) | ||
subspl_2 = subspl if subspl in (0, 1) else subspl / 2 | ||
r4 = round(max(radius * 4 / 3, 4)) | ||
r2 = round(max(radius * 2 / 3, 3)) | ||
r1 = round(max(radius / 3, 2)) | ||
|
||
clips = [clip.fmtc.nativetostack16()] | ||
clip_names = ["c"] | ||
ref_t = "c" | ||
if ref is not None: | ||
ref_s = ref.fmtc.nativetostack16() | ||
clips += [ref_s] | ||
clip_names += ["ref"] | ||
ref_t = "ref" | ||
|
||
avs_stuff = "c.Dither_bilateral16(radius={r4}, thr={thr_1}, flat=0.75, wmin={wmin}, ref={ref_t}, subspl={subspl}, y={y}, u={u}, v={v})" # noqa | ||
avs_stuff += ".Dither_bilateral16(radius={r2}, thr={thr_2}, flat=0.25, wmin={wmin}, ref={ref_t}, subspl={subspl_2}, y={y}, u={u}, v={v})" # noqa | ||
avs_stuff += ".Dither_bilateral16(radius={r1}, thr={thr_2}, flat=0.50, wmin={wmin}, ref={ref_t}, subspl={subspl_2}, y={y}, u={u}, v={v})" # noqa | ||
avs_stuff = avs_stuff.format(ref_t=ref_t, r4=r4, r2=r2, r1=r1, thr_1=thr_1, thr_2=thr_2, wmin=wmin, subspl=subspl, subspl_2=subspl_2, y=y, u=u, v=v) # noqa | ||
|
||
return core.avsw.Eval(avs_stuff, clips=clips, clip_names=clip_names).fmtc.stack16tonative() | ||
# TO-DO: Fix this function. Current error: Avisynth 32-bit proxy: command failed | ||
|
||
# TO-DO: Port all the other functions in ../legacy/debandshit.py |
Empty file.
Oops, something went wrong.