this probably won't really matter because they won't be re-encoded but it makes it easier to check things
106 lines
3.8 KiB
Python
106 lines
3.8 KiB
Python
import vapoursynth as vs
|
|
import vsutil
|
|
|
|
from kagefunc import retinex_edgemask
|
|
from lvsfunc.aa import upscaled_sraa
|
|
from lvsfunc.kernels import Bicubic
|
|
from lvsfunc.misc import replace_ranges
|
|
from lvsfunc.scale import descale as ldescale
|
|
from lvsfunc.scale import descale_detail_mask
|
|
from toolz.functoolz import curry
|
|
from typing import List, NamedTuple, Tuple
|
|
|
|
from .filter import Range
|
|
|
|
core = vs.core
|
|
|
|
|
|
class FadeRange(NamedTuple):
|
|
ref: int
|
|
range_: Tuple[int, int]
|
|
|
|
|
|
@curry
|
|
def _sraa_frameeval(n: int, clip: vs.VideoNode, w: int, h: int
|
|
) -> vs.VideoNode:
|
|
frame = clip.get_frame(n)
|
|
if frame.height < 1080:
|
|
rfactor = 2.5
|
|
else:
|
|
rfactor = 1.5
|
|
return upscaled_sraa(clip.resize.Bicubic(frame.width, frame.height),
|
|
rfactor=rfactor, h=h, ar=w/h)
|
|
|
|
|
|
def _sraa_reupscale(clip: vs.VideoNode, width: int, height: int
|
|
) -> vs.VideoNode:
|
|
sraa = clip.std.FrameEval(_sraa_frameeval(clip=clip, w=width,
|
|
h=height))
|
|
scale = sraa.resize.Spline36(width, height, format=vs.GRAY16)
|
|
return scale
|
|
|
|
|
|
def _fade_ranges_with_refs(clip: vs.VideoNode, reupscaled: vs.VideoNode,
|
|
ranges: List[FadeRange]) -> vs.VideoNode:
|
|
mask = core.std.BlankClip(clip)
|
|
for r in ranges:
|
|
rmask = descale_detail_mask(clip[r.ref], reupscaled[r.ref],
|
|
threshold=1500)
|
|
rmask = core.std.Expr([mask, rmask], "x y +")
|
|
mask = replace_ranges(mask, rmask, [r.range_])
|
|
|
|
return mask
|
|
|
|
|
|
@curry
|
|
def _inverse_mask(clip: vs.VideoNode, reupscaled: vs.VideoNode,
|
|
franges: List[FadeRange] = [], dranges: List[Range] = []
|
|
) -> vs.VideoNode:
|
|
reupscaled = reupscaled.resize.Bicubic(format=clip.format.id)
|
|
line_mask = retinex_edgemask(clip, 0.0001).std.Binarize(10000)
|
|
fade_mask = _fade_ranges_with_refs(clip, reupscaled, franges)
|
|
mask = core.std.Expr([fade_mask, line_mask.std.Invert()], "x y +")
|
|
if dranges:
|
|
detail_mask = descale_detail_mask(clip, reupscaled, threshold=1500)
|
|
mask_with_detail = core.std.Expr([mask, detail_mask], "x y +")
|
|
mask = replace_ranges(mask, mask_with_detail, dranges)
|
|
return mask.resize.Bicubic(format=clip.format.id)
|
|
|
|
|
|
@curry
|
|
def descale(clip: vs.VideoNode, force_scale: List[Range] = [],
|
|
no_scale: List[Range] = [], fade_ranges: List[FadeRange] = [],
|
|
detail_ranges: List[Range] = [], show_mask: bool = False
|
|
) -> vs.VideoNode:
|
|
kernel = Bicubic(b=1/3, c=1/3)
|
|
heights = [871, 872, 873]
|
|
y = vsutil.get_y(clip)
|
|
ys = ldescale(y, upscaler=_sraa_reupscale, height=heights,
|
|
kernel=kernel, threshold=0.003,
|
|
mask=_inverse_mask(franges=fade_ranges,
|
|
dranges=detail_ranges),
|
|
show_mask=show_mask)
|
|
if show_mask:
|
|
return ys
|
|
|
|
yf = ldescale(y, upscaler=_sraa_reupscale, height=heights,
|
|
kernel=kernel, threshold=0,
|
|
mask=_inverse_mask(franges=fade_ranges,
|
|
dranges=detail_ranges))
|
|
yd = replace_ranges(ys, yf, force_scale)
|
|
scaled = core.std.ShufflePlanes([yd, clip], planes=[0, 1, 2],
|
|
colorfamily=vs.YUV)
|
|
scaled = replace_ranges(scaled, clip, no_scale)
|
|
return scaled
|
|
|
|
|
|
@curry
|
|
def descale720(clip: vs.VideoNode, src: vs.VideoNode, ranges: List[Range] = []
|
|
) -> vs.VideoNode:
|
|
y = ldescale(vsutil.get_y(src), upscaler=_sraa_reupscale, height=720,
|
|
kernel=Bicubic(b=1/3, c=1/3), threshold=0, mask=_inverse_mask)
|
|
scaled = core.std.ShufflePlanes([y, src], planes=[0, 1, 2],
|
|
colorfamily=vs.YUV)
|
|
scaled = replace_ranges(clip, scaled, ranges)
|
|
return scaled
|