Advertisement
Zastin

resource for questionable reupscaling

Nov 1st, 2020 (edited)
487
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.89 KB | None | 0 0
  1. import vapoursynth as vs
  2. import G41Fun
  3. import havsfunc as haf
  4. import mvsfunc as mvf
  5. import muvsfunc as muf
  6. from vsutil import *
  7. from math import ceil
  8. from functools import partial
  9.  
  10. core = vs.core
  11.  
  12. w, h, b, c = 1280, 720, 0.2, 0.4
  13.  
  14. def dogahomo(clip):
  15.     clamp = clip.rgvs.RemoveGrain(1)
  16.     des_a =  descale(clip)
  17.     des_b =  descale(clamp)
  18.     dif_a = absdiff(clip, des_a)
  19.     dif_b = absdiff(clamp, des_b)
  20.     return core.std.Expr([dif_a, dif_b, clamp, clip], 'x y - 1000 > x 2500 > and z a ?')
  21.  
  22. def weakaa(clip, mask):
  23.     aa = clip.std.Transpose()
  24.    
  25.     eaa = aa
  26.     eaa = eaa.eedi3m.EEDI3(0,1,0, 0.2, 0.6, mclip=mask.std.Transpose()).resize.Spline36(height=eaa.height, src_top=.5)
  27.     eaa = eaa.std.Transpose()
  28.     eaa = eaa.eedi3m.EEDI3(0,1,0, 0.2, 0.6, mclip=mask                ).resize.Spline36(height=eaa.height, src_top=.5)
  29.    
  30.     naa = aa
  31.     naa = naa.znedi3.nnedi3(0,1,0,0,3,2).resize.Spline36(height=naa.height, src_top=.5)
  32.     naa = naa.std.Transpose()
  33.     naa = naa.znedi3.nnedi3(0,1,0,0,3,2).resize.Spline36(height=naa.height, src_top=.5)
  34.    
  35.     return median(eaa, naa, clip)
  36.  
  37. def eedi3aa(clip, mask, ssw=3520, ssh=1980, nsize=0, nns=4, qual=2, alpha=0.2, beta=0.5, gamma=None, nrad=2, mdis=20, sclip=True):
  38.     gamma = fallback(gamma, 20 if sclip is None else 69)
  39.     base = clip.resize.Spline36(1080, 1920).std.Transpose()
  40.     mclip = mask.fmtc.resample(ssw, ssh, kernel='box', fulls=1, fulld=1)
  41.     aa = clip.resize.Spline36(ssh, ssw)
  42.     aa = aa.eedi3m.EEDI3(0,0,0, alpha, beta, gamma, nrad, mdis, sclip=None if sclip is None else aa.znedi3.nnedi3(0,0,0, nsize, nns, qual), mclip=mclip.std.Transpose())
  43.     aa = aa.std.Transpose()
  44.     aa = aa.eedi3m.EEDI3(0,0,0, alpha, beta, gamma, nrad, mdis, sclip=None if sclip is None else aa.znedi3.nnedi3(0,0,0, nsize, nns, qual), mclip=mclip)
  45.     aa = aa.resize.Spline36(1920, 1080)
  46.     return base.std.MaskedMerge(aa, mask)
  47.  
  48. def median(*clips): return core.std.Expr(clips, 'x y z min max y z max min')
  49.  
  50. def contrast_adaptive_diff(clip, desc, rad=2, thr=0.125, lopass=1000):
  51.     error = absdiff(clip, desc)
  52.     contrast = range_mask(clip, rad)
  53.     return core.std.Expr([error, contrast], f'x y {thr} * {lopass} max > 65535 0 ?')
  54.  
  55. def absdiff(clip, desc):
  56.     error = desc.resize.Bicubic(1920, 1080, filter_param_a=b, filter_param_b=c)
  57.     return core.std.Expr([clip, error], 'x y - abs')
  58.  
  59. def descale(clip): return depth(depth(clip, 32, dither_type='none').descale.Debicubic(w, h, b=b, c=c), 16, dither_type='none')
  60.  
  61. def error_mask(clip, desc, thr1=2500, thr2=None, expand1=2, expand2=3, blur=3):
  62.     start = 0
  63.     error = absdiff(clip, desc)
  64.  
  65.     for x in range(expand1):
  66.         error = error.std.Maximum(coordinates=[[1]*8, [0,1,0,1,1,0,1,0]][min(start%3,1)])
  67.         start += 1
  68.  
  69.     if thr2 is not None:
  70.         error = error.std.Binarize(thr2).misc.Hysteresis(error.std.Binarize(thr1))
  71.     else:
  72.         error = error.std.Binarize(thr1)
  73.  
  74.     for x in range(expand2):
  75.         error = error.std.Maximum(coordinates=[[1]*8, [0,1,0,1,1,0,1,0]][min(start%3,1)])
  76.         start += 1
  77.  
  78.     if blur:
  79.         return error.std.BoxBlur(hradius=blur, vradius=blur)
  80.     return error
  81.  
  82. def ringing_mask(clip, rad=4, ethr1=30<<8, ethr2=50<<8, minthr=0.5):
  83.     prew = clip.std.Prewitt()
  84.     mask_lo = prew.std.Binarize(ethr1)
  85.     mask_hi = prew.std.Binarize(ethr2)
  86.     main = core.std.Expr([mask_lo, mask_hi.std.Maximum().std.Maximum(), mask_hi], 'x y - z max')
  87.     main = main.std.Maximum().std.Maximum().std.Minimum().std.Minimum()
  88.     shrink = main.std.Minimum()
  89.     mask = core.std.Expr([main, shrink.std.Maximum(), main.std.Merge(shrink, minthr)], f'x y 0 = and x z ?')
  90.     imask = iterate(mask, core.std.Maximum, rad).std.Invert()
  91.     return core.std.Expr([mask, imask], 'x y +')
  92.  
  93. def straight_line_mask(mask, thr=0.95, rad=69, expand=0):
  94.     mask = core.std.Expr(mask, 'x 255 0 ?', vs.GRAY8)
  95.    
  96.     shift = ceil(rad / 2)
  97.     grow = shift // 2
  98.    
  99.     v_avg = mask.std.BoxBlur(hradius=0, vradius=rad)
  100.     v_avg = [v_avg.resize.Point(src_top=-shift), v_avg, v_avg.resize.Point(src_top=shift)]
  101.     v_avg = core.std.Expr(v_avg, f'x y z max max {255 * thr} > 255 0 ?')
  102.     v_avg = iterate(v_avg, partial(core.std.Maximum, coordinates=[0,1,0,1,1,0,1,0]), expand)
  103.     v_avg = iterate(v_avg, partial(core.std.Maximum, coordinates=[0,1,0,0,0,0,1,0]), grow - expand)
  104.    
  105.     h_avg = mask.std.BoxBlur(hradius=rad, vradius=0)
  106.     h_avg = [h_avg.resize.Point(src_left=-shift), h_avg, h_avg.resize.Point(src_left=shift)]
  107.     h_avg = core.std.Expr(h_avg, f'x y z max max {255 * thr} > 255 0 ?')
  108.     h_avg = iterate(h_avg, partial(core.std.Maximum, coordinates=[0,1,0,1,1,0,1,0]), expand)
  109.     h_avg = iterate(h_avg, partial(core.std.Maximum, coordinates=[0,0,0,1,1,0,0,0]), grow - expand)
  110.  
  111.     return [h_avg, v_avg]
  112.  
  113. def morpho_mask(clip, radius=3, **mode):
  114.     refa = haf.mt_inpand_multi(haf.mt_expand_multi(clip, sw=radius, sh=radius, **mode), sw=radius, sh=radius, **mode)
  115.     refb = haf.mt_expand_multi(haf.mt_inpand_multi(clip, sw=radius, sh=radius, **mode), sw=radius, sh=radius, **mode)
  116.     return core.std.Expr([clip, refa, refb], 'x y - abs x z - abs max')
  117.  
  118. def repair1(clip, repairclip, rad=1):
  119.     if rad == 1:
  120.         return clip.rgvs.Repair(repairclip, 1)
  121.     rmax = haf.mt_expand_multi(repairclip, sw=rad, sh=rad, mode='ellipse')
  122.     rmin = haf.mt_inpand_multi(repairclip, sw=rad, sh=rad, mode='ellipse')
  123.     return core.std.Expr([clip, rmax, rmin], 'x y min z max')
  124.  
  125. def repairmod(clip, rad=1):
  126.     rmax = muf.Sort(clip, 2)
  127.     rmin = muf.Sort(clip, 8)
  128.     rmax = haf.mt_expand_multi(rmax, sw=rad, sh=rad, mode='ellipse')
  129.     rmin = haf.mt_inpand_multi(rmin, sw=rad, sh=rad, mode='ellipse')
  130.     return core.std.Expr([clip, rmax, rmin], 'x y min z max')
  131.  
  132. def resize_mclip(mclip, w=None, h=None):
  133.     iw = mclip.width
  134.     ih = mclip.height
  135.     ow = fallback(w, iw)
  136.     oh = fallback(h, ih)
  137.    
  138.     if (ow > iw and ow/iw != ow//iw) or (oh > ih and oh/ih != oh//ih):
  139.         mclip = mclip.resize.Point(iw * ceil(ow / iw), ih * ceil(oh / ih))
  140.    
  141.     return mclip.fmtc.resample(ow, oh, kernel='box', fulls=1, fulld=1)
  142.  
  143.  
  144.  
  145. clip = core.ffms2.Source()
  146. clip = depth(clip, 16)
  147.  
  148.  
  149.  
  150. # prep stuff
  151. clipy = get_y(clip)
  152. pre_descale = dogahomo(clipy)
  153. descaled = descale(pre_descale)
  154. error = error_mask(pre_descale, descaled, thr1=2500, thr2=3500, expand1=2, expand2=2, blur=3)
  155. FDOG = G41Fun.EdgeDetect(clipy, 'FDOG').std.Maximum().std.Minimum()
  156. sharp_edges = FDOG.std.Binarize(60<<9)
  157.  
  158.  
  159.  
  160. # reupscale w/ protection from nnedi3 line/halo weirdness on straight lines
  161. slm = sharp_edges.std.Maximum()
  162. slm = straight_line_mask(slm)
  163. slm = core.std.Expr(slm, 'x y or 65535 0 ?', vs.GRAY16)
  164.  
  165. slmt = slm.std.Transpose()
  166. mclip1 = resize_mclip(slm, w, h)
  167. mclip2 = resize_mclip(slmt, h * 2, w)
  168. slm_final = resize_mclip(slmt, h * 2, w * 2)
  169.  
  170. nedi = descaled.znedi3.nnedi3(0,1,0,0,4,2).std.Transpose().znedi3.nnedi3(0,1,0,0,4,2).resize.Spline36(src_left=0.5, src_top=0.5)
  171. fsr = get_y(join([descaled.std.Transpose()]*3).placebo.Shader(shader=r'C:\Users\Zastin\AppData\Roaming\mpv\shaders\FSRCNNX_x2_16-0-4-1.glsl', filter='box', width=h * 2, height=w * 2))
  172. doubled = nedi.std.Merge(fsr, 0.5)
  173. eedi = descaled.eedi3m.EEDI3(0,1,0,mclip=mclip1).resize.Spline36(src_top=0.5).std.Transpose().eedi3m.EEDI3(0,1,0,mclip=mclip2).resize.Spline36(src_top=0.5)
  174. spline = descaled.std.Transpose().resize.Spline16(h * 2, w * 2)
  175. merged = median(doubled, eedi, spline)
  176. upscaled = core.std.Expr([doubled, merged, slm_final], 'z y x ?')
  177.  
  178.  
  179.  
  180. # anti-aliasing
  181. aamask = sharp_edges.rgvs.RemoveGrain(11)
  182. upscaled = eedi3aa(upscaled, aamask, alpha=0.25, beta=0.6, gamma=0.15, sclip=False)
  183. #upscaled = upscaled.resize.Spline36(1080, 1920).std.Transpose()
  184. clipy = clipy.std.MaskedMerge(weakaa(clipy, core.std.Expr([aamask, error], 'y x 0 ?')), aamask)
  185.  
  186.  
  187.  
  188. # reduce descale artifacts - "ref" varys based on source (upscale sharpness, post-processing, compression artifacts)
  189. safemask = ringing_mask(clipy)
  190. #ref = upscaled.bilateral.Bilateral(sigmaS=2, sigmaR=6 / 255, algorithm=0)
  191. #ref = mvf.LimitFilter(ref, upscaled, thr=5, elast=2, brighten_thr=3)
  192. #ref = median(clipy, upscaled, ref)
  193. ref = clipy
  194. noring = ref.std.MaskedMerge(upscaled, safemask)
  195. upscaled = repair1(upscaled, noring, rad=1)
  196.  
  197.  
  198.  
  199. # build final detail mask
  200. morpho = morpho_mask(upscaled, 3).std.Binarize(1111)
  201. #morpho = morpho.rgvs.RemoveGrain(1)
  202. morpho = morpho.std.Maximum()
  203.  
  204. lo, hi, start = [5000, 12000, 65536//16]
  205. edges = FDOG.std.Expr(f'x {lo} <= 0 x {hi} >= 65535 x {lo} - {(65535 - start)/(hi-lo)} * {start} + ? ?')
  206. edges_shrink = edges.std.Minimum().std.Maximum()
  207.  
  208. detail = core.std.Expr([morpho, edges], 'x y and y 2 * y ?').std.Convolution([1]*9)
  209. detail = core.std.Expr([detail, edges, edges_shrink], 'y z > x y max x ?')
  210. descale_mask = core.std.Expr([detail, error], 'x y -')
  211.  
  212.  
  213.  
  214. # merge descaled clip with original luma
  215. masked = clipy.std.MaskedMerge(upscaled, descale_mask)
  216. final = muf.MergeChroma(masked, clip)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement