From eefc597138119702568cdee4ff3844e752900c55 Mon Sep 17 00:00:00 2001 From: louis <louis@poweris.moe> Date: Thu, 22 Apr 2021 15:33:23 -0400 Subject: [PATCH] vivy: common: antialiasing: use clamped upscaled_sraa --- Vivy/vivy_common/filter.py | 12 +++--- yt_common/yt_common/__init__.py | 2 +- yt_common/yt_common/antialiasing.py | 58 +++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 7 deletions(-) create mode 100644 yt_common/yt_common/antialiasing.py diff --git a/Vivy/vivy_common/filter.py b/Vivy/vivy_common/filter.py index 33334f4..06278ae 100644 --- a/Vivy/vivy_common/filter.py +++ b/Vivy/vivy_common/filter.py @@ -8,6 +8,8 @@ from lvsfunc.types import Range from mvsfunc import BM3D from typing import List, Optional +from yt_common import antialiasing + import os import vsutil @@ -37,19 +39,17 @@ def letterbox_edgefix(clip: vs.VideoNode, ranges: List[Range]) -> vs.VideoNode: def denoise(clip: vs.VideoNode, sigma: float = 0.75) -> vs.VideoNode: - bm3d = BM3D(clip, sigma=[sigma, 0], depth=16) - knl = core.knlm.KNLMeansCL(clip, d=3, a=2, h=0.4, channels="UV", device_type='gpu', device_id=0) - return core.std.ShufflePlanes([bm3d, knl], planes=[0, 1, 2], colorfamily=vs.YUV) + bm3d: vs.VideoNode = BM3D(clip, sigma=sigma, depth=16) + return bm3d def deband(clip: vs.VideoNode) -> vs.VideoNode: - deb = vdf.dumb3kdb(clip, radius=18, threshold=36, grain=[24, 0]) - assert isinstance(deb, vs.VideoNode) + deb: vs.VideoNode = vdf.dumb3kdb(clip, radius=18, threshold=36, grain=[24, 0]) return deb def antialias(clip: vs.VideoNode, noaa: Optional[List[Range]] = None) -> vs.VideoNode: - clamp = lvf.aa.nneedi3_clamp(clip) + clamp = antialiasing.sraa_clamp(clip, mask=antialiasing.aa_mask_strong(clip)) return lvf.misc.replace_ranges(clamp, clip, noaa) if noaa else clamp diff --git a/yt_common/yt_common/__init__.py b/yt_common/yt_common/__init__.py index 2ba26f8..c024e69 100644 --- a/yt_common/yt_common/__init__.py +++ b/yt_common/yt_common/__init__.py @@ -1 +1 @@ -from . import config, automation, logging, source # noqa: F401 +from . import antialiasing, config, automation, logging, source # noqa: F401 diff --git a/yt_common/yt_common/antialiasing.py b/yt_common/yt_common/antialiasing.py new file mode 100644 index 0000000..a18329d --- /dev/null +++ b/yt_common/yt_common/antialiasing.py @@ -0,0 +1,58 @@ +import vapoursynth as vs + +import vsutil + +from kagefunc import kirsch +from lvsfunc.aa import clamp_aa, upscaled_sraa +from lvsfunc.misc import replace_ranges, scale_thresh +from lvsfunc.types import Range + +from typing import Any, Dict, List, Optional, Union + + +core = vs.core + + +def nnedi3(clip: vs.VideoNode, opencl: bool = False) -> vs.VideoNode: + nnedi3_args: Dict[str, Any] = dict(field=0, dh=True, nsize=3, nns=3, qual=1) + + y = vsutil.get_y(clip) + + def _nnedi3(clip: vs.VideoNode) -> vs.VideoNode: + return clip.nnedi3cl.NNEDI3CL(**nnedi3_args) if opencl \ + else clip.nnedi3.nnedi3(**nnedi3_args) + + aa = _nnedi3(y.std.Transpose()) + aa = aa.resize.Spline36(height=clip.width, src_top=0.5).std.Transpose() + aa = _nnedi3(aa) + aa = aa.resize.Spline36(height=clip.height, src_top=0.5) + return aa + + +def aa_mask_weak(clip: vs.VideoNode) -> vs.VideoNode: + # use bilateral to smear the noise as much as possible without destroying lines + pre = vsutil.get_y(clip).bilateral.Bilateral(sigmaS=5, sigmaR=0.75) + # frei-chen edge detection + gx = core.std.Convolution(pre, [-7, 0, 7, -10, 0, 10, -7, 0, 7], divisor=7, saturate=False) + gy = core.std.Convolution(pre, [-7, -10, -7, 0, 0, 0, 7, 10, 7], divisor=7, saturate=False) + return core.std.Expr([gx, gy], 'x dup * y dup * + sqrt').std.Binarize(scale_thresh(0.25, clip)) \ + .std.Maximum().std.Convolution([1]*9) + + +def aa_mask_strong(clip: vs.VideoNode) -> vs.VideoNode: + mask: vs.VideoNode = kirsch(vsutil.get_y(clip)).std.Binarize(scale_thresh(0.25, clip)) \ + .std.Maximum().std.Convolution([1]*9) + return mask + + +def aa_mask(clip: vs.VideoNode, weak: Union[Range, List[Range], None] = None) -> vs.VideoNode: + weak = weak or [] + return replace_ranges(aa_mask_strong(clip), aa_mask_weak(clip), weak) + + +def sraa_clamp(clip: vs.VideoNode, mask: Optional[vs.VideoNode] = None, + strength: float = 3, opencl: bool = False) -> vs.VideoNode: + sraa = upscaled_sraa(clip, rfactor=1.3, opencl=opencl, + downscaler=lambda c, w, h: c.resize.Bicubic(w, h, filter_param_a=0, filter_param_b=1/2)) + clamp = clamp_aa(clip, nnedi3(clip, opencl=opencl), sraa, strength=strength) + return core.std.MaskedMerge(clip, clamp, mask, planes=0) if mask else clamp