diff --git a/Bishounen Tanteidan/02/02.vpy b/Bishounen Tanteidan/02/02.vpy index fe6ede2..67a1b9d 100644 --- a/Bishounen Tanteidan/02/02.vpy +++ b/Bishounen Tanteidan/02/02.vpy @@ -1,11 +1,12 @@ import vapoursynth as vs -from tanteidan_common import (PrettyConfig, PrettySource, antialias, deband, denoise, finalize, regrain) +from tanteidan_common import (PrettyConfig, PrettySource, antialias, deband, + denoise, finalize, regrain, stupid_op_scenefilter) from yt_common.automation import SelfRunner from yt_common.source import waka_replace -from typing import List +from typing import List, Optional from lvsfunc.dehardsub import HardsubLineFade, HardsubSignFade, HardsubMask, bounded_dehardsub from lvsfunc.types import Range @@ -20,6 +21,8 @@ EPNUM: int = int(os.path.basename(os.path.splitext(__file__)[0])) CONFIG: PrettyConfig = PrettyConfig(EPNUM) SOURCE: PrettySource = PrettySource(CONFIG) +OP: Optional[int] = 792 + WAKA_REPLACE: List[List[Range]] = [ [(31864, 32652)], [], @@ -76,7 +79,6 @@ AA_WEAK: List[Range] = [ AA_WEAK += TITLECARDS - AA_NONE: List[Range] = [ (5972, 6091), # this is heavily stylized and i'm not touching it ] @@ -97,7 +99,8 @@ def filter() -> vs.VideoNode: den = denoise(src) deb = deband(den) aa = antialias(deb, weak=AA_WEAK, noaa=AA_NONE) - grain = regrain(aa) + scenefilter = stupid_op_scenefilter(aa, deb, OP) + grain = regrain(scenefilter) final = finalize(grain) final.set_output() return final diff --git a/Bishounen Tanteidan/tanteidan_common/__init__.py b/Bishounen Tanteidan/tanteidan_common/__init__.py index 36c67d6..cf2f4dd 100644 --- a/Bishounen Tanteidan/tanteidan_common/__init__.py +++ b/Bishounen Tanteidan/tanteidan_common/__init__.py @@ -1,2 +1,2 @@ from .config import PrettyConfig, PrettySource # noqa: F401 -from .filter import antialias, deband, denoise, finalize, regrain # noqa: F401 +from .filter import antialias, deband, denoise, finalize, regrain, stupid_op_scenefilter # noqa: F401 diff --git a/Bishounen Tanteidan/tanteidan_common/filter.py b/Bishounen Tanteidan/tanteidan_common/filter.py index ff1d022..80309be 100644 --- a/Bishounen Tanteidan/tanteidan_common/filter.py +++ b/Bishounen Tanteidan/tanteidan_common/filter.py @@ -5,6 +5,8 @@ import vsutil from G41Fun import MaskedDHA from debandshit import f3kbilateral from havsfunc import LSFmod +from lvsfunc.aa import upscaled_sraa +from lvsfunc.kernels import Bicubic from lvsfunc.mask import detail_mask from lvsfunc.misc import replace_ranges from lvsfunc.types import Range @@ -16,6 +18,8 @@ from typing import List, Optional, Sequence, Union from yt_common.antialiasing import combine_mask, sraa_clamp from yt_common.deband import morpho_mask +from .scenefilter import get_op_scenefilters + core = vs.core @@ -43,7 +47,8 @@ def deband(clip: vs.VideoNode) -> vs.VideoNode: return deband -def antialias(clip: vs.VideoNode, weak: Optional[List[Range]] = None, noaa: Optional[List[Range]] = None, +def antialias(clip: vs.VideoNode, strong: Optional[List[Range]] = None, + weak: Optional[List[Range]] = None, noaa: Optional[List[Range]] = None, dehalo: bool = True, sharpen: bool = False) -> vs.VideoNode: def _sraa_pp_sharpdehalo(sraa: vs.VideoNode) -> vs.VideoNode: if sharpen: # all this really seems to do is make the haloing worse, will not be using! @@ -52,7 +57,8 @@ def antialias(clip: vs.VideoNode, weak: Optional[List[Range]] = None, noaa: Opti sraa = MaskedDHA(sraa, rx=1.7, ry=1.7, darkstr=0, brightstr=0.75) if dehalo else sraa return sraa clamp = sraa_clamp(clip, mask=combine_mask(clip, weak or []), postprocess=_sraa_pp_sharpdehalo) - return replace_ranges(clamp, clip, noaa or []) + sraa = upscaled_sraa(clip, rfactor=2, downscaler=Bicubic(b=0, c=1/2).scale) + return replace_ranges(replace_ranges(clamp, clip, noaa or []), sraa, strong or []) def regrain(clip: vs.VideoNode) -> vs.VideoNode: @@ -68,5 +74,15 @@ def regrain(clip: vs.VideoNode) -> vs.VideoNode: return grain +def stupid_op_scenefilter(aa: vs.VideoNode, deb: vs.VideoNode, start: Optional[int]) -> vs.VideoNode: + if start is None: + return aa + aastrong, masks = get_op_scenefilters(start) + sraa = replace_ranges(aa, upscaled_sraa(deb, rfactor=2, downscaler=Bicubic(b=0, c=1/2).scale), aastrong) + for mask in masks: + sraa = replace_ranges(sraa, core.std.MaskedMerge(sraa, aa, mask.get_mask(deb, deb)), mask.ranges) + return sraa + + def finalize(clip: vs.VideoNode) -> vs.VideoNode: return vsutil.depth(clip, 10) diff --git a/Bishounen Tanteidan/tanteidan_common/scenefilter.py b/Bishounen Tanteidan/tanteidan_common/scenefilter.py new file mode 100644 index 0000000..47891e5 --- /dev/null +++ b/Bishounen Tanteidan/tanteidan_common/scenefilter.py @@ -0,0 +1,91 @@ +import vapoursynth as vs + +import vsutil + +from typing import Any, List, Optional, Tuple + +from lvsfunc.mask import DeferredMask +from lvsfunc.misc import replace_ranges, scale_thresh +from lvsfunc.types import Range + + +core = vs.core + + +class SelfDehardsub(DeferredMask): + """ + oh god why + basically use a reference frame to mask OP credits when they're on a static bg + """ + thresh: float + expand: int + inflate: int + prebrz: Optional[float] + + def __init__(self, *args: Any, thresh: float = 0.01, expand: int = 2, + inflate: int = 3, prebrz: Optional[float] = None, **kwargs: Any) -> None: + self.thresh = thresh + self.expand = expand + self.inflate = inflate + self.prebrz = prebrz + super().__init__(*args, **kwargs) + + def get_mask(self, clip: vs.VideoNode, ref: vs.VideoNode) -> vs.VideoNode: + """ + Get the bounded mask. + :param clip: Source + :param ref: Reference clip + :return: Bounded mask + """ + if self.bound: + bm = self.bound.get_mask(ref) + bm = bm if not self.blur else bm.std.BoxBlur(hradius=5, vradius=5, hpasses=5, vpasses=5) + + if self.prebrz: + clip = vsutil.get_y(clip).std.Binarize(scale_thresh(self.prebrz, clip)).std.Invert() + ref = vsutil.get_y(ref).std.Binarize(scale_thresh(self.prebrz, ref)).std.Invert() + + if ref.format is None or clip.format is None: + raise ValueError("SelfDehardsub: 'Variable-format clips not supported'") + + if len(self.refframes) == 0: + hm = vsutil.depth(self._mask(clip, ref), clip.format.bits_per_sample, + range=vsutil.Range.FULL, range_in=vsutil.Range.FULL) + else: + hm = core.std.BlankClip(ref, format=ref.format.replace(color_family=vs.GRAY, + subsampling_h=0, subsampling_w=0).id) + for range, rf in zip(self.ranges, self.refframes): + mask = vsutil.depth(self._mask(clip, ref[rf]), clip.format.bits_per_sample, + range=vsutil.Range.FULL, range_in=vsutil.Range.FULL) + hm = replace_ranges(hm, core.std.Expr([hm, mask*len(hm)], expr="x y max"), range) + + return hm if self.bound is None else core.std.MaskedMerge(core.std.BlankClip(hm), hm, bm) + + def _mask(self, clip: vs.VideoNode, ref: vs.VideoNode) -> vs.VideoNode: + assert clip.format is not None + hsmf = core.std.Expr([clip, ref], 'x y - abs') \ + .resize.Point(format=clip.format.replace(subsampling_w=0, subsampling_h=0).id) + if clip.format.num_planes > 1: + hsmf = core.std.Expr(vsutil.split(hsmf), "x y z max max") + hsmf = vsutil.iterate(vsutil.iterate(hsmf.std.Binarize(scale_thresh(self.thresh, clip)) + .std.Minimum(), + core.std.Maximum, self.expand), + core.std.Inflate, self.inflate) + return hsmf + + +def get_op_scenefilters(start: Optional[int]) -> Tuple[List[Range], List[DeferredMask]]: + if start is None: + return [], [] + return [ + (start+1019, start+1021), + (start+1029, start+1031), + (start+1039, start+1041), + (start+1067, start+1372), + (start+1481, start+1689), + ], [ + SelfDehardsub((start+1170, start+1274), ((217, 441), (597, 198)), refframes=1274), + SelfDehardsub((start+1275, start+1369), ((1069, 337), (593, 361)), refframes=1371), + SelfDehardsub((start+1481, start+1581), ((247, 294), (647, 467)), refframes=1582), + SelfDehardsub((start+1584, start+1688), ((352, 443), (277, 190)), refframes=1689), + ]