def nnedi3_resample_kernel_vertical(input, target_height=None, src_top=None, src_height=None, scale_thr=None, nsize=None, nns=None, qual=None, etype=None, pscrn=None, opt=None, int16_prescreener=None, int16_predictor=None, exp=None, kernel=None, taps=None, a1=None, a2=None, invks=False, invkstaps=3): core = vs.get_core() # Parameters of scaling if target_height is None: target_height = input.height if src_top is None: src_top = 0 if src_height is None: src_height = input.height elif src_height <= 0: src_height = input.height - src_top + src_height if scale_thr is None: scale_thr = 1.125 scale = target_height / src_height # Total scaling ratio eTimes = math.ceil(math.log(scale / scale_thr, 2)) if scale > scale_thr else 0 # Iterative times of nnedi3 eScale = 1 << eTimes # Scaling ratio of nnedi3 pScale = scale / eScale # Scaling ratio of fmtc.resample # Parameters of nnedi3 if nsize is None: nsize = 0 if nns is None: nns = 3 if qual is None: qual = 2 # Parameters of fmtc.resample if kernel is None: kernel = 'spline36' else: kernel = kernel.lower() # Skip scaling if not needed if scale == 1 and src_top == 0 and src_height == input.height: return input # Scaling with nnedi3 last = nnedi3_rpow2_vertical(input, eTimes, 1, nsize, nns, qual, etype, pscrn, opt, int16_prescreener, int16_predictor, exp) # Center shift calculation vShift = 0.5 if eTimes >= 1 else 0 # Scaling with fmtc.resample as well as correct center shift w = last.width h = target_height sx = 0 sy = src_top * eScale - vShift sw = last.width sh = src_height * eScale if h != last.height or sy != 0 or sh != last.height: if h < last.height and invks is True: last = core.fmtc.resample(last, w, h, sx, sy, sw, sh, kernel=kernel, taps=taps, a1=a1, a2=a2, invks=True, invkstaps=invkstaps) else: last = core.fmtc.resample(last, w, h, sx, sy, sw, sh, kernel=kernel, taps=taps, a1=a1, a2=a2) # Output return last
def clamp16 (src, bright_limit, dark_limit, overshoot=0, undershoot=0): core = vs.get_core () os = overshoot * 256 us = undershoot * 256 clip = core.std.Expr ([src, bright_limit, dark_limit], ["x y {os} + > y {os} + x ? z {us} - < z {us} - x ?".format (os=os, us=us)]) return clip
def setUp(self): self.core = vs.get_core() self.frame = self.core.std.BlankClip().get_frame(0) self.props = self.frame.props self.frame_copy = self.frame.copy() self.props_rw = self.frame_copy.props
def Baa(c, aa = "sangnom2", ss = None, mask=True, mthr = 30, blur=5, expand = 1, chroma = False): core = vs.get_core() aac = 48 if chroma == True else 0 if not isinstance(c, vs.VideoNode): raise ValueError('ediaaclip: This is not a clip') edibits=c.format.bits_per_sample if edibits > 8: a8 = core.fmtc.bitdepth(c, bits=8) else : a8 = c if mask == True: mask = core.generic.Prewitt(a8, mthr, mthr) mask = BlurLoop(ExpandLoop(mask, expand), blur) if ss == None: ss = 2 if aa == "sangnom2" else 1.1 if ss != 1: a8 = Resize(a8, m16(c.width * ss), m16(c.height * ss)) if aa == "nnedi3": a8 = Resize(core.nnedi3.nnedi3(a8, field=1,dh=True).std.Transpose().nnedi3.nnedi3(field=1,dh=True).std.Transpose(), a8.width, a8.height, -0.5,-0.5,2*a8.width+.001,2*a8.height+.001) elif aa == "eedi3": a8 = Resize(core.eedi3.eedi3(a8, field=1,dh=True).std.Transpose().eedi3.eedi3(field=1,dh=True).std.Transpose(), a8.width, a8.height, -0.5,-0.5,2*a8.width+.001,2*a8.height+.001) elif aa == "eedi2": a8 = Resize(core.eedi2.EEDI2(a8, field=1,dh=True).std.Transpose().eedi2.EEDI2(field=1,dh=True).std.Transpose(), a8.width, a8.height, -0.5,-0.5,2*a8.width+.001,2*a8.height+.001) #To-Do rewrite eedix+sangnom2 combo to not throw away good field elif aa == "eedi2+sangnom2": a8 = Resize(core.std.Transpose(core.sangnom.SangNomMod(core.std.Transpose(core.sangnom.SangNomMod(core.std.Transpose(core.eedi2.EEDI2(core.std.Transpose(core.eedi2.EEDI2(a8, field=1,dh=True)), field=1,dh=True)),aac=aac)),aac=aac)), a8.width, a8.height, -0.5,-0.5,2*a8.width+.001,2*a8.height+.001) elif aa == "eedi3+sangnom2": a8 = Resize(core.std.Transpose(core.sangnom.SangNomMod(core.std.Transpose(core.sangnom.SangNomMod(core.std.Transpose(core.eedi3.eedi3(core.std.Transpose(core.eedi3.eedi3(a8, field=1,dh=True)), field=1,dh=True)),aac=aac)),aac=aac)), a8.width, a8.height, -0.5,-0.5,2*a8.width+.001,2*a8.height+.001) else: a8 = core.sangnom.SangNomMod(a8,aac=aac).std.Transpose().sangnom.SangNomMod(aac=aac).std.Transpose() if ss != 1: a8 = Resize(a8, c.width, c.height) if edibits > 8: a8 = core.fmtc.bitdepth(a8,bits=edibits) if isinstance(mask, vs.VideoNode): mask = core.fmtc.bitdepth(mask,bits=edibits) if isinstance(mask, vs.VideoNode): return core.std.MaskedMerge(c,a8,mask) return a8
def interpolate(config, recalcconfig=None): core = vs.get_core() clip = video_in # Interpolating to fps higher than 60 is too CPU-expensive # Use interpolation from opengl video output dst_fps = display_fps while (dst_fps > 60): dst_fps /= 2 src_fps_num = int(container_fps * 1e8) src_fps_den = int(1e8) dst_fps_num = int(dst_fps * 1e4) dst_fps_den = int(1e4) # Needed because clip FPS is missing clip = core.std.AssumeFPS(clip, fpsnum = src_fps_num, fpsden = src_fps_den) print("Reflowing from ",src_fps_num/src_fps_den," fps to ",dst_fps_num/dst_fps_den," fps.") pad = config.get('blksize', 8) sup = core.mv.Super(clip, pel=1, hpad=pad, vpad=pad) bvec, fvec = analyse(sup, config) if recalcconfig: bvec, fvec = recalculate(sup, bvec, fvec, recalcconfig) clip = core.mv.FlowFPS(clip, sup, bvec, fvec, num=dst_fps_num, den=dst_fps_den, thscd2=90) clip.set_output()
def BlurLoop(c, x, planes=[0]): if c.format.color_family != vs.GRAY: rg = [0,0,0] if 0 in planes: rg[0] = 12 else: rg[0] = 0 if 1 in planes: rg[1] = 12 else: rg[1] = 0 if 2 in planes: rg[2] = 12 else: rg[2] = 0 else: rg = [12] core = vs.get_core() for y in range(0, x): c = core.rgvs.RemoveGrain(c, rg) return c
def LinearAndGamma(src, l2g_flag, fulls, fulld, curve, planes, gcor, sigmoid, thr, cont): core = vs.get_core() if curve == 'srgb': c_num = 0 elif curve in ['709', '601', '170']: c_num = 1 elif curve == '240': c_num = 2 elif curve == '2020': c_num = 3 else: raise ValueError('LinearAndGamma: wrong curve value') if src.format.color_family == vs.GRAY: planes = [0] # BT-709/601 # sRGB SMPTE 170M SMPTE 240M BT-2020 k0 = [0.04045, 0.081, 0.0912, 0.08145][c_num] phi = [12.92, 4.5, 4.0, 4.5][c_num] alpha = [0.055, 0.099, 0.1115, 0.0993][c_num] gamma = [2.4, 2.22222, 2.22222, 2.22222][c_num] def g2l(x): expr = x / 65536 if fulls else (x - 4096) / 56064 if expr <= k0: expr /= phi else: expr = ((expr + alpha) / (1 + alpha)) ** gamma if gcor != 1 and expr >= 0: expr **= gcor if sigmoid: x0 = 1 / (1 + math.exp(cont * thr)) x1 = 1 / (1 + math.exp(cont * (thr - 1))) expr = thr - math.log(max(1 / max(expr * (x1 - x0) + x0, 0.000001) - 1, 0.000001)) / cont if fulld: return min(max(round(expr * 65536), 0), 65535) else: return min(max(round(expr * 56064 + 4096), 0), 65535) # E' = (E <= k0 / phi) ? E * phi : (E ^ (1 / gamma)) * (alpha + 1) - alpha def l2g(x): expr = x / 65536 if fulls else (x - 4096) / 56064 if sigmoid: x0 = 1 / (1 + math.exp(cont * thr)) x1 = 1 / (1 + math.exp(cont * (thr - 1))) expr = (1 / (1 + math.exp(cont * (thr - expr))) - x0) / (x1 - x0) if gcor != 1 and expr >= 0: expr **= gcor if expr <= k0 / phi: expr *= phi else: expr = expr ** (1 / gamma) * (alpha + 1) - alpha if fulld: return min(max(round(expr * 65536), 0), 65535) else: return min(max(round(expr * 56064 + 4096), 0), 65535) return core.std.Lut(src, planes=planes, function=l2g if l2g_flag else g2l)
def fulltonative (src, a=32, h=6.4, lowpass=6, mode=0): core = vs.get_core () NLMeans = core.knlm.KNLMeansCL resample = core.fmtc.resample Expr = core.std.Expr MakeDiff = core.std.MakeDiff MergeDiff = core.std.MergeDiff ShufflePlanes = core.std.ShufflePlanes Crop = core.std.CropRel def gauss_h (src, p=30): upsmp = resample (src, src.width * 2, src.height, kernel="gauss", a1=100, **fmtc_args) clip = resample (upsmp, src.width, src.height, kernel="gauss", a1=p, **fmtc_args) return clip pad = padding (src, a, a, a, a) srcy = ShufflePlanes (pad, 0, vs.GRAY) srcu = ShufflePlanes (pad, 1, vs.GRAY) srcv = ShufflePlanes (pad, 2, vs.GRAY) u4x = genpelclip (pad, pel=4) luma = ShufflePlanes (u4x, 0, vs.GRAY) u = Expr (ShufflePlanes (u4x, 1, vs.GRAY), "x 0.5 +") v = Expr (ShufflePlanes (u4x, 2, vs.GRAY), "x 0.5 +") unew = resizenr (NLMeans (u, d=0, a=a, s=0, h=h, wref=1.0, rclip=luma), pad.width, pad.height, sx=-1.5, sy=-1.5, kernel="spline", taps=6) vnew = resizenr (NLMeans (v, d=0, a=a, s=0, h=h, wref=1.0, rclip=luma), pad.width, pad.height, sx=-1.5, sy=-1.5, kernel="spline", taps=6) uhi = MakeDiff (unew, gauss_h (unew, p=lowpass)) if mode else MakeDiff (unew, gauss (unew, p=lowpass)) vhi = MakeDiff (vnew, gauss_h (vnew, p=lowpass)) if mode else MakeDiff (vnew, gauss (vnew, p=lowpass)) ufinal = Expr (MergeDiff (Expr (srcu, "x 0.5 +"), uhi), "x 0.5 -") vfinal = Expr (MergeDiff (Expr (srcv, "x 0.5 +"), vhi), "x 0.5 -") merge = ShufflePlanes ([srcy, ufinal, vfinal], [0, 0, 0], vs.YUV) clip = Crop (merge, a, a, a, a) return clip
def delete_range(src, start, end=None): """ Deletes a range of frames from a clip. If no end frame is given, it will only delete the start frame. """ core = vs.get_core() if end is None: end = start if start < 0 or start > src.num_frames - 1: raise ValueError('start frame out of bounds: {}.'.format(start)) if end < start or end > src.num_frames - 1: raise ValueError('end frame out of bounds: {}.'.format(end)) if start != 0: final = src[:start] if end < src.num_frames - 1: final = final + src[end + 1:] else: final = src[end + 1:] if src.num_frames != final.num_frames + (end - start + 1): raise ValueError('output expected framecount missmatch.') return final
def hipass (src, sharp, p=16): core = vs.get_core () MakeDiff = core.std.MakeDiff MergeDiff = core.std.MergeDiff hif = MakeDiff (sharp, gauss (sharp, p=p)) clip = MergeDiff (gauss (src, p=p), hif) return clip
def detailsharpen(clip, sstr=1.01, estr=10, ethr=5, repair=False, rmode=12): core = vs.get_core() bd = clip.format.bits_per_sample max_ = 2 ** bd - 1 mid = (max_ + 1) // 2 scl = (max_ + 1) // 256 src = clip clip = vsh.get_luma(clip) blur = core.rgvs.RemoveGrain(clip, 20) # "x y == x x x y - abs 0.25 ^ 4.24 * x y - 2 ^ x y - 2 ^ 2 + / * x y - x y - abs / * 1 x y - abs 16 / 4 ^ + / + ?" # "x x y - abs 0.25 ^ 4.24 * x y - x y - abs 2 + / * +" # 'x x y - abs 4 / 1 4 / ^ 4 * 1.5 * x y - x y - abs 2 + / * +' # 'x x y - abs 1 4 / ^ 2.83 * 1.5 * x y - x y - abs 2 + / * +' # expr = 'x x y - 1 x y - 16 / 4 ^ + / +' expr = '{x} {x} {y} - abs 4 / log 0.25 * exp 4 * {st} * {x} {y} - {x} {y} - abs 1.001 + / * + {sc}'.format( x='x {} /'.format(scl) if bd != 8 else 'x', y='y {} /'.format(scl) if bd != 8 else 'y', sc='{} *'.format(scl) if bd != 8 else '', st=sstr) clip = core.std.Expr([clip, blur], [expr]) if estr > 0: tmp = clip clip = core.msmoosh.MSharpen(clip, threshold=ethr, strength=estr) if repair is True: clip = core.rgvs.Repair(clip=clip, repairclip=tmp, mode=rmode) clip = vsh.merge_chroma(clip, src) return clip
def add16 (src1, src2, dif=True): core = vs.get_core () if dif: clip = core.std.MergeDiff (src1, src2) else: clip = core.std.Expr ([src1, src2], ["x y +"]) return clip
def StoreVect (vectors, log): core = vs.get_core () w = vectors.get_frame (0).width with open (log, "w") as f: print (w, file=f) vectors = core.std.CropAbs (vectors, width=w, height=1) return vectors
def sub16 (src1, src2, dif=True): core = vs.get_core () if dif: clip = core.std.MakeDiff (src1, src2) else: clip = core.std.Expr ([src1, src2], ["x y -"]) return clip
def fit(clipa, clipb): core = vs.get_core() bd = clipb.format.bits_per_sample max_ = 2 ** bd - 1 mid = (max_ + 1) // 2 if clipb.format.num_planes > 1: if clipb.format.color_family == vs.RGB: color = [max_, max_, max_] else: color = [max_, mid, mid] else: color = [max_] if clipa.width > clipb.width: clipb = core.std.AddBorders(clip=clipb, left=0, right=clipa.width - clipb.width, color=color) elif clipa.width < clipb.width: clipb = core.std.CropRel(clip=clipb, left=0, right=clipb.width - clipa.width) if clipa.height > clipb.height: clipb = core.std.AddBorders(clip=clipb, top=0, bottom=clipa.height - clipb.height, color=color) elif clipa.height < clipb.height: clipb = core.std.CropRel(clip=clipb, top=0, bottom=clipb.height - clipa.height) return clipb
def sharpfinal (soft, dif, limit, vmulti, peldif=None, pellimit=None, pel=4, tr=6, thsad=400, thscd1=10000, thscd2=255, str=1.00, lowpass=8, a=32, h=6.4, thr=0.00390625, elast=None): core = vs.get_core () Repair = core.rgsf.Repair Maximum = core.flt.Maximum Minimum = core.flt.Minimum Expr = core.std.Expr MakeDiff = core.std.MakeDiff MergeDiff = core.std.MergeDiff MSuper = core.mvsf.Super MDegrainN = mvmulti.DegrainN MCompensate = mvmulti.Compensate expression = ["{x} {y} {x} - abs 4 / 1 4 / pow 4 * 1.6 * {str} * {y} {x} - {y} {x} - abs 1.001 + / * + 256 /".format (str=str, x="x 256 *", y="y 256 *")] blankd = Expr ([dif], ["0.5"]) superdif = MSuper (dif, pelclip=peldif, rfilter=2, pel=pel, **msuper_args) supercmp = MSuper (limit, pelclip=pellimit, rfilter=2, pel=pel, **msuper_args) coarse = MDegrainN (blankd, superdif, vmulti, tr=tr, thsad=10000, thscd1=thscd1, thscd2=thscd2, **mdegrain_args) fine = MDegrainN (blankd, superdif, vmulti, tr=tr, thsad=thsad, thscd1=thscd1, thscd2=thscd2, **mdegrain_args) newdif = Expr ([dif, coarse, blankd, fine], ["y z - abs x z - abs > a y ?"]) averaged = MergeDiff (soft, newdif) comp = MCompensate (soft, supercmp, vmulti, tr=tr, thsad=thsad, thscd1=thscd1, thscd2=thscd2) bright = Expr ([maxmulti (comp, tr=tr), Maximum (limit)], "x y min") dark = Expr ([minmulti (comp, tr=tr), Minimum (limit)], "x y max") clamped = clamp (averaged, bright, dark, overshoot=0.0, undershoot=0.0) amplified = Expr ([soft, clamped], expression) clip = hipass (soft, Repair (amplified, halonr (amplified, a, h, thr, elast, lowpass), 16), lowpass) return clip
def move(clips, x, y): core = vs.get_core() moved = None for clip in clips: if clip.format.num_planes == 1: color = [(2 ** clip.format.bits_per_sample) - 1] else: color = None if x != 0 or y != 0: if x >= 0: right = 0 left = x else: right = abs(x) left = 0 if y >= 0: top = 0 bottom = y else: top = abs(y) bottom = 0 clip = core.std.AddBorders(clip=clip, left=left, right=right, top=top, bottom=bottom, color=color) clip = core.std.CropRel(clip=clip, left=right, right=left, top=bottom, bottom=top) if clip is isinstance(list()): moved.append(clip) else: moved = clip return moved
def subtract(c1, c2, luma=126, planes=[0]): core = vs.get_core() expr = ('{luma} x + y -').format(luma=luma) expr = [(i in planes) * expr for i in range(c1.format.num_planes)] return core.std.Expr([c1, c2], expr)
def soothe(clip, src, keep=24): core = vs.get_core() clip_bits = clip.format.bits_per_sample src_bits = src.format.bits_per_sample if clip_bits != src_bits: raise ValueError(MODULE_NAME + ': temporal_stabilize: bits depth of clip and src mismatch.') neutral = 1 << (clip_bits - 1) ceil = (1 << clip_bits) - 1 multiple = ceil // 255 const = 100 * multiple kp = keep * multiple diff = core.std.MakeDiff(src, clip) try: diff_soften = core.misc.AverageFrame(diff, weights=[1, 1, 1], scenechange=32) except AttributeError: diff_soften = core.focus.TemporalSoften(diff, radius=1, luma_threshold=255, chroma_threshold=255, scenechange=32, mode=2) diff_soothed_expr = "x {neutral} - y {neutral} - * 0 < x {neutral} - {const} / {kp} * {neutral} + " \ "x {neutral} - abs y {neutral} - abs > " \ "x {kp} * y {const} {kp} - * + {const} / x ? ?".format(neutral=neutral, const=const, kp=kp) diff_soothed = core.std.Expr([diff, diff_soften], diff_soothed_expr) clip_soothed = core.std.MakeDiff(src, diff_soothed) return clip_soothed
def temporal_stabilize(clip, src, delta=3, pel=1, retain=0.6): core = vs.get_core() clip_bits = clip.format.bits_per_sample src_bits = src.format.bits_per_sample if clip_bits != src_bits: raise ValueError(MODULE_NAME + ': temporal_stabilize: bits depth of clip and src mismatch.') if delta not in [1, 2, 3]: raise ValueError(MODULE_NAME + ': temporal_stabilize: delta (1~3) invalid.') diff = core.std.MakeDiff(src, clip) clip_super = core.mv.Super(clip, pel=pel) diff_super = core.mv.Super(diff, pel=pel, levels=1) backward_vectors = [core.mv.Analyse(clip_super, isb=True, delta=i+1, overlap=8, blksize=16) for i in range(delta)] forward_vectors = [core.mv.Analyse(clip_super, isb=False, delta=i+1, overlap=8, blksize=16) for i in range(delta)] vectors = [vector for vector_group in zip(backward_vectors, forward_vectors) for vector in vector_group] stabilize_func = { 1: core.mv.Degrain1, 2: core.mv.Degrain2, 3: core.mv.Degrain3 } diff_stabilized = stabilize_func[delta](diff, diff_super, *vectors) neutral = 1 << (clip_bits - 1) expr = 'x {neutral} - abs y {neutral} - abs < x y ?'.format(neutral=neutral) diff_stabilized_limited = core.std.Expr([diff, diff_stabilized], expr) diff_stabilized = core.std.Merge(diff_stabilized_limited, diff_stabilized, retain) clip_stabilized = core.std.MakeDiff(src, diff_stabilized) return clip_stabilized
def daa(clip, mode=-1, opencl=False): core = vs.get_core() if opencl is True: try: daa_nnedi3 = core.nnedi3cl.NNEDI3CL except AttributeError: daa_nnedi3 = core.nnedi3.nnedi3 else: try: daa_nnedi3 = core.znedi3.nnedi3 except AttributeError: daa_nnedi3 = core.nnedi3.nnedi3 if mode == -1: nn = daa_nnedi3(clip, field=3) nnt = daa_nnedi3(core.std.Transpose(clip), field=3).std.Transpose() clph = core.std.Merge(core.std.SelectEvery(nn, cycle=2, offsets=0), core.std.SelectEvery(nn, cycle=2, offsets=1)) clpv = core.std.Merge(core.std.SelectEvery(nnt, cycle=2, offsets=0), core.std.SelectEvery(nnt, cycle=2, offsets=1)) clp = core.std.Merge(clph, clpv) elif mode == 1: nn = daa_nnedi3(clip, field=3) clp = core.std.Merge(core.std.SelectEvery(nn, cycle=2, offsets=0), core.std.SelectEvery(nn, cycle=2, offsets=1)) elif mode == 2: nnt = daa_nnedi3(core.std.Transpose(clip), field=3).std.Transpose() clp = core.std.Merge(core.std.SelectEvery(nnt, cycle=2, offsets=0), core.std.SelectEvery(nnt, cycle=2, offsets=1)) else: raise ValueError(MODULE_NAME + ': daa: at least one direction should be processed.') return clp
def padding (src, left=0, right=0, top=0, bottom=0): core = vs.get_core () resample = core.fmtc.resample w = src.width h = src.height clip = resample (src, w+left+right, h+top+bottom, -left, -top, w+left+right, h+top+bottom, kernel="point", **fmtc_args) return clip
def Resize16nr (src, w=None, h=None, sx=0, sy=0, sw=0, sh=0, kernel="spline36", kernelh=None, kernelv=None, fh=1, fv=1, taps=4, a1=None, a2=None, a3=None, kovrspl=1, cnorm=True, center=True, fulls=None, fulld=None, cplace="mpeg2", invks=False, invkstaps=4, noring=True): core = vs.get_core () w = src.width if w is None else w h = src.height if h is None else h kernelh = kernel if kernelh is None else kernelh kernelv = kernel if kernelv is None else kernelv sr_h = float (w / src.width) sr_v = float (h / src.height) sr_up = max (sr_h, sr_v) sr_dw = 1.0 / min (sr_h, sr_v) sr = max (sr_up, sr_dw) thr = 2.5 nrb = (sr > thr) nrf = (sr < thr + 1.0 and noring) nrr = min (sr - thr, 1.0) if nrb else 1.0 nrv = [round ((1.0 - nrr) * 65535), round ((1.0 - nrr) * 65535), round ((1.0 - nrr) * 65535)] if nrb else [0, 0, 0] nrm = core.std.BlankClip (clip=src, width=w, height=h, color=nrv) if nrb and nrf else 0 main = core.fmtc.resample (src, w=w, h=h, sx=sx, sy=sy, sw=sw, sh=sh, kernel=kernel, kernelh=kernelh, kernelv=kernelv, fh=fh, fv=fv, taps=taps, a1=a1, a2=a2, a3=a3, kovrspl=kovrspl, cnorm=cnorm, center=center, fulls=fulls, fulld=fulld, cplace=cplace, invks=invks, invkstaps=invkstaps) nrng = core.fmtc.resample (src, w=w, h=h, sx=sx, sy=sy, sw=sw, sh=sh, kernel="gauss", a1=100, center=center, fulls=fulls, fulld=fulld, cplace=cplace) if nrf else main clip = core.rgvs.Repair (main, nrng, 1) if nrf else main clip = core.std.MaskedMerge (main, clip, nrm) if nrf and nrb else clip return clip
def deconvolution (src, loop=2, lowpass=8, a=32, h=12.8, thr=0.00390625, elast=None): core = vs.get_core () Deconv = core.vcfreq.Sharp dcv = Deconv (src, **deconv_args) clip = hipass (src, dcv, p=lowpass) loop = loop - 1 return halonr (clip, a, h, thr, elast, lowpass) if loop == 0 else deconvolution (clip, loop, lowpass, a, h, thr, elast)
def dec_txt60mc (src,frame_ref, srcbob=False,draft=False,tff=None): core = vs.get_core() field_ref = frame_ref if srcbob else frame_ref * 2 field_ref = field_ref % 5 invpos = (5 - field_ref) % 5 pel = 1 if draft else 2 if srcbob: last = src elif draft: last = haf.Bob(src,tff=tff) else: last = haf.QTGMC(src,SourceMatch=3, Lossless=2, TR0=1, TR1=1, TR2=1,TFF=tff) if invpos > 3: clean = core.std.AssumeFPS(core.std.Trim(last, 0, 0)+core.std.SelectEvery(last,5, 8 - invpos), fpsnum=12000, fpsden=1001) else: clean = core.std.SelectEvery(last,5, 4 - invpos) if invpos > 1: jitter = core.std.AssumeFPS(core.std.Trim(last, 0, 0)+core.std.SelectEvery(last,5, [6 - invpos, 5 - invpos]), fpsnum=24000, fpsden=1001) else: jitter = core.std.SelectEvery(last,5, [1 - invpos, 2 - invpos]) jsup = core.mv.Super(jitter,pel=pel) vect_f = core.mv.Analyse (jsup,isb=False, delta=1, overlap=4) vect_b = core.mv.Analyse (jsup,isb=True, delta=1, overlap=4) comp = core.mv.FlowInter (jitter,jsup, vect_b, vect_f, time=50, thscd1=400) fixed = core.std.SelectEvery (comp,2, 0) last = core.std.Interleave ([fixed, clean]) return last[invpos // 3:]
def subtofull (src, cplace="mpeg2"): core = vs.get_core () resample = core.fmtc.resample Expr = core.std.Expr ShufflePlanes = core.std.ShufflePlanes factor_w = src.format.subsampling_w factor_h = src.format.subsampling_h def inline_pel_422 (src): NNEDI = core.nnedi3.nnedi3 Transpose = core.std.Transpose clip = Transpose (NNEDI (Transpose (src), **nnedi_args)) return clip srcy = ShufflePlanes (src, 0, vs.GRAY) srcu = Expr (ShufflePlanes (src, 1, vs.GRAY), "x 0.5 +") srcv = Expr (ShufflePlanes (src, 2, vs.GRAY), "x 0.5 +") if factor_w == 1 and factor_h == 1: unew = genpelclip (srcu, pel=2) vnew = genpelclip (srcv, pel=2) if cplace == "mpeg2": ushift = resample (unew, sx=0, sy=-0.5, kernel="spline", taps=6, **fmtc_args) vshift = resample (vnew, sx=0, sy=-0.5, kernel="spline", taps=6, **fmtc_args) elif cplace == "mpeg1": ushift = resample (unew, sx=-0.5, sy=-0.5, kernel="spline", taps=6, **fmtc_args) vshift = resample (vnew, sx=-0.5, sy=-0.5, kernel="spline", taps=6, **fmtc_args) else: raise ValueError ("wtf?") if factor_w == 1 and factor_h == 0: unew = inline_pel_422 (srcu) vnew = inline_pel_422 (srcv) ushift = resample (unew, sx=1, sy=0, kernel="spline", taps=6, **fmtc_args) vshift = resample (vnew, sx=1, sy=0, kernel="spline", taps=6, **fmtc_args) ufinal = Expr (ushift, "x 0.5 -") vfinal = Expr (vshift, "x 0.5 -") clip = ShufflePlanes ([srcy, ufinal, vfinal], [0, 0, 0], vs.YUV) return clip
def naa(c, ss=2, chroma=False): """ naa - antialiasing function using nnedi3 +++++++++++++++++++++++++++++++++ ss: supersampling value, must be even. cp: if false chroma will not be altered. """ core = vs.get_core() if ss % 2 != 0: raise ValueError('ss must be an even number.') src = c if chroma is False: c = vsh.get_luma(c) if c.format.bits_per_sample > 8: fapprox = 12 else: fapprox = 7 ret = core.nnedi3.nnedi3_rpow2(clip=c, rfactor=ss, correct_shift=1, qual=2, fapprox=fapprox, nsize=6) ret = core.nnedi3.nnedi3(clip=ret, field=0, nns=2, fapprox=fapprox, nsize=6) ret = core.std.Transpose(ret) ret = core.nnedi3.nnedi3(clip=ret, field=0, nns=2, fapprox=fapprox, nsize=6) ret = core.std.Transpose(ret) ret = core.fmtc.resample(ret, c.width, c.height) if ret.format.bits_per_sample != c.format.bits_per_sample: ret = core.fmtc.bitdepth(ret, bits=c.format.bits_per_sample) if chroma is False: ret = vsh.merge_chroma(ret, src) return ret
def __init__(self): self.core = vs.get_core() self.MSuper = self.core.mvsf.Super self.MAnalyze = mvmulti.Analyze self.MRecalculate = mvmulti.Recalculate self.MDegrainN = mvmulti.DegrainN self.RGB2OPP = self.core.bm3d.RGB2OPP self.OPP2RGB = self.core.bm3d.OPP2RGB self.BMBasic = self.core.bm3d.VBasic self.BMFinal = self.core.bm3d.VFinal self.Aggregate = self.core.bm3d.VAggregate self.DFTTest = self.core.dfttest.DFTTest self.KNLMeansCL = self.core.knlm.KNLMeansCL self.NNEDI = self.core.nnedi3.nnedi3 self.Resample = self.core.fmtc.resample self.Expr = self.core.std.Expr self.MakeDiff = self.core.std.MakeDiff self.MergeDiff = self.core.std.MergeDiff self.Crop = self.core.std.CropRel self.CropAbs = self.core.std.CropAbs self.Transpose = self.core.std.Transpose self.BlankClip = self.core.std.BlankClip self.AddBorders = self.core.std.AddBorders self.StackHorizontal = self.core.std.StackHorizontal self.StackVertical = self.core.std.StackVertical self.MaskedMerge = self.core.std.MaskedMerge self.ShufflePlanes = self.core.std.ShufflePlanes self.SetFieldBased = self.core.std.SetFieldBased
def replace_range(clip1, clip2, start, end=None): """ Replaces a range of frames of a clip with the same range of frames from another clip. If no end frame is given, it will only replace the start frame. """ core = vs.get_core() if end is None: end = start if start < 0 or start > clip1.num_frames - 1: raise ValueError('start frame out of bounds: {}.'.format(start)) if end < start or end > clip1.num_frames - 1: raise ValueError('end frame out of bounds: {}.'.format(end)) if start > 0: temp = 'core.std.Trim(clip1, 0, start - 1) + ' else: temp = '' temp += 'core.std.Trim(clip2, start, end)' if end < clip1.num_frames - 1: temp += '+ core.std.Trim(clip1, end + 1)' final = eval(temp) if clip1.num_frames != final.num_frames: raise ValueError('input / output framecount missmatch (got: {}; expected: {}).' .format(final.num_frames, clip1.num_frames)) return final
def RestoreDepth(LowDepth, HighDepth, diffmask=None, dmode=None, planes=[0, 1, 2]): core = vs.get_core() lowbits = LowDepth.format.bits_per_sample highbits = HighDepth.format.bits_per_sample DownscaledDepth = core.fmtc.bitdepth(HighDepth,bits=lowbits,dmode=dmode) Yexpr = ("x y - abs 0 > " + str(pow(2,lowbits)-1) + " 0 ?") if 0 in planes else "" Uexpr = ("x y - abs 0 > " + str(pow(2,lowbits)-1) + " 0 ?") if 1 in planes else "" Vexpr = ("x y - abs 0 > " + str(pow(2,lowbits)-1) + " 0 ?") if 2 in planes else "" if isinstance(diffmask, vs.VideoNode) == False: diffmask = core.std.Expr(clips=[LowDepth, DownscaledDepth], expr=[Yexpr, Uexpr, Vexpr]) UpscaledDepth = core.fmtc.bitdepth(LowDepth,bits=highbits) UpscaledMask = core.fmtc.bitdepth(diffmask,bits=highbits) return core.std.MaskedMerge(HighDepth, UpscaledDepth, UpscaledMask,planes=planes) # original script by Torchlight and Firesledge(?) # port by BakaProxy # bob and qtgmc from HavsFunc is used # what is this used for again? def dec_txt60mc (src,frame_ref, srcbob=False,draft=False,tff=None): core = vs.get_core() field_ref = frame_ref if srcbob else frame_ref * 2 field_ref = field_ref % 5 invpos = (5 - field_ref) % 5 pel = 1 if draft else 2 if srcbob: last = src elif draft: last = haf.Bob(src,tff=tff) else: last = haf.QTGMC(src,SourceMatch=3, Lossless=2, TR0=1, TR1=1, TR2=1,TFF=tff) if invpos > 3: clean = core.std.AssumeFPS(core.std.Trim(last, 0, 0)+core.std.SelectEvery(last,5, 8 - invpos), fpsnum=12000, fpsden=1001) else: clean = core.std.SelectEvery(last,5, 4 - invpos) if invpos > 1: jitter = core.std.AssumeFPS(core.std.Trim(last, 0, 0)+core.std.SelectEvery(last,5, [6 - invpos, 5 - invpos]), fpsnum=24000, fpsden=1001) else: jitter = core.std.SelectEvery(last,5, [1 - invpos, 2 - invpos]) jsup = core.mv.Super(jitter,pel=pel) vect_f = core.mv.Analyse (jsup,isb=False, delta=1, overlap=4) vect_b = core.mv.Analyse (jsup,isb=True, delta=1, overlap=4) comp = core.mv.FlowInter (jitter,jsup, vect_b, vect_f, time=50, thscd1=400) fixed = core.std.SelectEvery (comp,2, 0) last = core.std.Interleave ([fixed, clean]) return last[invpos // 3:]
def nnedi3_dh(input, field=1, nsize=None, nns=None, qual=None, etype=None, pscrn=None, opt=None, int16_prescreener=None, int16_predictor=None, exp=None): core = vs.get_core() return core.nnedi3.nnedi3(input, field=field, dh=True, nsize=nsize, nns=nns, qual=qual, etype=etype, pscrn=pscrn, opt=opt, int16_prescreener=int16_prescreener, int16_predictor=int16_predictor, exp=exp)
def select_best_chunking_method(self): """ Selecting best chunking method based on available methods """ if not find_executable('vspipe'): self.chunk_method = 'hybrid' log('Set Chunking Method: Hybrid') else: try: import vapoursynth plugins = vapoursynth.get_core().get_plugins() if 'systems.innocent.lsmas' in plugins: log('Set Chunking Method: L-SMASH\n') self.chunk_method = 'vs_lsmash' elif 'com.vapoursynth.ffms2' in plugins: log('Set Chunking Method: FFMS2\n') self.chunk_method = 'vs_ffms2' except: log('Vapoursynth not installed but vspipe reachable\n' + 'Fallback to Hybrid\n') self.chunk_method = 'hybrid'
def blank_it(src, start, end=None, color='black'): """ Blanks a range of frames in a clip, by default to pure balck. If no endframe is provided start frame will be used. """ core = vs.get_core() if end is None: end = start e = core.std.BlankClip(src, color=color) if start != 0: z = src[:start] + e[start:end + 1] else: z = e[start:end + 1] if end < src.num_frames - 1: z = z + src[end + 1:] if src.num_frames != z.num_frames: raise ValueError( 'input / output framecount missmatch (got: {}; expected: {}).'. format(z.num_frames, src.num_frames)) return z
def assrenderwrapper(clip, data, charset=None, debuglevel=None, fontdir=None, linespacing=None, margins=None, sar=None, scale=None): core = vs.get_core() subs = core.assvapour.AssRender(clip=clip, data=data, charset=charset, debuglevel=debuglevel, fontdir=fontdir, linespacing=linespacing, margins=margins, sar=sar, scale=scale) subs[0] = core.resize.Bicubic(subs[0], format=clip.format.id) subs[1] = core.resize.Bicubic(subs[1], format=clip.format.id) return core.std.MaskedMerge(clipa=clip, clipb=subs[0], mask=subs[1])
def TAAmbk(clip, aatype=1, aatypeu=None, aatypev=None, preaa=0, strength=0.0, cycle=0, mtype=None, mclip=None, mthr=None, mthr2=None, mlthresh=None, mpand=(1, 0), txtmask=0, txtfade=0, thin=0, dark=0.0, sharp=0, aarepair=0, postaa=None, src=None, stabilize=0, down8=True, showmask=0, opencl=False, opencl_device=0, **args): core = vs.get_core() aatypeu = aatype if aatypeu is None else aatypeu aatypev = aatype if aatypev is None else aatypev if mtype is None: mtype = 0 if preaa == 0 and True not in (aatype, aatypeu, aatypev) else 1 if postaa is None: postaa = True if abs(sharp) > 70 or (0.4 < abs(sharp) < 1) else False if src is None: src = clip else: if clip.format.id != src.format.id: raise ValueError(MODULE_NAME + ': clip format and src format mismatch.') elif clip.width != src.width or clip.height != src.height: raise ValueError(MODULE_NAME + ': clip resolution and src resolution mismatch.') preaa_clip = clip if preaa == 0 else daa(clip, preaa) if thin == 0 and dark == 0: edge_enhanced_clip = preaa_clip elif thin != 0 and dark != 0: edge_enhanced_clip = haf.Toon(core.warp.AWarpSharp2(preaa_clip, depth=int(thin)), str=float(dark)) elif thin == 0: edge_enhanced_clip = haf.Toon(preaa_clip, str=float(dark)) else: edge_enhanced_clip = core.warp.AWarpSharp2(preaa_clip, depth=int(thin)) aa_kernel = { 1: AAEedi2, 2: AAEedi3, 3: AANnedi3, 4: AANnedi3UpscaleSangNom, 5: AASpline64NRSangNom, 6: AASpline64SangNom, -1: AAEedi2SangNom, -2: AAEedi3SangNom, -3: AANnedi3SangNom, 'Eedi2': AAEedi2, 'Eedi3': AAEedi3, 'Nnedi3': AANnedi3, 'Nnedi3UpscaleSangNom': AANnedi3UpscaleSangNom, 'Spline64NrSangNom': AASpline64NRSangNom, 'Spline64SangNom': AASpline64SangNom, 'Eedi2SangNom': AAEedi2SangNom, 'Eedi3SangNom': AAEedi3SangNom, 'Nnedi3SangNom': AANnedi3SangNom, 'PointSangNom': AAPointSangNom } aaed_clip = None if clip.format.color_family is vs.YUV: y = core.std.ShufflePlanes(edge_enhanced_clip, 0, vs.GRAY) u = core.std.ShufflePlanes(edge_enhanced_clip, 1, vs.GRAY) v = core.std.ShufflePlanes(edge_enhanced_clip, 2, vs.GRAY) if aatype != 0: try: y = aa_kernel[aatype](y, strength, down8, opencl=opencl, opencl_device=opencl_device, **args).out() cycle_y = cycle while cycle_y > 0: y = aa_kernel[aatype](y, strength, down8, opencl=opencl, opencl_device=opencl_device, **args).out() cycle_y -= 1 y = mvf.Depth( y, clip.format.bits_per_sample) if down8 is True else y except KeyError: raise ValueError(MODULE_NAME + ': unknown aatype.') if aatypeu != 0: try: u = aa_kernel[aatypeu]( u, 0, down8, opencl=opencl, opencl_device=opencl_device, **args).out() # Won't do predown for u plane cycle_u = cycle while cycle_u > 0: u = aa_kernel[aatypeu](u, 0, down8, opencl=opencl, opencl_device=opencl_device, **args).out() cycle_u -= 1 u = mvf.Depth( u, clip.format.bits_per_sample) if down8 is True else u except KeyError: raise ValueError(MODULE_NAME + ': unknown aatypeu.') if aatypev != 0: try: v = aa_kernel[aatypev]( v, 0, down8, opencl=opencl, opencl_device=opencl_device, **args).out() # Won't do predown for v plane cycle_v = cycle while cycle_v > 0: v = aa_kernel[aatypev](v, 0, down8, opencl=opencl, opencl_device=opencl_device, **args).out() cycle_v -= 1 v = mvf.Depth( v, clip.format.bits_per_sample) if down8 is True else v except KeyError: raise ValueError(MODULE_NAME + ': unknown aatypev.') aaed_clip = core.std.ShufflePlanes([y, u, v], [0, 0, 0], vs.YUV) elif clip.format.color_family is vs.GRAY: y = edge_enhanced_clip if aatype != 0: try: y = aa_kernel[aatype](y, strength, down8, **args).out() cycle_y = cycle while cycle_y > 0: y = aa_kernel[aatype](y, strength, down8, **args).out() cycle_y -= 1 aaed_clip = mvf.Depth( y, clip.format.bits_per_sample) if down8 is True else y except KeyError: raise ValueError(MODULE_NAME + ': unknown aatype.') else: raise ValueError(MODULE_NAME + ': Unsupported color family.') abs_sharp = abs(sharp) if sharp >= 1: sharped_clip = haf.LSFmod(aaed_clip, strength=int(abs_sharp), defaults='old', source=src) elif sharp > 0: per = int(40 * abs_sharp) matrix = [-1, -2, -1, -2, 52 - per, -2, -1, -2, -1] sharped_clip = core.std.Convolution(aaed_clip, matrix) elif sharp == 0: sharped_clip = aaed_clip elif sharp > -1: sharped_clip = haf.LSFmod(aaed_clip, strength=round(abs_sharp * 100), defaults='fast', source=src) elif sharp == -1: blured = core.rgvs.RemoveGrain( aaed_clip, mode=20 if aaed_clip.width > 1100 else 11) diff = core.std.MakeDiff(aaed_clip, blured) diff = core.rgvs.Repair(diff, core.std.MakeDiff(src, aaed_clip), mode=13) sharped_clip = core.std.MergeDiff(aaed_clip, diff) else: sharped_clip = aaed_clip postaa_clip = sharped_clip if postaa is False else soothe( sharped_clip, src, 24) repaired_clip = postaa_clip if aarepair == 0 else core.rgvs.Repair( src, postaa_clip, aarepair) stabilized_clip = repaired_clip if stabilize == 0 else temporal_stabilize( repaired_clip, src, stabilize) if mclip is not None: mask = mclip try: masked_clip = core.std.MaskedMerge(src, stabilized_clip, mask, first_plane=True) except vs.Error: raise RuntimeError(MODULE_NAME + ': Something wrong with your mclip. ' 'Maybe resolution or bit_depth mismatch.') elif mtype != 0: if mtype == 1 or mtype is 'Canny': opencl_device = args.get('opencl_device', 0) mthr = 1.2 if mthr is None else mthr mthr2 = 8.0 if mthr2 is None else mthr2 mask = MaskCanny(clip, sigma=mthr, t_h=mthr2, lthresh=mlthresh, mpand=mpand, opencl=opencl, opencl_devices=opencl_device).out() elif mtype == 2 or mtype is 'Sobel': mthr = 1.2 if mthr is None else mthr mthr2 = 48 if mthr2 is None else mthr2 mask = MaskSobel(clip, sigma=mthr, binarize=mthr2, lthresh=mlthresh, mpand=mpand).out() elif mtype == 3 or mtype is 'prewitt': mthr = 62 if mthr is None else mthr mask = MaskPrewitt(clip, factor=mthr, lthresh=mlthresh, mpand=mpand).out() else: raise ValueError(MODULE_NAME + ': unknown mtype.') masked_clip = core.std.MaskedMerge(src, stabilized_clip, mask) else: masked_clip = stabilized_clip if txtmask > 0 and clip.format.color_family is not vs.GRAY: text_mask = FadeTextMask(clip, lthr=txtmask, fade_nums=txtfade).out() txt_protected_clip = core.std.MaskedMerge(masked_clip, src, text_mask, first_plane=True) else: txt_protected_clip = masked_clip if clip.format.bits_per_sample > 8 and down8 is True: clamped_clip = mvf.LimitFilter(src, txt_protected_clip, thr=1.0, elast=2.0) else: clamped_clip = txt_protected_clip try: if showmask == -1: return text_mask elif showmask == 1: return mask elif showmask == 2: return core.std.StackVertical([ core.std.ShufflePlanes([mask, core.std.BlankClip(src)], [0, 1, 2], vs.YUV), src ]) elif showmask == 3: return core.std.Interleave([ core.std.ShufflePlanes([mask, core.std.BlankClip(src)], [0, 1, 2], vs.YUV), src ]) else: return clamped_clip except UnboundLocalError: raise RuntimeError(MODULE_NAME + ': No mask to show if you don\'t have one.')
def get_lsb(src): core = vs.get_core() clip = core.fmtc.nativetostack16(src) return core.std.CropRel(clip, 0, 0, (clip.height // 2), 0)
def linear_and_gamma(src, l2g_flag=True, fulls=True, fulld=None, curve="srgb", gcor=1.0, sigmoid=False, thr=0.5, cont=6.5): core = vs.get_core() if curve == "srgb": k0 = "0.04045" phi = "12.92" alpha = "0.055" gamma = "2.4" elif curve == "709": k0 = "0.081" phi = "4.5" alpha = "0.099" gamma = "2.22222" elif curve == "240": k0 = "0.0912" phi = "4.0" alpha = "0.1115" gamma = "2.22222" elif curve == "2020": k0 = "0.08145" phi = "4.5" alpha = "0.0993" gamma = "2.22222" else: k0 = "0.04045" phi = "12.92" alpha = "0.055" gamma = "2.4" fulld = fulls if fulld is None else fulld if fulls == False: expr = "x 4096 - 56064 /" else: expr = "x 65536 /" g2l = "{expr} {k0} <= {expr} {phi} / {expr} {alpha} + 1 {alpha} + / log {gamma} * exp ?".format( expr=expr, k0=k0, phi=phi, alpha=alpha, gamma=gamma) if gcor != 1.0: g2l = "{g2l} 0 >= {g2l} log {gcor} * exp {g2l} ?".format(g2l=g2l, gcor=gcor) if sigmoid: g2l = build_sigmoid_expr(g2l, True, thr, cont) l2g = build_sigmoid_expr(expr, False, thr, cont) else: l2g = expr if gcor != 1.0: l2g = "{l2g} 0 >= {l2g} log {gcor} * exp {l2g} ?".format(l2g=l2g, gcor=gcor) l2g = "{l2g} {k0} {phi} / <= {l2g} {phi} * {l2g} log 1 {gamma} / * exp {alpha} 1 + * {alpha} - ?".format( l2g=l2g, k0=k0, phi=phi, alpha=alpha, gamma=gamma) if l2g_flag: expr = l2g else: expr = g2l if fulld == False: expr = expr + " 56064 * 4096 +" else: expr = expr + " 65536 *" clip = core.std.Expr([src], [expr]) return clip
def merge16_8(src1, src2, mask): core = vs.get_core() mask16 = core.fmtc.bitdepth(mask, bits=16, fulls=True, fulld=True) clip = core.std.MaskedMerge(src1, src2, mask16) return clip
def sigmoid_inverse(src, thr=0.5, cont=6.5): core = vs.get_core() expr = build_sigmoid_expr("x 65536 /", True, thr, cont) clip = core.std.Expr([src], [expr + " 65536 *"]) return clip
def setUp(self): self.core = vs.get_core() self.Lut = self.core.std.Lut self.Lut2 = self.core.std.Lut2 self.BlankClip = self.core.std.BlankClip self.mask = lambda val, bits: val & ((1 << bits) - 1)
def BalanceBorders(c, cTop, cBottom, cLeft, cRight, thresh=128, blur=999): funcname = "BalanceBorders" if not isinstance(c, vs.VideoNode): raise TypeError(funcname + ': This is not a clip.') if c.format.color_family != vs.YUV: raise TypeError(funcname + ': Clip must be YUV family.') if c.format.sample_type != vs.INTEGER: raise TypeError(funcname + ': Clip must be integer format.') if thresh < 0 or thresh > 128: raise ValueError(funcname + ': \"thresh\" must between 0 and 128.') if blur < 0: raise ValueError(funcname + ': \"blur\" must greater than 0.') del funcname core = vs.get_core() def BalanceTopBorder(c, cTop, thresh, blur): cWidth = c.width cHeight = c.height cTop = min(cTop, cHeight - 1) BlurWidth = max(4, math.floor(cWidth / blur)) C2 = core.resize.Point(c, cWidth << 1, cHeight << 1) C3 = core.std.CropRel( C2, 0, 0, cTop << 1, (cHeight - cTop - 1) << 1) #(cHeight * 2 - cTop * 2) - 2 C3 = core.resize.Point(C3, cWidth << 1, cTop << 1) C3 = core.resize.Bilinear(C3, BlurWidth << 1, cTop << 1) C3 = core.std.Convolution(C3, matrix=[0, 0, 0, 1, 1, 1, 0, 0, 0], planes=[0, 1, 2]) ReferenceBlur = core.resize.Bilinear(C3, cWidth << 1, cTop << 1) Original = core.std.CropRel( C2, 0, 0, 0, (cHeight - cTop) << 1) #cHeight * 2 - 0 - cTop * 2 C3 = core.resize.Bilinear(Original, BlurWidth << 1, cTop << 1) C3 = core.std.Convolution(C3, matrix=[0, 0, 0, 1, 1, 1, 0, 0, 0], planes=[0, 1, 2]) OriginalBlur = core.resize.Bilinear(C3, cWidth << 1, cTop << 1) del C3 Balanced = core.std.Expr(clips=[Original, OriginalBlur, ReferenceBlur], expr=["z y - x +", "z y - x +", "z y - x +"]) del OriginalBlur del ReferenceBlur Difference = core.std.MakeDiff(Balanced, Original, planes=[0, 1, 2]) del Balanced Tp = (128 + thresh) * ( (1 << c.format.bits_per_sample) - 1) * 0.004 # 1 / 255 = 0.004 Tm = (128 - thresh) * ((1 << c.format.bits_per_sample) - 1) * 0.004 expr = 'x {0} > {0} x ?'.format(Tp) Difference = core.std.Expr(clips=Difference, expr=[expr, expr, expr]) expr = 'x {0} < {0} x ?'.format(Tm) Difference = core.std.Expr(clips=Difference, expr=[expr, expr, expr]) del expr del Tp del Tm res = core.std.MergeDiff(Original, Difference, planes=[0, 1, 2]) del Difference res = core.std.StackVertical( clips=[res, core.std.CropRel(C2, 0, 0, cTop * 2, 0)]) #cHeight * 2 - cTop * 2 - (cHeight - cTop) * 2 = 0 return core.resize.Point(res, cWidth, cHeight) res = BalanceTopBorder( c, cTop, thresh, blur).std.Transpose().std.FlipHorizontal( ) if cTop > 0 else core.std.Transpose(c).std.FlipHorizontal() res = BalanceTopBorder( res, cLeft, thresh, blur).std.Transpose().std.FlipHorizontal( ) if cLeft > 0 else core.std.Transpose(res).std.FlipHorizontal() res = BalanceTopBorder( res, cBottom, thresh, blur).std.Transpose().std.FlipHorizontal( ) if cBottom > 0 else core.std.Transpose(res).std.FlipHorizontal() res = BalanceTopBorder( res, cRight, thresh, blur).std.Transpose().std.FlipHorizontal( ) if cRight > 0 else core.std.Transpose(res).std.FlipHorizontal() return res
def L0Smooth(clip, lamda=2e-2, kappa=2, color=True, **depth_args): """L0 Smooth in VapourSynth It is also known as "L0 Gradient Minimization". L0 smooth is a new image editing method, particularly effective for sharpening major edges by increasing the steepness of transitions while eliminating a manageable degree of low-amplitude structures. It is achieved in an unconventional optimization framework making use of L0 gradient minimization, which can globally control how many non-zero gradients are resulted to approximate prominent structures in a structure-sparsity-management manner. Unlike other edge-preserving smoothing approaches, this method does not depend on local features and globally locates important edges. It, as a fundamental tool, finds many applications and is particularly beneficial to edge extraction, clip-art JPEG artifact removal, and non-photorealistic image generation. All the internal calculations are done at 32-bit float. Args: clip: Input clip with no chroma subsampling. lamda: (float) Smoothing parameter controlling the degree of smooth. A large "lamda" makes the result have very few edges. Typically it is within the range [0.001, 0.1]. This parameter is renamed from "lambda" for better compatibility with Python. Default is 0.02. kappa: (float) Parameter that controls the convergence rate of alternating minimization algorithm. Small "kappa" results in more iteratioins and with sharper edges. kappa = 2 is suggested for natural images, which is a good balance between efficiency and performance. Default is 2. color: (bool) Whether to process data collaboratively. If true, the gradient magnitude in the model is defined as the sum of gradient magnitudes in the original color space. If false, channels in "clip" will be processed separately. Default is True. depth_args: (dict) Additional arguments passed to mvf.Depth() in the form of keyword arguments. Default is {}. Ref: [1] Xu, L., Lu, C., Xu, Y., & Jia, J. (2011, December). Image smoothing via L0 gradient minimization. In ACM Transactions on Graphics (TOG) (Vol. 30, No. 6, p. 174). ACM. [2] http://www.cse.cuhk.edu.hk/~leojia/projects/L0smoothing/index.html TODO: Optimize FFT using pyfftw library. """ funcName = 'L0Smooth' core = vs.get_core() if not isinstance(clip, vs.VideoNode) or any( (clip.format.subsampling_w, clip.format.subsampling_h)): raise TypeError( funcName + ': \"clip\" must be a clip with no chroma subsampling!') # Internal parameters bits = clip.format.bits_per_sample sampleType = clip.format.sample_type per_plane = not color or clip.format.num_planes == 1 # Convert to floating point clip = mvf.Depth(clip, depth=32, sample=vs.FLOAT, **depth_args) # Add padding for real Fast Fourier Transform if clip.width & 1: pad = True clip = core.std.AddBorders(clip, left=1) else: pad = False # Pre-calculate constant 2-D matrix size2D = (clip.height, clip.width) Denormin2 = L0Smooth_generate_denormin2(size2D) # Process clip = numpy_process(clip, functools.partial(L0Smooth_core, lamda=lamda, kappa=kappa, Denormin2=Denormin2, copy=True), per_plane=per_plane) # Crop the padding if pad: clip = core.std.CropRel(clip, left=1) # Convert the bit depth and sample type of output to the same as input clip = mvf.Depth(clip, depth=bits, sample=sampleType, **depth_args) return clip
def inputs(config, files, is_training=False, is_testing=False): # parameters channels = config.in_channels threads = config.threads threads_py = config.threads_py scaling = config.scaling if is_training: num_epochs = config.num_epochs data_format = config.data_format patch_height = config.patch_height patch_width = config.patch_width batch_size = config.batch_size if is_training: buffer_size = config.buffer_size epoch_size = len(files) # dataset mapping function def parse1_func(filename): # read data dtype = tf.float32 image = tf.read_file(filename) image = tf.image.decode_image(image, channels=channels) shape = tf.shape(image) height = shape[-3] width = shape[-2] # pre down-scale for high resolution image dscale = 1 if is_training and config.pre_down: ''' if (width >= 3072 and height >= 1536) or (width >= 1536 and height >= 3072): dscale = 3 elif (width >= 1024 and height >= 512) or (width >= 512 and height >= 1024): dscale = 2 ''' def c_t(const1, const2, true_fn, false_fn): return tf.cond(tf.logical_or( tf.logical_and( tf.greater_equal(width, const1), tf.greater_equal(height, const2) ), tf.logical_and( tf.greater_equal(width, const2), tf.greater_equal(height, const1) ) ), true_fn, false_fn) dscale = c_t(3072, 1536, lambda: 3, lambda: c_t(1024, 512, lambda: 2, lambda: 1) ) elif is_testing and config.pre_down: ''' if (width >= 3072 and height >= 3072): dscale = 4 elif (width >= 2048 and height >= 2048): dscale = 3 elif (width >= 1024 and height >= 1024): dscale = 2 ''' def c_t(const1, true_fn, false_fn): return tf.cond(tf.logical_and( tf.greater_equal(width, const1), tf.greater_equal(height, const1) ), true_fn, false_fn) dscale = c_t(3072, lambda: 4, lambda: c_t(2048, lambda: 3, lambda: c_t(1024, lambda: 2, lambda: 1) ) ) # padding cropped_height = patch_height * dscale cropped_width = patch_width * dscale ''' if cropped_height > height or cropped_width > width: pad_height = cropped_height - height pad_width = cropped_width - width if pad_height > 0: pad_height = [pad_height // 2, pad_height - pad_height // 2] height = cropped_height else: pad_height = [0, 0] if pad_width > 0: pad_width = [pad_width // 2, pad_width - pad_width // 2] width = cropped_width else: pad_width = [0, 0] block = tf.pad(image, [pad_height, pad_width, [0, 0]], mode='REFLECT') else: block = image ''' cond_height = tf.greater(cropped_height, height) cond_width = tf.greater(cropped_width, width) def c_f1(): def _1(): ph = cropped_height - height return [ph // 2, ph - ph // 2] pad_height = tf.cond(cond_height, _1, lambda: [0, 0]) def _2(): pw = cropped_width - width return [pw // 2, pw - pw // 2] pad_width = tf.cond(cond_width, _2, lambda: [0, 0]) return tf.pad(image, [pad_height, pad_width, [0, 0]], mode='REFLECT') block = tf.cond(tf.logical_or(cond_height, cond_width), c_f1, lambda: image) height = tf.maximum(cropped_height, height) width = tf.maximum(cropped_width, width) # cropping if is_training: block = tf.random_crop(block, [cropped_height, cropped_width, channels]) block = tf.image.random_flip_up_down(block) block = tf.image.random_flip_left_right(block) elif is_testing: offset_height = (height - cropped_height) // 2 offset_width = (width - cropped_width) // 2 block = tf.image.crop_to_bounding_box(block, offset_height, offset_width, cropped_height, cropped_width) # convert dtype block = tf.image.convert_image_dtype(block, dtype, saturate=False) # random color augmentation if is_training and config.color_augmentation > 0: block = tf.image.random_saturation(block, 1 - config.color_augmentation, 1 + config.color_augmentation) block = tf.image.random_brightness(block, config.color_augmentation) block = tf.image.random_contrast(block, 1 - config.color_augmentation, 1 + config.color_augmentation) # data format conversion block.set_shape([None, None, channels]) if data_format == 'NCHW': block = tf.transpose(block, (2, 0, 1)) # return return block # tf.py_func processing using vapoursynth, numpy, etc. import threading import vapoursynth as vs from scipy import ndimage def eval_random_select(n, clips): rand_idx = np.random.randint(0, len(clips)) return clips[rand_idx] def SigmoidInverse(clip, thr=0.5, cont=6.5, epsilon=1e-6): assert clip.format.sample_type == vs.FLOAT x0 = 1 / (1 + np.exp(cont * thr)) x1 = 1 / (1 + np.exp(cont * (thr - 1))) # thr - log(max(1 / max(x * (x1 - x0) + x0, epsilon) - 1, epsilon)) / cont expr = '{thr} 1 x {x1_x0} * {x0} + {epsilon} max / 1 - {epsilon} max log {cont_rec} * -'.format(thr=thr, cont_rec=1 / cont, epsilon=epsilon, x0=x0, x1_x0=x1 - x0) return clip.std.Expr(expr) def SigmoidDirect(clip, thr=0.5, cont=6.5): assert clip.format.sample_type == vs.FLOAT x0 = 1 / (1 + np.exp(cont * thr)) x1 = 1 / (1 + np.exp(cont * (thr - 1))) # (1 / (1 + exp(cont * (thr - x))) - x0) / (x1 - x0) expr = '1 1 {cont} {thr} x - * exp + / {x0} - {x1_x0_rec} *'.format(thr=thr, cont=cont, x0=x0, x1_x0_rec=1 / (x1 - x0)) return clip.std.Expr(expr) _lock = threading.Lock() _index_ref = [0] _src_ref = [None for _ in range(epoch_size)] core = vs.get_core(threads=1 if is_testing else threads_py) core.max_cache_size = 8000 _dscales = list(range(1, 5)) if config.pre_down else [1] _src_blk = [core.std.BlankClip(None, patch_width * s, patch_height * s, format=vs.RGBS, length=epoch_size) for s in _dscales] _dst_blk = core.std.BlankClip(None, patch_width // scaling, patch_height // scaling, format=vs.RGBS, length=epoch_size) def src_frame_func(n, f): f_out = f.copy() planes = f_out.format.num_planes # output for p in range(planes): f_arr = np.array(f_out.get_write_array(p), copy=False) np.copyto(f_arr, _src_ref[n][p, :, :] if data_format == 'NCHW' else _src_ref[n][:, :, p]) # set frame properties f_out.props['_Primaries'] = 1 # BT.709 f_out.props['_Transfer'] = 1 # BT.709 return f_out _srcs = [s.std.ModifyFrame(s, src_frame_func) for s in _src_blk] _srcs_linear = [s.resize.Bicubic(transfer_s='linear') for s in _srcs] def src_down_func(clip): dw = patch_width dh = patch_height if clip.width != dw or clip.height != dh: clip = SigmoidInverse(clip) clip = clip.resize.Bicubic(dw, dh, filter_param_a=0, filter_param_b=0.5) clip = SigmoidDirect(clip) return clip if config.pre_down: _srcs_linear = [src_down_func(s) for s in _srcs_linear] _srcs = _srcs[0:1] + [s.resize.Bicubic(transfer_s='709') for s in _srcs_linear[1:]] def src_select_eval(n): # select source shape = _src_ref[n].shape sh = shape[-2 if data_format == 'NCHW' else -3] dscale = sh // patch_height # downscale if needed clip = _srcs[dscale - 1] return clip if config.pre_down: _src = _src_blk[0].std.FrameEval(src_select_eval) else: _src = _srcs[0] def resize_set_func(clip, convert_linear=False): # disable resize set when scaling=1 if scaling == 1: return clip # parameters dw = int(patch_width / scaling + 0.5) dh = int(patch_height / scaling + 0.5) rets = {} # resizers rets['bilinear'] = clip.resize.Bilinear(dw, dh) rets['spline16'] = clip.resize.Spline16(dw, dh) rets['spline36'] = clip.resize.Spline36(dw, dh) for taps in range(2, 12): rets['lanczos{}'.format(taps)] = clip.resize.Lanczos(dw, dh, filter_param_a=taps) # linear to gamma if convert_linear: for key in rets: rets[key] = rets[key].resize.Bicubic(transfer_s='709', transfer_in_s='linear') return rets def resize_eval(n, src, src_linear, resizes, linear_resizes, dscale=None): # select source if dscale is True: shape = _src_ref[n].shape sh = shape[-2 if data_format == 'NCHW' else -3] dscale = max(1, sh // patch_height) if dscale: src = src[dscale - 1] src_linear = src_linear[dscale - 1] resizes = resizes[dscale - 1] linear_resizes = linear_resizes[dscale - 1] # initialize clip = src # multiple stages max_iter = config.multistage_resize * 2 if scaling != 1: max_iter += 1 for _ in range(max_iter): downscale = _ % 2 == 0 # randomly skip multistage resize scaling_match = _ % 2 == 0 if scaling == 1 else _ % 2 == 1 # whether the last scaling matches output size if _ > 0 and scaling_match and np.random.uniform(0, 1) < 0.7: break # scaling size if scaling == 1: scaling1 = 1 while scaling1 < 4 / 3: # [4 / 3, ~2) scaling1 = 2 ** np.random.normal(0.6, 0.2) else: scaling1 = scaling dw = int(patch_width / scaling1 + 0.5) if downscale else patch_width dh = int(patch_height / scaling1 + 0.5) if downscale else patch_height use_resize_set = scaling != 1 and _ == 0 # random number generator rand_val = np.random.uniform(-1, 1) if config.random_resizer == 0 else config.random_resizer abs_rand = np.abs(rand_val) # random gamma-to-linear if _ == 0: clip = src_linear if rand_val < 0 else src resizes = linear_resizes if rand_val < 0 else resizes # random resizers if abs_rand < (0.05 if downscale else 0.05): clip = resizes['bilinear'] if use_resize_set else clip.resize.Bilinear(dw, dh) elif abs_rand < (0.10 if downscale else 0.10): clip = resizes['spline16'] if use_resize_set else clip.resize.Spline16(dw, dh) elif abs_rand < (0.15 if downscale else 0.15): clip = resizes['spline36'] if use_resize_set else clip.resize.Spline36(dw, dh) elif abs_rand < (0.25 if downscale else 0.40): # Lanczos taps=[2, 12) taps = int(np.clip(np.random.exponential(2) + 2, 2, 11)) clip = resizes['lanczos{}'.format(taps)] if use_resize_set else clip.resize.Lanczos(dw, dh, filter_param_a=taps) elif abs_rand < (0.50 if downscale else 0.50): # Catmull-Rom b = 0 if config.random_resizer == 0.4 else np.random.normal(0, 1/6) c = (1 - b) * 0.5 clip = clip.resize.Bicubic(dw, dh, filter_param_a=b, filter_param_b=c) elif abs_rand < (0.60 if downscale else 0.60): # Mitchell-Netravali (standard Bicubic) b = 1/3 if config.random_resizer == 0.6 else np.random.normal(1/3, 1/6) c = (1 - b) * 0.5 clip = clip.resize.Bicubic(dw, dh, filter_param_a=b, filter_param_b=c) elif abs_rand < (0.80 if downscale else 0.70): # sharp Bicubic b = -0.5 if config.random_resizer == 0.7 else np.random.normal(-0.5, 0.25) c = b * -0.5 clip = clip.resize.Bicubic(dw, dh, filter_param_a=b, filter_param_b=c) elif abs_rand < (0.85 if downscale else 0.80): # soft Bicubic b = 0.75 if config.random_resizer == 0.8 else np.random.normal(0.75, 0.25) c = 1 - b clip = clip.resize.Bicubic(dw, dh, filter_param_a=b, filter_param_b=c) elif abs_rand < (1.00 if downscale else 0.90): # arbitrary Bicubic b = np.random.normal(0, 0.5) c = np.random.normal(0.25, 0.25) clip = clip.resize.Bicubic(dw, dh, filter_param_a=b, filter_param_b=c) elif abs_rand < (1.00 if downscale else 1.00): # Bicubic with haloing & aliasing b = np.random.normal(0, 1) # amount of haloing c = -1 # when c is around b * 0.8, aliasing is minimum if b >= 0: # with aliasing b = 1 + b while c < 0 or c > b * 1.2: c = np.random.normal(b * 0.4, b * 0.2) else: # without aliasing b = 1 - b while c < 0 or c > b * 1.2: c = np.random.normal(b * 0.8, b * 0.2) b = -b clip = clip.resize.Bicubic(dw, dh, filter_param_a=b, filter_param_b=c) # return return clip _resizes = [resize_set_func(s, convert_linear=False) for s in _srcs] _linear_resizes = [resize_set_func(s, convert_linear=config.multistage_resize == 0) for s in _srcs_linear] _dst = _dst_blk.std.FrameEval(lambda n: resize_eval(n, _srcs, _srcs_linear, _resizes, _linear_resizes, dscale=True)) _dst = _dst.resize.Bicubic(transfer_s='709') # convert to BT.709 transfer # chroma subsampling def chroma_subsampling(src): YUV420PS = core.register_format(vs.YUV, vs.FLOAT, 32, 1, 1) src420 = src.resize.Bicubic(format=YUV420PS, matrix_s='709', filter_param_a=0, filter_param_b=0.5) clips = [src420.resize.Bilinear(format=vs.RGBS, matrix_in_s='709'), src420.resize.Bicubic(format=vs.RGBS, matrix_in_s='709', filter_param_a=1.0, filter_param_b=0.0), src420.resize.Bicubic(format=vs.RGBS, matrix_in_s='709', filter_param_a=0.5, filter_param_b=0.5), src420.resize.Bicubic(format=vs.RGBS, matrix_in_s='709', filter_param_a=1 / 3, filter_param_b=1 / 3), src420.resize.Bicubic(format=vs.RGBS, matrix_in_s='709', filter_param_a=0, filter_param_b=0.5), src420.resize.Bicubic(format=vs.RGBS, matrix_in_s='709', filter_param_a=-0.5, filter_param_b=0.25), src420.resize.Bicubic(format=vs.RGBS, matrix_in_s='709', filter_param_a=-1, filter_param_b=0.3), src420.resize.Bicubic(format=vs.RGBS, matrix_in_s='709', filter_param_a=-1, filter_param_b=0.8), src420.resize.Bicubic(format=vs.RGBS, matrix_in_s='709', filter_param_a=-2, filter_param_b=0.6), src420.resize.Bicubic(format=vs.RGBS, matrix_in_s='709', filter_param_a=-2, filter_param_b=1.6)] clips += [src] * 6 clip = src.std.FrameEval(lambda n: eval_random_select(n, clips)) return clip _dst = chroma_subsampling(_dst) # parser def parse2_pyfunc(label): channel_index = -3 if data_format == 'NCHW' else -1 dscale = label.shape[-2 if data_format == 'NCHW' else -3] // patch_height # safely acquire and increase shared index _lock.acquire() index = _index_ref[0] _index_ref[0] = (index + 1) % epoch_size _lock.release() # processing using vs _src_ref[index] = label if config.pre_down and dscale > 1: f_src = _src.get_frame(index) f_dst = _dst.get_frame(index) _src_ref[index] = None # vs.VideoFrame to np.ndarray if config.pre_down and dscale > 1: label = [] planes = f_src.format.num_planes for p in range(planes): f_arr = np.array(f_src.get_read_array(p), copy=False) label.append(f_arr) label = np.stack(label, axis=channel_index) data = [] planes = f_dst.format.num_planes for p in range(planes): f_arr = np.array(f_dst.get_read_array(p), copy=False) data.append(f_arr) data = np.stack(data, axis=channel_index) # add Gaussian noise of random scale and random spatial correlation def _add_noise(data, noise_scale, noise_corr): # noise spatial correlation def noise_correlation(noise, corr): if corr > 0: sigma = np.random.normal(corr, corr) if sigma > 0.25: sigma = [0, sigma, sigma] if data_format == 'NCHW' else [sigma, sigma, 0] noise = ndimage.gaussian_filter(noise, sigma, truncate=2.0) return noise if noise_scale <= 0: return data rand_val = np.random.uniform(0, 1) scale = np.random.exponential(noise_scale) if rand_val < 0.2 or scale < 0.002: # won't add noise return data noise_shape = list(data.shape) if rand_val < 0.35: # RGB noise noise = np.random.normal(0.0, scale, noise_shape).astype(np.float32) noise = noise_correlation(noise, noise_corr) else: # Y/YUV noise noise_shape[channel_index] = 1 noise_y = np.random.normal(0.0, scale, noise_shape).astype(np.float32) noise_y = noise_correlation(noise_y, noise_corr) scale_uv = np.random.exponential(noise_scale / 2) if rand_val < 0.55 and scale_uv > 0.002: # YUV noise noise_u = np.random.normal(0.0, scale_uv, noise_shape).astype(np.float32) noise_u = noise_correlation(noise_u, noise_corr * 1.5) noise_v = np.random.normal(0.0, scale_uv, noise_shape).astype(np.float32) noise_v = noise_correlation(noise_v, noise_corr * 1.5) rand_val2 = np.random.uniform(0, 1) if rand_val2 < 0.3: # Rec.601 Kr = 0.299 Kg = 0.587 Kb = 0.114 elif rand_val2 < 0.9: # Rec.709 Kr = 0.2126 Kg = 0.7152 Kb = 0.0722 else: # Rec.2020 Kr = 0.2627 Kg = 0.6780 Kb = 0.0593 noise_r = noise_y + ((1 - Kr) / 2) * noise_v noise_b = noise_y + ((1 - Kb) / 2) * noise_u noise_g = (1 / Kg) * noise_y - (Kr / Kg) * noise_r - (Kb / Kg) * noise_b noise = [noise_r, noise_g, noise_b] else: noise = [noise_y, noise_y, noise_y] noise = np.concatenate(noise, axis=channel_index) # adding noise return data + noise data = _add_noise(data, config.noise_scale, config.noise_corr) # return return data, label def parse3_func(data, label): # final process data = tf.clip_by_value(data, 0.0, 1.0) label = tf.clip_by_value(label, 0.0, 1.0) # JPEG encoding def _jpeg_coding(data, quality_step, random_seed=None): if quality_step <= 0: return data steps = 16 prob_step = 0.02 rand_val = tf.random_uniform([], -1, 1, seed=random_seed) abs_rand = tf.abs(rand_val) def c_f1(data): if data_format == 'NCHW': data = tf.transpose(data, (1, 2, 0)) data = tf.image.convert_image_dtype(data, tf.uint8, saturate=True) def _f1(quality, chroma_ds): quality = int(quality + 0.5) return tf.image.encode_jpeg(data, quality=quality, chroma_downsampling=chroma_ds) def _cond_recur(abs_rand, count=15, chroma_ds=False, prob=0.0, quality=100.0): prob += prob_step if count <= 0: return _f1(quality, chroma_ds) else: return tf.cond(abs_rand < prob, lambda: _f1(quality, chroma_ds), lambda: _cond_recur(abs_rand, count - 1, chroma_ds, prob, quality - config.jpeg_coding)) data = tf.cond(rand_val < 0, lambda: _cond_recur(abs_rand, steps - 1, True), lambda: _cond_recur(abs_rand, steps - 1, False)) data = tf.image.decode_jpeg(data) data = tf.image.convert_image_dtype(data, tf.float32, saturate=False) if data_format == 'NCHW': data = tf.transpose(data, (2, 0, 1)) return data return tf.cond(rand_val < prob_step * steps, lambda: c_f1(data), lambda: data) data = _jpeg_coding(data, config.jpeg_coding, config.random_seed if is_testing else None) # return return data, label # Dataset API dataset = tf.data.Dataset.from_tensor_slices((files)) if is_training and buffer_size > 0: dataset = dataset.shuffle(buffer_size) dataset = dataset.map(parse1_func, num_parallel_calls=1 if is_testing else threads) dataset = dataset.map(lambda label: tuple(tf.py_func(parse2_pyfunc, [label], [tf.float32, tf.float32])), num_parallel_calls=1 if is_testing else threads_py) dataset = dataset.map(parse3_func, num_parallel_calls=1 if is_testing else threads) dataset = dataset.batch(batch_size) dataset = dataset.repeat(num_epochs if is_training else None) dataset = dataset.prefetch(64) # return iterator iterator = dataset.make_one_shot_iterator() next_data, next_label = iterator.get_next() # data shape declaration data_shape = [None] * 4 data_shape[-3 if data_format == 'NCHW' else -1] = channels next_data.set_shape(data_shape) next_label.set_shape(data_shape) return next_data, next_label
def sharpen(clip, mode=1, sstr=2.0, cstr=None, xstr=0.19, lstr=1.49, pstr=1.272, ldmp=None, use_lut=True): """Small and relatively fast realtime-sharpening function, for 1080p, or after scaling 720p -> 1080p during playback (to make 720p look more like being 1080p) It's a generic sharpener. Only for good quality sources! (If the source is crap, FineSharp will happily sharpen the crap.) ;) Noise/grain will be enhanced, too. The method is GENERIC. Modus operandi: A basic nonlinear sharpening method is performed, then the *blurred* sharp-difference gets subtracted again. Args: clip (clip): vs.YUV or vs.GRAY video. mode (int): 1 to 3, weakest to strongest. When negative -1 to -3, a broader kernel for equalisation is used. sstr (float): strength of sharpening, 0.0 up to ?? cstr (float): strength of equalisation, 0.0 to ? 2.0 ? (recomm. 0.5 to 1.25, default AUTO) xstr (float): strength of XSharpen-style final sharpening, 0.0 to 1.0 (but, better don't go beyond 0.249 ...) lstr (float): modifier for non-linear sharpening pstr (float): exponent for non-linear sharpening ldmp (float): "low damp", to not overenhance very small differences (noise coming out of flat areas, default sstr+1) Example: .. code-block:: python ... import finesharp ... clip = finesharp.sharpen(clip) ... """ core = vs.get_core() bd = clip.format.bits_per_sample max_ = 2 ** bd - 1 mid = (max_ + 1) // 2 scl = (max_ + 1) // 256 x = 'x {} /'.format(scl) y = 'y {} /'.format(scl) src = clip if core.version_number() < 33: raise EnvironmentError('VapourSynth version should be 33 or greater.') if src.format.color_family != vs.YUV and src.format.color_family != vs.GRAY: raise ValueError('clip must be YUV or GRAY color family.') if bd < 8 or bd > 16: raise ValueError('clip must be 8..16 bits.') mode = int(mode) if abs(mode) > 3 or mode == 0: raise ValueError('mode must be 1, 2, 3, -1, -2 or -3.') sstr = float(sstr) if sstr < 0.0: raise ValueError('sstr must be larger than zero.') if src.format.color_family != vs.GRAY: clip = core.std.ShufflePlanes(clips=clip, planes=0, colorfamily=vs.GRAY) if cstr is None: cstr = spline(sstr, {0: 0, 0.5: 0.1, 1: 0.6, 2: 0.9, 2.5: 1, 3: 1.09, 3.5: 1.15, 4: 1.19, 8: 1.249, 255: 1.5}) if mode > 0: cstr **= 0.8 cstr = float(cstr) xstr = float(xstr) if xstr < 0.0: raise ValueError('xstr must be larger than zero.') lstr = float(lstr) pstr = float(pstr) if ldmp is None: ldmp = sstr + 0.1 ldmp = float(ldmp) rg = 20 - (mode > 0) * 9 if sstr < 0.01 and cstr < 0.01 and xstr < 0.01: return src if abs(mode) == 1: c2 = core.std.Convolution(clip, matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1]).std.Median() else: c2 = core.std.Median(clip).std.Convolution(matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1]) if abs(mode) == 3: c2 = core.std.Median(clip) if bd in [8, 9, 10] and use_lut is True: def expr(x, y): d = x - y absd = abs(d) e0 = ((absd / lstr) ** (1 / pstr)) * sstr e1 = d / (absd + 0.001) e2 = (d * d) / (d * d + ldmp) return clamp(e0 * e1 * e2 + mid, max_) diff = core.std.Lut2(clipa=clip, clipb=c2, function=expr) else: expr = '{x} {y} - abs {lstr} / log 1 {pstr} / * exp ' \ '{sstr} * {x} {y} - {x} {y} - abs 0.001 + / * {x} {y} - log 2 * exp ' \ '{x} {y} - log 2 * exp {ldmp} + / * 128 + {scl} *' expr = expr.format(x=x, y=y, lstr=lstr, pstr=pstr, sstr=sstr, ldmp=ldmp, scl=scl) diff = core.std.Expr(clips=[clip, c2], expr=expr) shrp = clip if sstr >= 0.01: shrp = core.std.MergeDiff(clipa=shrp, clipb=diff) if cstr >= 0.01: expr = 'x {mid} - {cstr} * {mid} +'.format(mid=mid, cstr=cstr) diff = core.std.Expr(clips=diff, expr=expr) diff = core.rgvs.RemoveGrain(clip=diff, mode=[rg]) shrp = core.std.MakeDiff(clipa=shrp, clipb=diff) if xstr >= 0.01: expr = 'x x y - 9.9 * +' xyshrp = core.std.Expr(clips=[shrp, core.std.Convolution(shrp, matrix=[1, 1, 1, 1, 1, 1, 1, 1, 1])], expr=expr) rpshrp = core.rgvs.Repair(clip=xyshrp, repairclip=shrp, mode=[12]) shrp = core.std.Merge(clipa=rpshrp, clipb=shrp, weight=[1 - xstr]) if src.format.color_family != vs.GRAY: shrp = core.std.ShufflePlanes(clips=[shrp, src], planes=[0, 1, 2], colorfamily=src.format.color_family) return shrp
def L0GradientProjection(clip, alpha=0.08, precision=255, epsilon=0.0002, maxiter=5000, gamma=3, eta=0.95, color=True, **depth_args): """L0 Gradient Projection in VapourSynth L0 gradient projection is a new edge-preserving filtering method based on the L0 gradient. In contrast to the L0 gradient minimization, L0 gradient projection framework is intuitive because one can directly impose a desired L0 gradient value on the output image. The constrained optimization problem is minimizing the quadratic data-fidelity subject to the hard constraint that the L0 gradient is less than a user-given parameter "alpha". The solution is based on alternating direction method of multipliers (ADMM), while the hard constraint is handled by projection onto the mixed L1,0 pseudo-norm ball with variable splitting, and the computational complexity is O(NlogN). However, current implementation here is extremely slow. In my experiment, the number of iteration of this algorithm is far more than L0Smooth. All the internal calculations are done at 32-bit float. Args: clip: Input clip with no chroma subsampling. alpha: (float) L0 gradient of output in percentage form, i.e. the range is [0, 1]. It can be seen as the degree of flatness in the output. Default is 0.08. precision: (float) Precision of the calculation of L0 gradient. The larger the value, the more accurate the calculation. Default is 255. epsilon: (float) Stopping criterion in percentage form, i.e. the range is [0, 1]. It determines the allowable error from alpha. Default is 0.0002. maxiter: (int) Maximum number of iterations. Default is 5000. gamma: (int) Step size of ADMM. Default is 3. eta: (int) Controling gamma for nonconvex optimization. It stabilizes ADMM for nonconvex optimization. According to recent convergence analyses of ADMM for nonconvex cases, under appropriate conditions, the sequence generated by ADMM converges to a stationary point with sufficiently small gamma. Default is 0.95. depth_args: (dict) Additional arguments passed to mvf.Depth() in the form of keyword arguments. Default is {}. Ref: [1] Ono, S. (2017). $ L_ {0} $ Gradient Projection. IEEE Transactions on Image Processing, 26(4), 1554-1564. [2] Ono, S. (2017, March). Edge-preserving filtering by projection onto L 0 gradient constraint. In Acoustics, Speech and Signal Processing (ICASSP), 2017 IEEE International Conference on (pp. 1492-1496). IEEE. [3] https://sites.google.com/site/thunsukeono/publications TODO: Optimize FFT using pyfftw library. """ funcName = 'L0GradientProjection' core = vs.get_core() if not isinstance(clip, vs.VideoNode) or any( (clip.format.subsampling_w, clip.format.subsampling_h)): raise TypeError( funcName + ': \"clip\" must be a clip with no chroma subsampling!') # Internal parameters bits = clip.format.bits_per_sample sampleType = clip.format.sample_type per_plane = not color or clip.format.num_planes == 1 # Convert to floating point clip = mvf.Depth(clip, depth=32, sample=vs.FLOAT, **depth_args) # Add padding for real Fast Fourier Transform if clip.width & 1: pad = True clip = core.std.AddBorders(clip, left=1) else: pad = False # Pre-calculate constant 2-D matrix size2D = (clip.height, clip.width) Lap = L0GradProj_generate_lap(size2D) # Process clip = numpy_process(clip, functools.partial(L0GradProj_core, alpha=alpha, precision=precision, epsilon=epsilon, maxiter=maxiter, gamma=gamma, eta=eta, Lap=Lap, copy=True), per_plane=per_plane) # Crop the padding if pad: clip = core.std.CropRel(clip, left=1) # Convert the bit depth and sample type of output to the same as input clip = mvf.Depth(clip, depth=bits, sample=sampleType, **depth_args) return clip
def setUp(self): self.core = vs.get_core()
def __init__(self): self.core = vs.get_core()
def correct_edi_shift(clip, rfactor, plugin): import vapoursynth as vs core = vs.get_core() if clip.format.subsampling_w == 1: hshift = -rfactor / 2 + 0.5 # hshift(steps+1)=2*hshift(steps)-0.5 else: hshift = -0.5 if plugin == "zimg": if clip.format.subsampling_h == 0: clip = core.resize.Spline36(clip=clip, width=clip.width, height=clip.height, src_left=hshift, src_top=-0.5) else: Y = core.std.ShufflePlanes(clips=clip, planes=0, colorfamily=vs.GRAY) U = core.std.ShufflePlanes(clips=clip, planes=1, colorfamily=vs.GRAY) V = core.std.ShufflePlanes(clips=clip, planes=2, colorfamily=vs.GRAY) Y = core.resize.Spline36(clip=Y, width=clip.width, height=clip.height, src_left=hshift, src_top=-0.5) U = core.resize.Spline36(clip=U, width=clip.width, height=clip.height, src_left=hshift / 2, src_top=-0.5) V = core.resize.Spline36(clip=V, width=clip.width, height=clip.height, src_left=hshift / 2, src_top=-0.5) clip = core.std.ShufflePlanes(clips=[Y, U, V], planes=[0, 0, 0], colorfamily=vs.YUV) if plugin == "fmtconv": bits = clip.format.bits_per_sample if clip.format.subsampling_h == 0: clip = core.fmtc.resample(clip=clip, sx=hshift, sy=-0.5) else: clip = core.fmtc.resample(clip=clip, sx=hshift, sy=-0.5, planes=[3, 2, 2]) clip = core.fmtc.resample(clip=clip, sx=hshift, sy=-1, planes=[2, 3, 3]) if bits != 16: clip = core.fmtc.bitdepth(clip=clip, bits=bits) return clip
def mask_fadetxt(clip, lthr=225, cthr=(2, 2), expand=2, fade_num=(5, 5), apply_range=None): core = vs.get_core() if clip.format.color_family != vs.YUV: raise TypeError(MODULE_NAME + ': fadetxt mask: only yuv clips are supported.') w = clip.width h = clip.height bps = clip.format.bits_per_sample ceil = (1 << bps) - 1 neutral = 1 << (bps - 1) frame_count = clip.num_frames yuv = [ core.std.ShufflePlanes(clip, i, vs.GRAY) for i in range(clip.format.num_planes) ] try: yuv444 = [ core.resize.Bicubic(plane, w, h, src_left=0.25) if yuv.index(plane) > 0 else plane for plane in yuv ] except vs.Error: yuv444 = [ mvf.Depth(core.fmtc.resample(plane, w, h, sx=0.25), 8) if yuv.index(plane) > 0 else plane for plane in yuv ] cthr_u = cthr if not isinstance(cthr, (list, tuple)) else cthr[0] cthr_v = cthr if not isinstance(cthr, (list, tuple)) else cthr[1] expr = 'x %d > y %d - abs %d < and z %d - abs %d < and %d 0 ?' % ( lthr, neutral, cthr_u, neutral, cthr_v, ceil) mask = core.std.Expr(yuv444, expr) mask = [mask] + [core.std.Maximum] * expand mask = functools.reduce(lambda x, y: y(x), mask) if fade_num is not 0: def shift_backward(n, mask_clip, num): return mask_clip[frame_count - 1] if n + num > frame_count - 1 else mask_clip[ n + num] def shift_forward(n, mask_clip, num): return mask_clip[0] if n - num < 0 else mask_clip[n - num] fade_in_num = fade_num if not isinstance(fade_num, (list, tuple)) else fade_num[0] fade_out_num = fade_num if not isinstance(fade_num, (list, tuple)) else fade_num[1] fade_in = core.std.FrameEval( mask, functools.partial(shift_backward, mask_clip=mask, num=fade_in_num)) fade_out = core.std.FrameEval( mask, functools.partial(shift_forward, mask_clip=mask, num=fade_out_num)) mask = core.std.Expr([mask, fade_in, fade_out], 'x y max z max') if apply_range is not None and isinstance(apply_range, (list, tuple)): try: blank = core.std.BlankClip(mask) if 0 in apply_range: mask = mask[apply_range[0]:apply_range[1]] + blank[ apply_range[1]:] elif frame_count in apply_range: mask = blank[0:apply_range[0]] + mask[ apply_range[0]:apply_range[1]] else: mask = blank[0:apply_range[0]] + mask[ apply_range[0]:apply_range[1]] + blank[apply_range[1]:] except vs.Error: raise ValueError( MODULE_NAME + ': incorrect apply range setting. Possibly end less than start' ) except IndexError: raise ValueError( MODULE_NAME + ': incorrect apply range setting. ' 'Apply range must be a tuple/list with 2 elements') return mask
def Resize16nr(src, w=None, h=None, sx=0, sy=0, sw=0, sh=0, kernel="spline36", kernelh=None, kernelv=None, fh=1, fv=1, taps=4, a1=None, a2=None, a3=None, kovrspl=1, cnorm=True, center=True, fulls=None, fulld=None, cplace="mpeg2", invks=False, invkstaps=4, noring=True): core = vs.get_core() w = src.width if w is None else w h = src.height if h is None else h kernelh = kernel if kernelh is None else kernelh kernelv = kernel if kernelv is None else kernelv sr_h = float(w / src.width) sr_v = float(h / src.height) sr_up = max(sr_h, sr_v) sr_dw = 1.0 / min(sr_h, sr_v) sr = max(sr_up, sr_dw) thr = 2.5 nrb = (sr > thr) nrf = (sr < thr + 1.0 and noring) nrr = min(sr - thr, 1.0) if nrb else 1.0 nrv = [ round((1.0 - nrr) * 65535), round((1.0 - nrr) * 65535), round((1.0 - nrr) * 65535) ] if nrb else [0, 0, 0] nrm = core.std.BlankClip(clip=src, width=w, height=h, color=nrv) if nrb and nrf else 0 main = core.fmtc.resample(src, w=w, h=h, sx=sx, sy=sy, sw=sw, sh=sh, kernel=kernel, kernelh=kernelh, kernelv=kernelv, fh=fh, fv=fv, taps=taps, a1=a1, a2=a2, a3=a3, kovrspl=kovrspl, cnorm=cnorm, center=center, fulls=fulls, fulld=fulld, cplace=cplace, invks=invks, invkstaps=invkstaps) nrng = core.fmtc.resample(src, w=w, h=h, sx=sx, sy=sy, sw=sw, sh=sh, kernel="gauss", a1=100, center=center, fulls=fulls, fulld=fulld, cplace=cplace) if nrf else main clip = core.rgvs.Repair(main, nrng, 1) if nrf else main clip = core.std.MaskedMerge(main, clip, nrm) if nrf and nrb else clip return clip
def Denoise2(src, denoise=400, blur=None, lsb=True, truemotion=True, chroma=True, fast=False, blksize=None, prefix=None, recalculate=None, thSAD=None): core = vs.get_core() if fast: if blksize is None: blksize = 32 overlap = int(blksize / 4) else: if blksize is None: blksize = 8 overlap = int(blksize / 2) if recalculate is None: recalculate = blksize if thSAD is None: thSAD = int(denoise * 1.25) pad = blksize + overlap src = core.fmtc.resample(src, src.width + pad, src.height + pad, sw=src.width + pad, sh=src.height + pad, kernel="point") src16 = Up16(src, lsb) super = core.mv.Super(src16, chroma=chroma) if prefix is not None: exist = os.path.exists(prefix + ".vec") and os.path.exists(prefix + ".len") create = not exist else: exist = False create = False if not exist or (blksize > recalculate): if blur is not None: blurred = core.generic.GBlur(src, blur) blurred = Up16(blurred, lsb) else: blurred = src16 rep = has.DitherLumaRebuild(blurred, s0=1, chroma=chroma) superRep = core.mv.Super(rep, chroma=chroma) if not exist: bvec2 = core.mv.Analyse(superRep, isb=True, delta=2, blksize=blksize, overlap=overlap, truemotion=truemotion, chroma=chroma) bvec1 = core.mv.Analyse(superRep, isb=True, delta=1, blksize=blksize, overlap=overlap, truemotion=truemotion, chroma=chroma) fvec1 = core.mv.Analyse(superRep, isb=False, delta=1, blksize=blksize, overlap=overlap, truemotion=truemotion, chroma=chroma) fvec2 = core.mv.Analyse(superRep, isb=False, delta=2, blksize=blksize, overlap=overlap, truemotion=truemotion, chroma=chroma) if create: return WriteVecs([bvec1, bvec2, fvec1, fvec2], prefix) else: bvec1 = ReadVecs(0, prefix, 4) bvec2 = ReadVecs(1, prefix, 4) fvec1 = ReadVecs(2, prefix, 4) fvec2 = ReadVecs(3, prefix, 4) if blksize > recalculate and exist: bvec1 = core.std.Splice( [core.std.BlankClip(bvec1, width=1, length=1), bvec1], mismatch=True).std.Trim(1) bvec2 = core.std.Splice( [core.std.BlankClip(bvec2, width=1, length=1), bvec2], mismatch=True).std.Trim(1) fvec1 = core.std.Splice( [core.std.BlankClip(fvec1, width=1, length=1), fvec1], mismatch=True).std.Trim(1) fvec2 = core.std.Splice( [core.std.BlankClip(fvec2, width=1, length=1), fvec2], mismatch=True).std.Trim(1) while blksize > recalculate: blksize = int(blksize / 2) if fast: overlap = int(overlap / 4) else: overlap = int(overlap / 2) bvec1 = core.mv.Recalculate(superRep, bvec1, thSAD, blksize=blksize, chroma=chroma, truemotion=truemotion, overlap=overlap) bvec2 = core.mv.Recalculate(superRep, bvec2, thSAD, blksize=blksize, chroma=chroma, truemotion=truemotion, overlap=overlap) fvec1 = core.mv.Recalculate(superRep, fvec1, thSAD, blksize=blksize, chroma=chroma, truemotion=truemotion, overlap=overlap) fvec2 = core.mv.Recalculate(superRep, fvec2, thSAD, blksize=blksize, chroma=chroma, truemotion=truemotion, overlap=overlap) fin = core.mv.Degrain2(src16, super, bvec1, fvec1, bvec2, fvec2, denoise, plane=4 if chroma else 0) fin = core.std.CropRel(fin, 0, pad, 0, pad) return fin
def min_dif16(src1, src2, ref): core = vs.get_core() clip = core.std.Expr([src1, src2, ref], ["x z - abs y z - abs > y x ?"]) return clip
def mask_msharpen(mthr, **kwargs): core = vs.get_core() mthr /= 5 return lambda clip: core.msmoosh.MSharpen( clip, threshold=mthr, strength=0, mask=True)
import vapoursynth as vs import os import sys core = vs.get_core(threads=15) core.std.LoadPlugin(ffms2) core.std.LoadPlugin(svpflow1) core.std.LoadPlugin(svpflow2) clip = core.ffms2.Source(source=file) clip = clip.resize.Bicubic(format=vs.YUV420P8) if gpu == '1': super_params = "{scale:{up:0},gpu:1,pel:1,full:false}" else: super_params = "{scale:{up:0},gpu:0,pel:1,full:false}" analyse_params = "{block:{w:32,h:32},main:{search:{coarse:{type:2,distance:-5,bad:{range:0}},type:3,distance:-3},penalty:{pnbour:65},levels:4},refine:[{search:{distance:1}}]}" smoothfps_params = "{rate:{num:5,den:2},algo:23,mask:{cover:80},scene:{mode:0,limits:{scene:3000,blocks:40}}}" super = core.svp1.Super(clip, super_params) vectors = core.svp1.Analyse(super["clip"], super["data"], clip, analyse_params) smooth = core.svp2.SmoothFps(clip, super["clip"], super["data"], vectors["clip"], vectors["data"], smoothfps_params) smooth = core.std.AssumeFPS(smooth, fpsnum=smooth.fps_num, fpsden=smooth.fps_den) smooth.set_output()
def TAAmbk(clip, aatype=1, aatypeu=None, aatypev=None, preaa=0, strength=0.0, cycle=0, mtype=None, mclip=None, mthr=None, mlthresh=None, mpand=(0, 0), txtmask=0, txtfade=0, thin=0, dark=0.0, sharp=0, aarepair=0, postaa=None, src=None, stabilize=0, down8=True, showmask=0, opencl=False, opencl_device=-1, **kwargs): core = vs.get_core() aatypeu = aatype if aatypeu is None else aatypeu aatypev = aatype if aatypev is None else aatypev if mtype is None: mtype = 0 if preaa == 0 and True not in (aatype, aatypeu, aatypev) else 1 if postaa is None: postaa = True if abs(sharp) > 70 or (0.4 < abs(sharp) < 1) else False if src is None: src = clip else: if clip.format.id != src.format.id: raise ValueError(MODULE_NAME + ': clip format and src format mismatch.') elif clip.width != src.width or clip.height != src.height: raise ValueError(MODULE_NAME + ': clip resolution and src resolution mismatch.') preaa_clip = clip if preaa == 0 else daa(clip, preaa, opencl, opencl_device) edge_enhanced_clip = ( thin != 0 and core.warp.AWarpSharp2(preaa_clip, depth=int(thin)) or preaa_clip) edge_enhanced_clip = (dark != 0 and haf.Toon(edge_enhanced_clip, str=float(dark)) or edge_enhanced_clip) aa_kernel = { 0: lambda clip, *args, **kwargs: type('', (), {'out': lambda: clip}), 1: AAEedi2, 2: AAEedi3, 3: AANnedi3, 4: AANnedi3UpscaleSangNom, 5: AASpline64NRSangNom, 6: AASpline64SangNom, -1: AAEedi2SangNom, -2: AAEedi3SangNom, -3: AANnedi3SangNom, 'Eedi2': AAEedi2, 'Eedi3': AAEedi3, 'Nnedi3': AANnedi3, 'Nnedi3UpscaleSangNom': AANnedi3UpscaleSangNom, 'Spline64NrSangNom': AASpline64NRSangNom, 'Spline64SangNom': AASpline64SangNom, 'Eedi2SangNom': AAEedi2SangNom, 'Eedi3SangNom': AAEedi3SangNom, 'Nnedi3SangNom': AANnedi3SangNom, 'PointSangNom': AAPointSangNom, 'Unknown': lambda clip, *args, **kwargs: type( '', (), { 'out': lambda: exec( 'raise ValueError(MODULE_NAME + ": unknown aatype, aatypeu or aatypev")' ) }), 'Custom': kwargs.get( 'aakernel', lambda clip, *args, **kwargs: type( '', (), { 'out': lambda: exec( 'raise RuntimeError(MODULE_NAME + ": custom aatype: aakernel must be set.")' ) })), } if clip.format.color_family is vs.YUV: yuv = [ core.std.ShufflePlanes(edge_enhanced_clip, i, vs.GRAY) for i in range(clip.format.num_planes) ] aatypes = [aatype, aatypeu, aatypev] aa_classes = [ aa_kernel.get(aatype, aa_kernel['Unknown']) for aatype in aatypes ] aa_clips = [ aa_cycle(plane, aa_class, cycle, strength if yuv.index(plane) == 0 else 0, down8, opencl=opencl, opencl_device=opencl_device, **kwargs) for plane, aa_class in zip(yuv, aa_classes) ] aaed_clip = core.std.ShufflePlanes(aa_clips, [0, 0, 0], vs.YUV) elif clip.format.color_family is vs.GRAY: gray = edge_enhanced_clip aa_class = aa_kernel.get(aatype, aa_kernel['Unknown']) aaed_clip = aa_cycle(gray, aa_class, cycle, strength, down8, **kwargs) else: raise ValueError(MODULE_NAME + ': Unsupported color family.') abs_sharp = abs(sharp) if sharp >= 1: sharped_clip = haf.LSFmod(aaed_clip, strength=int(abs_sharp), defaults='old', source=src) elif sharp > 0: per = int(40 * abs_sharp) matrix = [-1, -2, -1, -2, 52 - per, -2, -1, -2, -1] sharped_clip = core.std.Convolution(aaed_clip, matrix) elif sharp == 0: sharped_clip = aaed_clip elif sharp > -1: sharped_clip = haf.LSFmod(aaed_clip, strength=round(abs_sharp * 100), defaults='fast', source=src) elif sharp == -1: blured = core.rgvs.RemoveGrain( aaed_clip, mode=20 if aaed_clip.width > 1100 else 11) diff = core.std.MakeDiff(aaed_clip, blured) diff = core.rgvs.Repair(diff, core.std.MakeDiff(src, aaed_clip), mode=13) sharped_clip = core.std.MergeDiff(aaed_clip, diff) else: sharped_clip = aaed_clip postaa_clip = sharped_clip if postaa is False else soothe( sharped_clip, src, 24) repaired_clip = ( (aarepair > 0 and core.rgvs.Repair(src, postaa_clip, aarepair)) or (aarepair < 0 and core.rgvs.Repair(postaa_clip, src, -aarepair)) or postaa_clip) stabilized_clip = repaired_clip if stabilize == 0 else temporal_stabilize( repaired_clip, src, stabilize) if mclip is not None: try: masked_clip = core.std.MaskedMerge(src, stabilized_clip, mclip, first_plane=True) masker = type('', (), { '__call__': lambda *args, **kwargs: mclip })() except vs.Error: raise RuntimeError( MODULE_NAME + ': Something wrong with your mclip. Maybe format, resolution or bit_depth mismatch.' ) else: # Use lambda for lazy evaluation mask_kernel = { 0: lambda: lambda a, b, *args, **kwargs: b, 1: lambda: mask_lthresh(clip, mthr, mlthresh, mask_sobel, mpand, opencl=opencl, opencl_device=opencl_device, **kwargs), 2: lambda: mask_lthresh(clip, mthr, mlthresh, mask_robert, mpand, ** kwargs), 3: lambda: mask_lthresh(clip, mthr, mlthresh, mask_prewitt, mpand, ** kwargs), 4: lambda: mask_lthresh(clip, mthr, mlthresh, mask_tedge, mpand, ** kwargs), 5: lambda: mask_lthresh(clip, mthr, mlthresh, mask_canny_continuous, mpand, opencl=opencl, opencl_device=opencl_device, **kwargs), 6: lambda: mask_lthresh(clip, mthr, mlthresh, mask_msharpen, mpand, ** kwargs), 'Sobel': lambda: mask_lthresh(clip, mthr, mlthresh, mask_sobel, mpand, opencl=opencl, opencl_device=opencl_device, **kwargs), 'Canny': lambda: mask_lthresh(clip, mthr, mlthresh, mask_canny_binarized, mpand, opencl=opencl, opencl_device=opencl_device, **kwargs), 'Prewitt': lambda: mask_lthresh(clip, mthr, mlthresh, mask_prewitt, mpand, ** kwargs), 'Robert': lambda: mask_lthresh(clip, mthr, mlthresh, mask_robert, mpand, ** kwargs), 'TEdge': lambda: mask_lthresh(clip, mthr, mlthresh, mask_tedge, mpand, ** kwargs), 'Canny_Old': lambda: mask_lthresh(clip, mthr, mlthresh, mask_canny_continuous, mpand, opencl=opencl, opencl_device=opencl_device, **kwargs), 'MSharpen': lambda: mask_lthresh(clip, mthr, mlthresh, mask_msharpen, mpand, ** kwargs), 'Unknown': lambda: exec('raise ValueError(MODULE_NAME + ": unknown mtype")') } mtype = 5 if mtype is None else mtype mthr = (24, ) if mthr is None else mthr masker = mask_kernel.get(mtype, mask_kernel['Unknown'])() masked_clip = masker(src, stabilized_clip) if txtmask > 0 and clip.format.color_family is not vs.GRAY: text_mask = mask_fadetxt(clip, lthr=txtmask, fade_num=txtfade) txt_protected_clip = core.std.MaskedMerge(masked_clip, src, text_mask, first_plane=True) else: text_mask = src txt_protected_clip = masked_clip final_output = ( (showmask == -1 and text_mask) or (showmask == 1 and masker(None, src, show=True)) or (showmask == 2 and core.std.StackVertical([ core.std.ShufflePlanes( [masker(None, src, show=True), core.std.BlankClip(src)], [0, 1, 2], vs.YUV), src ])) or (showmask == 3 and core.std.Interleave([ core.std.ShufflePlanes( [masker(None, src, show=True), core.std.BlankClip(src)], [0, 1, 2], vs.YUV), src ])) or txt_protected_clip) return final_output
def nnedi3_resample(input, target_width=None, target_height=None, src_left=None, src_top=None, src_width=None, src_height=None, csp=None, mats=None, matd=None, cplaces=None, cplaced=None, fulls=None, fulld=None, curves=None, curved=None, sigmoid=None, scale_thr=None, nsize=None, nns=None, qual=None, etype=None, pscrn=None, opt=None, int16_prescreener=None, int16_predictor=None, exp=None, kernel=None, invks=False, taps=None, invkstaps=3, a1=None, a2=None, chromak_up=None, chromak_up_taps=None, chromak_up_a1=None, chromak_up_a2=None, chromak_down=None, chromak_down_invks=False, chromak_down_invkstaps=3, chromak_down_taps=None, chromak_down_a1=None, chromak_down_a2=None, opencl=False, device=-1): core = vs.get_core() funcName = 'nnedi3_resample' # Get property about input clip if not isinstance(input, vs.VideoNode): raise TypeError(funcName + ': This is not a clip!') sFormat = input.format sColorFamily = sFormat.color_family if sColorFamily == vs.COMPAT: raise ValueError( funcName + ': Color family *COMPAT* of input clip is not supported!') sIsGRAY = sColorFamily == vs.GRAY sIsYUV = sColorFamily == vs.YUV or sColorFamily == vs.YCOCG sIsRGB = sColorFamily == vs.RGB sbitPS = sFormat.bits_per_sample sHSubS = 1 << sFormat.subsampling_w sVSubS = 1 << sFormat.subsampling_h sIsSubS = sHSubS > 1 or sVSubS > 1 sPlaneNum = sFormat.num_planes # Get property about output clip dFormat = sFormat if csp is None else core.get_format(csp) dColorFamily = dFormat.color_family if dColorFamily == vs.COMPAT: raise ValueError( funcName + ': Color family *COMPAT* of output clip is not supported!') dIsGRAY = dColorFamily == vs.GRAY dIsYUV = dColorFamily == vs.YUV or dColorFamily == vs.YCOCG dIsRGB = dColorFamily == vs.RGB dbitPS = dFormat.bits_per_sample dHSubS = 1 << dFormat.subsampling_w dVSubS = 1 << dFormat.subsampling_h dIsSubS = dHSubS > 1 or dVSubS > 1 dPlaneNum = dFormat.num_planes # Parameters of format SD = input.width <= 1024 and input.height <= 576 HD = input.width <= 2048 and input.height <= 1536 if mats is None: mats = "601" if SD else "709" if HD else "2020" else: mats = mats.lower() if matd is None: matd = mats else: matd = matd.lower() # Matrix of output clip makes sense only if dst is not of RGB if dIsRGB: matd = mats # Matrix of input clip makes sense only src is not of GRAY or RGB if sIsGRAY or sIsRGB: mats = matd if cplaces is None: if sHSubS == 4: cplaces = 'dv' else: cplaces = 'mpeg2' else: cplaces = cplaces.lower() if cplaced is None: if dHSubS == 4: cplaced = 'dv' else: cplaced = cplaces else: cplaced = cplaced.lower() if fulls is None: fulls = sColorFamily == vs.YCOCG or sColorFamily == vs.RGB if fulld is None: if dColorFamily == sColorFamily: fulld = fulls else: fulld = dColorFamily == vs.YCOCG or dColorFamily == vs.RGB if curves is None: curves = 'linear' else: curves = curves.lower() if curved is None: curved = curves else: curved = curved.lower() if sigmoid is None: sigmoid = False # Parameters of scaling if target_width is None: target_width = input.width if target_height is None: target_height = input.height if src_left is None: src_left = 0 if src_top is None: src_top = 0 if src_width is None: src_width = input.width elif src_width <= 0: src_width = input.width - src_left + src_width if src_height is None: src_height = input.height elif src_height <= 0: src_height = input.height - src_top + src_height if scale_thr is None: scale_thr = 1.125 src_right = src_width - input.width + src_left src_bottom = src_height - input.height + src_top hScale = target_width / src_width vScale = target_height / src_height # Parameters of nnedi3 if nsize is None: nsize = 0 if nns is None: nns = 3 if qual is None: qual = 2 # Parameters of fmtc.resample if kernel is None: if not invks: kernel = 'spline36' else: kernel = 'bilinear' else: kernel = kernel.lower() if chromak_up is None: chromak_up = 'nnedi3' else: chromak_up = chromak_up.lower() if chromak_up == 'softcubic': chromak_up = 'bicubic' if chromak_up_a1 is None: chromak_up_a1 = 75 chromak_up_a1 = chromak_up_a1 / 100 chromak_up_a2 = 1 - chromak_up_a1 if chromak_down is None: chromak_down = 'bicubic' else: chromak_down = chromak_down.lower() if chromak_down == 'softcubic': chromak_down = 'bicubic' if chromak_down_a1 is None: chromak_down_a1 = 75 chromak_down_a1 = chromak_down_a1 / 100 chromak_down_a2 = 1 - chromak_down_a1 # Procedure decision hIsScale = hScale != 1 vIsScale = vScale != 1 isScale = hIsScale or vIsScale hResample = hIsScale or int(src_left) != src_left or int( src_right) != src_right vResample = vIsScale or int(src_top) != src_top or int( src_bottom) != src_bottom resample = hResample or vResample hReSubS = dHSubS != sHSubS vReSubS = dVSubS != sVSubS reSubS = hReSubS or vReSubS sigmoid = sigmoid and resample sGammaConv = curves != 'linear' dGammaConv = curved != 'linear' gammaConv = (sGammaConv or dGammaConv or sigmoid) and (resample or curved != curves) scaleInGRAY = sIsGRAY or dIsGRAY scaleInYUV = not scaleInGRAY and mats == matd and not gammaConv and ( reSubS or (sIsYUV and dIsYUV)) scaleInRGB = not scaleInGRAY and not scaleInYUV # If matrix conversion or gamma correction is applied, scaling will be done in RGB. Otherwise, if at least one of input&output clip # is RGB and no chroma subsampling is involved, scaling will be done in RGB. # Chroma placement relative to the frame center in luma scale sCLeftAlign = cplaces == 'mpeg2' or cplaces == 'dv' sHCPlace = 0 if not sCLeftAlign else 0.5 - sHSubS / 2 sVCPlace = 0 dCLeftAlign = cplaced == 'mpeg2' or cplaced == 'dv' dHCPlace = 0 if not dCLeftAlign else 0.5 - dHSubS / 2 dVCPlace = 0 # Convert depth to 16-bit last = mvf.Depth(input, depth=16, fulls=fulls) # Color space conversion before scaling if scaleInGRAY and sIsYUV: if mats != matd: last = core.fmtc.matrix(last, mats=mats, matd=matd, fulls=fulls, fulld=fulld, col_fam=vs.GRAY, singleout=0) last = core.std.ShufflePlanes(last, [0], vs.GRAY) elif scaleInGRAY and sIsRGB: # Matrix conversion for output clip of GRAY last = core.fmtc.matrix(last, mat=matd, fulls=fulls, fulld=fulld, col_fam=vs.GRAY, singleout=0) fulls = fulld elif scaleInRGB and sIsYUV: # Chroma upsampling if sIsSubS: if chromak_up == 'nnedi3': # Separate planes Y = core.std.ShufflePlanes(last, [0], vs.GRAY) U = core.std.ShufflePlanes(last, [1], vs.GRAY) V = core.std.ShufflePlanes(last, [2], vs.GRAY) # Chroma up-scaling U = nnedi3_resample_kernel( U, Y.width, Y.height, -sHCPlace / sHSubS, -sVCPlace / sVSubS, None, None, 1, nsize, nns, qual, etype, pscrn, opt, int16_prescreener, int16_predictor, exp, kernel, taps, a1, a2, opencl, device) V = nnedi3_resample_kernel( V, Y.width, Y.height, -sHCPlace / sHSubS, -sVCPlace / sVSubS, None, None, 1, nsize, nns, qual, etype, pscrn, opt, int16_prescreener, int16_predictor, exp, kernel, taps, a1, a2, opencl, device) # Merge planes last = core.std.ShufflePlanes([Y, U, V], [0, 0, 0], last.format.color_family) else: last = core.fmtc.resample(last, kernel=chromak_up, taps=chromak_up_taps, a1=chromak_up_a1, a2=chromak_up_a2, css="444", fulls=fulls, cplaces=cplaces) # Matrix conversion if mats == '2020cl': last = core.fmtc.matrix2020cl(last, fulls) else: last = core.fmtc.matrix(last, mat=mats, fulls=fulls, fulld=True, col_fam=vs.RGB, singleout=-1) fulls = True elif scaleInYUV and sIsRGB: # Matrix conversion if matd == '2020cl': last = core.fmtc.matrix2020cl(last, fulld) else: last = core.fmtc.matrix(last, mat=matd, fulls=fulls, fulld=fulld, col_fam=vs.YUV, singleout=-1) fulls = fulld # Scaling if scaleInGRAY or scaleInRGB: if gammaConv and sGammaConv: last = GammaToLinear(last, fulls, fulls, curves, sigmoid=sigmoid) elif sigmoid: last = SigmoidInverse(last) last = nnedi3_resample_kernel(last, target_width, target_height, src_left, src_top, src_width, src_height, scale_thr, nsize, nns, qual, etype, pscrn, opt, int16_prescreener, int16_predictor, exp, kernel, taps, a1, a2, invks, invkstaps, opencl, device) if gammaConv and dGammaConv: last = LinearToGamma(last, fulls, fulls, curved, sigmoid=sigmoid) elif sigmoid: last = SigmoidDirect(last) elif scaleInYUV: # Separate planes Y = core.std.ShufflePlanes(last, [0], vs.GRAY) U = core.std.ShufflePlanes(last, [1], vs.GRAY) V = core.std.ShufflePlanes(last, [2], vs.GRAY) # Scale Y Y = nnedi3_resample_kernel(Y, target_width, target_height, src_left, src_top, src_width, src_height, scale_thr, nsize, nns, qual, etype, pscrn, opt, int16_prescreener, int16_predictor, exp, kernel, taps, a1, a2, opencl, device) # Scale UV dCw = target_width // dHSubS dCh = target_height // dVSubS dCsx = ((src_left - sHCPlace) * hScale + dHCPlace) / hScale / sHSubS dCsy = ((src_top - sVCPlace) * vScale + dVCPlace) / vScale / sVSubS dCsw = src_width / sHSubS dCsh = src_height / sVSubS U = nnedi3_resample_kernel(U, dCw, dCh, dCsx, dCsy, dCsw, dCsh, scale_thr, nsize, nns, qual, etype, pscrn, opt, int16_prescreener, int16_predictor, exp, kernel, taps, a1, a2, opencl, device) V = nnedi3_resample_kernel(V, dCw, dCh, dCsx, dCsy, dCsw, dCsh, scale_thr, nsize, nns, qual, etype, pscrn, opt, int16_prescreener, int16_predictor, exp, kernel, taps, a1, a2, opencl, device) # Merge planes last = core.std.ShufflePlanes([Y, U, V], [0, 0, 0], last.format.color_family) # Color space conversion after scaling if scaleInGRAY and dIsYUV: dCw = target_width // dHSubS dCh = target_height // dVSubS last = mvf.Depth(last, depth=dbitPS, fulls=fulls, fulld=fulld) blkUV = core.std.BlankClip(last, dCw, dCh, color=[1 << (dbitPS - 1)]) last = core.std.ShufflePlanes([last, blkUV, blkUV], [0, 0, 0], dColorFamily) elif scaleInGRAY and dIsRGB: last = mvf.Depth(last, depth=dbitPS, fulls=fulls, fulld=fulld) last = core.std.ShufflePlanes([last, last, last], [0, 0, 0], dColorFamily) elif scaleInRGB and dIsYUV: # Matrix conversion if matd == '2020cl': last = core.fmtc.matrix2020cl(last, fulld) else: last = core.fmtc.matrix(last, mat=matd, fulls=fulls, fulld=fulld, col_fam=dColorFamily, singleout=-1) # Chroma subsampling if dIsSubS: dCSS = '411' if dHSubS == 4 else '420' if dVSubS == 2 else '422' last = core.fmtc.resample(last, kernel=chromak_down, taps=chromak_down_taps, a1=chromak_down_a1, a2=chromak_down_a2, css=dCSS, fulls=fulld, cplaced=cplaced, invks=chromak_down_invks, invkstaps=chromak_down_invkstaps, planes=[2, 3, 3]) last = mvf.Depth(last, depth=dbitPS, fulls=fulld) elif scaleInYUV and dIsRGB: # Matrix conversion if mats == '2020cl': last = core.fmtc.matrix2020cl(last, fulls) else: last = core.fmtc.matrix(last, mat=mats, fulls=fulls, fulld=True, col_fam=vs.RGB, singleout=-1) last = mvf.Depth(last, depth=dbitPS, fulls=True, fulld=fulld) else: last = mvf.Depth(last, depth=dbitPS, fulls=fulls, fulld=fulld) # Output return last
def inputs(files, is_training=False, is_testing=False): # parameters channels = FLAGS.image_channels threads = FLAGS.threads threads_py = FLAGS.threads_py scaling = FLAGS.scaling if is_training: num_epochs = FLAGS.num_epochs data_format = FLAGS.data_format patch_height = FLAGS.patch_height patch_width = FLAGS.patch_width batch_size = FLAGS.batch_size if is_training: buffer_size = FLAGS.buffer_size epoch_size = len(files) # dataset mapping function def parse1_func(filename): # read data dtype = tf.float32 image = tf.read_file(filename) image = tf.image.decode_image(image, channels=channels) shape = tf.shape(image) height = shape[-3] width = shape[-2] # pre down-scale for high resolution image dscale = 1 if is_training and FLAGS.pre_down: ''' if (width >= 3072 and height >= 1536) or (width >= 1536 and height >= 3072): dscale = 3 elif (width >= 1024 and height >= 512) or (width >= 512 and height >= 1024): dscale = 2 ''' def c_t(const1, const2, true_fn, false_fn): return tf.cond( tf.logical_or( tf.logical_and(tf.greater_equal(width, const1), tf.greater_equal(height, const2)), tf.logical_and(tf.greater_equal(width, const2), tf.greater_equal(height, const1))), true_fn, false_fn) dscale = c_t(3072, 1536, lambda: 3, lambda: c_t(1024, 512, lambda: 2, lambda: 1)) elif is_testing and FLAGS.pre_down: ''' if (width >= 3072 and height >= 3072): dscale = 4 elif (width >= 2048 and height >= 2048): dscale = 3 elif (width >= 1024 and height >= 1024): dscale = 2 ''' def c_t(const1, true_fn, false_fn): return tf.cond( tf.logical_and(tf.greater_equal(width, const1), tf.greater_equal(height, const1)), true_fn, false_fn) dscale = c_t( 3072, lambda: 4, lambda: c_t( 2048, lambda: 3, lambda: c_t(1024, lambda: 2, lambda: 1))) # padding cropped_height = patch_height * dscale cropped_width = patch_width * dscale ''' if cropped_height > height or cropped_width > width: pad_height = cropped_height - height pad_width = cropped_width - width if pad_height > 0: pad_height = [pad_height // 2, pad_height - pad_height // 2] height = cropped_height else: pad_height = [0, 0] if pad_width > 0: pad_width = [pad_width // 2, pad_width - pad_width // 2] width = cropped_width else: pad_width = [0, 0] block = tf.pad(image, [pad_height, pad_width, [0, 0]], mode='REFLECT') else: block = image ''' cond_height = tf.greater(cropped_height, height) cond_width = tf.greater(cropped_width, width) def c_f1(): def _1(): ph = cropped_height - height return [ph // 2, ph - ph // 2] pad_height = tf.cond(cond_height, _1, lambda: [0, 0]) def _2(): pw = cropped_width - width return [pw // 2, pw - pw // 2] pad_width = tf.cond(cond_width, _2, lambda: [0, 0]) return tf.pad(image, [pad_height, pad_width, [0, 0]], mode='REFLECT') block = tf.cond(tf.logical_or(cond_height, cond_width), c_f1, lambda: image) height = tf.maximum(cropped_height, height) width = tf.maximum(cropped_width, width) # cropping if is_training: block = tf.random_crop(block, [cropped_height, cropped_width, channels]) block = tf.image.random_flip_up_down(block) block = tf.image.random_flip_left_right(block) elif is_testing: offset_height = (height - cropped_height) // 2 offset_width = (width - cropped_width) // 2 block = tf.image.crop_to_bounding_box(block, offset_height, offset_width, cropped_height, cropped_width) # convert dtype block = tf.image.convert_image_dtype(block, dtype, saturate=False) # random color augmentation if is_training and FLAGS.color_augmentation > 0: block = tf.image.random_saturation(block, 1 - FLAGS.color_augmentation, 1 + FLAGS.color_augmentation) block = tf.image.random_brightness(block, FLAGS.color_augmentation) block = tf.image.random_contrast(block, 1 - FLAGS.color_augmentation, 1 + FLAGS.color_augmentation) # data format conversion block.set_shape([None, None, channels]) if data_format == 'NCHW': block = tf.transpose(block, (2, 0, 1)) # return return block # tf.py_func processing using vapoursynth, numpy, etc. import threading import vapoursynth as vs from scipy import ndimage def SigmoidInverse(clip, thr=0.5, cont=6.5, epsilon=1e-6): assert clip.format.sample_type == vs.FLOAT x0 = 1 / (1 + np.exp(cont * thr)) x1 = 1 / (1 + np.exp(cont * (thr - 1))) # thr - log(max(1 / max(x * (x1 - x0) + x0, epsilon) - 1, epsilon)) / cont expr = '{thr} 1 x {x1_x0} * {x0} + {epsilon} max / 1 - {epsilon} max log {cont_rec} * -'.format( thr=thr, cont_rec=1 / cont, epsilon=epsilon, x0=x0, x1_x0=x1 - x0) return clip.std.Expr(expr) def SigmoidDirect(clip, thr=0.5, cont=6.5): assert clip.format.sample_type == vs.FLOAT x0 = 1 / (1 + np.exp(cont * thr)) x1 = 1 / (1 + np.exp(cont * (thr - 1))) # (1 / (1 + exp(cont * (thr - x))) - x0) / (x1 - x0) expr = '1 1 {cont} {thr} x - * exp + / {x0} - {x1_x0_rec} *'.format( thr=thr, cont=cont, x0=x0, x1_x0_rec=1 / (x1 - x0)) return clip.std.Expr(expr) _lock = threading.Lock() _index_ref = [0] _src_ref = [None for _ in range(epoch_size)] core = vs.get_core(threads=threads_py) _dscales = list(range(1, 5)) if FLAGS.pre_down else [1] _src_blk = [ core.std.BlankClip(None, patch_width * s, patch_height * s, format=vs.RGBS, length=epoch_size) for s in _dscales ] _dst_blk = core.std.BlankClip(None, patch_width // scaling, patch_height // scaling, format=vs.RGBS, length=epoch_size) def src_frame_func(n, f): f_out = f.copy() planes = f_out.format.num_planes # output for p in range(planes): f_arr = np.array(f_out.get_write_array(p), copy=False) np.copyto( f_arr, _src_ref[n][p, :, :] if data_format == 'NCHW' else _src_ref[n][:, :, p]) return f_out _srcs = [s.std.ModifyFrame(s, src_frame_func) for s in _src_blk] _srcs_linear = [ s.resize.Bicubic(transfer_s='linear', transfer_in_s='709') for s in _srcs ] def src_down_func(clip): dw = patch_width dh = patch_height #clip = clip.resize.Bicubic(transfer_s='linear', transfer_in_s='709') clip = SigmoidInverse(clip) clip = clip.resize.Bicubic(dw, dh, filter_param_a=0, filter_param_b=0.5) clip = SigmoidDirect(clip) clip = clip.resize.Bicubic(transfer_s='709', transfer_in_s='linear') return clip if FLAGS.pre_down: _srcs_down = [src_down_func(s) for s in _srcs_linear] def src_select_eval(n): # select source shape = _src_ref[n].shape sh = shape[-2 if data_format == 'NCHW' else -3] dscale = sh // patch_height # downscale if needed if dscale > 1: clip = _srcs_down[dscale - 1] else: clip = _srcs[dscale - 1] return clip if FLAGS.pre_down: _src = _src_blk[0].std.FrameEval(src_select_eval) else: _src = _srcs[0] def resize_set_func(clip, linear=False): # parameters dw = patch_width // scaling dh = patch_height // scaling rets = {} # resizers rets['bilinear'] = clip.resize.Bilinear(dw, dh) rets['spline16'] = clip.resize.Spline16(dw, dh) rets['spline36'] = clip.resize.Spline36(dw, dh) for taps in range(2, 12): rets['lanczos{}'.format(taps)] = clip.resize.Lanczos( dw, dh, filter_param_a=taps) # linear to gamma if linear: for key in rets: rets[key] = rets[key].resize.Bicubic(transfer_s='709', transfer_in_s='linear') return rets _resizes = [resize_set_func(s, linear=False) for s in _srcs] _linear_resizes = [resize_set_func(s, linear=True) for s in _srcs_linear] def resize_eval(n): # parameters dw = patch_width // scaling dh = patch_height // scaling rand_val = np.random.uniform(-1, 1) abs_rand = np.abs(rand_val) # select source shape = _src_ref[n].shape sh = shape[-2 if data_format == 'NCHW' else -3] dscale = sh // patch_height # random gamma-to-linear if rand_val < 0: clip = _srcs_linear[dscale - 1] resizes = _linear_resizes[dscale - 1] else: clip = _srcs[dscale - 1] resizes = _resizes[dscale - 1] # random resizers if abs_rand < 0.05: clip = resizes['bilinear'] elif abs_rand < 0.1: clip = resizes['spline16'] elif abs_rand < 0.15: clip = resizes['spline36'] elif abs_rand < 0.4: # Lanczos taps=[2, 12) taps = int(np.clip(np.random.exponential(2) + 2, 2, 11)) clip = resizes['lanczos{}'.format(taps)] elif abs_rand < 0.6: # Catmull-Rom b = np.random.normal(0, 1 / 6) c = (1 - b) * 0.5 clip = clip.resize.Bicubic(dw, dh, filter_param_a=b, filter_param_b=c) elif abs_rand < 0.7: # Mitchell-Netravali (standard Bicubic) b = np.random.normal(1 / 3, 1 / 6) c = (1 - b) * 0.5 clip = clip.resize.Bicubic(dw, dh, filter_param_a=b, filter_param_b=c) elif abs_rand < 0.8: # sharp Bicubic b = np.random.normal(-0.5, 0.25) c = b * -0.5 clip = clip.resize.Bicubic(dw, dh, filter_param_a=b, filter_param_b=c) elif abs_rand < 0.9: # soft Bicubic b = np.random.normal(0.75, 0.25) c = 1 - b clip = clip.resize.Bicubic(dw, dh, filter_param_a=b, filter_param_b=c) else: # arbitrary Bicubic b = np.random.normal(0, 0.5) c = np.random.normal(0.25, 0.25) clip = clip.resize.Bicubic(dw, dh, filter_param_a=b, filter_param_b=c) # random linear-to-gamma if rand_val < 0 and abs_rand >= 0.4: clip = clip.resize.Bicubic(transfer_s='709', transfer_in_s='linear') # return return clip _dst = _dst_blk.std.FrameEval(resize_eval) def parse2_pyfunc(label): channel_index = -3 if data_format == 'NCHW' else -1 dscale = label.shape[-2 if data_format == 'NCHW' else -3] // patch_height # safely acquire and increase shared index _lock.acquire() index = _index_ref[0] _index_ref[0] = (index + 1) % epoch_size _lock.release() # processing using vs _src_ref[index] = label if FLAGS.pre_down and dscale > 1: f_src = _src.get_frame(index) f_dst = _dst.get_frame(index) _src_ref[index] = None # vs.VideoFrame to np.ndarray if FLAGS.pre_down and dscale > 1: label = [] planes = f_src.format.num_planes for p in range(planes): f_arr = np.array(f_src.get_read_array(p), copy=False) label.append(f_arr) label = np.stack(label, axis=channel_index) data = [] planes = f_dst.format.num_planes for p in range(planes): f_arr = np.array(f_dst.get_read_array(p), copy=False) data.append(f_arr) data = np.stack(data, axis=channel_index) # noise spatial correlation def noise_correlation(noise, corr): if corr > 0: sigma = np.random.normal(corr, corr) if sigma > 0.25: sigma = [0, sigma, sigma ] if data_format == 'NCHW' else [sigma, sigma, 0] noise = ndimage.gaussian_filter(noise, sigma, truncate=2.0) return noise # add Gaussian noise of random scale and random spatial correlation if FLAGS.noise_scale > 0: rand_val = np.random.uniform(0, 1) scale = np.random.exponential(FLAGS.noise_scale) if rand_val >= 0.2 and scale > 0.002: # add noise noise_shape = list(data.shape) if rand_val < 0.35: # RGB noise noise = np.random.normal(0.0, scale, noise_shape).astype(np.float32) noise = noise_correlation(noise, FLAGS.noise_corr) else: # Y/YUV noise noise_shape[channel_index] = 1 noise_y = np.random.normal(0.0, scale, noise_shape).astype(np.float32) noise_y = noise_correlation(noise_y, FLAGS.noise_corr) scale_uv = np.random.exponential(FLAGS.noise_scale / 2) if rand_val < 0.55 and scale_uv > 0.002: # YUV noise noise_u = np.random.normal( 0.0, scale_uv, noise_shape).astype(np.float32) noise_u = noise_correlation(noise_u, FLAGS.noise_corr * 1.5) noise_v = np.random.normal( 0.0, scale_uv, noise_shape).astype(np.float32) noise_v = noise_correlation(noise_v, FLAGS.noise_corr * 1.5) rand_val2 = np.random.uniform(0, 1) if rand_val2 < 0.3: # Rec.601 Kr = 0.299 Kg = 0.587 Kb = 0.114 elif rand_val2 < 0.9: # Rec.709 Kr = 0.2126 Kg = 0.7152 Kb = 0.0722 else: # Rec.2020 Kr = 0.2627 Kg = 0.6780 Kb = 0.0593 noise_r = noise_y + ((1 - Kr) / 2) * noise_v noise_b = noise_y + ((1 - Kb) / 2) * noise_u noise_g = (1 / Kg) * noise_y - (Kr / Kg) * noise_r - ( Kb / Kg) * noise_b noise = [noise_r, noise_g, noise_b] else: noise = [noise_y, noise_y, noise_y] noise = np.concatenate(noise, axis=channel_index) # adding noise data += noise # return return data, label def parse3_func(data, label): # final process data = tf.clip_by_value(data, 0.0, 1.0) label = tf.clip_by_value(label, 0.0, 1.0) # JPEG encoding if FLAGS.jpeg_coding: rand_val = tf.random_uniform([], 0, 1) def c_f1(data): if data_format == 'NCHW': data = tf.transpose(data, (1, 2, 0)) data = tf.image.convert_image_dtype(data, tf.uint8, saturate=True) def _f1(): return tf.image.encode_jpeg(data, quality=98, chroma_downsampling=False) def _f2(): return tf.image.encode_jpeg(data, quality=96, chroma_downsampling=False) def _f3(): return tf.image.encode_jpeg(data, quality=95, chroma_downsampling=False) def _f4(): return tf.image.encode_jpeg(data, quality=92, chroma_downsampling=False) def _f5(): return tf.image.encode_jpeg(data, quality=90, chroma_downsampling=False) def _f6(): return tf.image.encode_jpeg(data, quality=88, chroma_downsampling=False) def _f7(): return tf.image.encode_jpeg(data, quality=85, chroma_downsampling=False) def _f8(): return tf.image.encode_jpeg(data, quality=84, chroma_downsampling=False) def _f9(): return tf.image.encode_jpeg(data, quality=82, chroma_downsampling=False) def _f10(): return tf.image.encode_jpeg(data, quality=80, chroma_downsampling=False) data = tf.cond( tf.less(rand_val, 0.03), _f1, lambda: tf.cond( tf.less(rand_val, 0.06), _f2, lambda: tf.cond( tf.less(rand_val, 0.09), _f3, lambda: tf.cond( tf.less(rand_val, 0.12), _f4, lambda: tf.cond( tf.less(rand_val, 0.15), _f5, lambda: tf. cond( tf.less(rand_val, 0.18), _f6, lambda: tf.cond( tf.less(rand_val, 0.21), _f7, lambda: tf.cond( tf.less(rand_val, 0.24), _f8, lambda: tf.cond( tf.less(rand_val, 0.27), _f9, _f10))))))))) data = tf.image.decode_jpeg(data) data = tf.image.convert_image_dtype(data, tf.float32, saturate=False) if data_format == 'NCHW': data = tf.transpose(data, (2, 0, 1)) return data data = tf.cond(tf.less(rand_val, 0.3), lambda: c_f1(data), lambda: data) # return return data, label # Dataset API dataset = tf.contrib.data.Dataset.from_tensor_slices((files)) dataset = dataset.map(parse1_func, num_threads=threads, output_buffer_size=threads * 64) dataset = dataset.map(lambda label: tuple( tf.py_func(parse2_pyfunc, [label], [tf.float32, tf.float32])), num_threads=threads_py, output_buffer_size=threads_py * 64) dataset = dataset.map(parse3_func, num_threads=threads, output_buffer_size=threads * 64) if is_training and FLAGS.buffer_size > 0: dataset = dataset.shuffle(buffer_size) dataset = dataset.batch(batch_size) if is_training: dataset = dataset.repeat(num_epochs) # return iterator iterator = dataset.make_one_shot_iterator() next_data, next_label = iterator.get_next() # data shape declaration if data_format == 'NCHW': next_data.set_shape([None, channels, None, None]) next_label.set_shape([None, channels, None, None]) #next_data.set_shape([None, channels, patch_height // scaling, patch_width // scaling]) #next_label.set_shape([None, channels, patch_height, patch_width]) else: next_data.set_shape([None, None, None, channels]) next_label.set_shape([None, None, None, channels]) #next_data.set_shape([None, patch_height // scaling, patch_width // scaling, channels]) #next_label.set_shape([None, patch_height, patch_width, channels]) return next_data, next_label
def LinearAndGamma(src, l2g_flag, fulls, fulld, curve, planes, gcor, sigmoid, thr, cont): core = vs.get_core() if curve == 'srgb': c_num = 0 elif curve in ['709', '601', '170']: c_num = 1 elif curve == '240': c_num = 2 elif curve == '2020': c_num = 3 else: raise ValueError('LinearAndGamma: wrong curve value') if src.format.color_family == vs.GRAY: planes = [0] # BT-709/601 # sRGB SMPTE 170M SMPTE 240M BT-2020 k0 = [0.04045, 0.081, 0.0912, 0.08145][c_num] phi = [12.92, 4.5, 4.0, 4.5][c_num] alpha = [0.055, 0.099, 0.1115, 0.0993][c_num] gamma = [2.4, 2.22222, 2.22222, 2.22222][c_num] def g2l(x): expr = x / 65536 if fulls else (x - 4096) / 56064 if expr <= k0: expr /= phi else: expr = ((expr + alpha) / (1 + alpha))**gamma if gcor != 1 and expr >= 0: expr **= gcor if sigmoid: x0 = 1 / (1 + math.exp(cont * thr)) x1 = 1 / (1 + math.exp(cont * (thr - 1))) expr = thr - math.log( max(1 / max(expr * (x1 - x0) + x0, 0.000001) - 1, 0.000001)) / cont if fulld: return min(max(round(expr * 65536), 0), 65535) else: return min(max(round(expr * 56064 + 4096), 0), 65535) # E' = (E <= k0 / phi) ? E * phi : (E ^ (1 / gamma)) * (alpha + 1) - alpha def l2g(x): expr = x / 65536 if fulls else (x - 4096) / 56064 if sigmoid: x0 = 1 / (1 + math.exp(cont * thr)) x1 = 1 / (1 + math.exp(cont * (thr - 1))) expr = (1 / (1 + math.exp(cont * (thr - expr))) - x0) / (x1 - x0) if gcor != 1 and expr >= 0: expr **= gcor if expr <= k0 / phi: expr *= phi else: expr = expr**(1 / gamma) * (alpha + 1) - alpha if fulld: return min(max(round(expr * 65536), 0), 65535) else: return min(max(round(expr * 56064 + 4096), 0), 65535) return core.std.Lut(src, planes=planes, function=l2g if l2g_flag else g2l)
import vapoursynth as vs core = vs.get_core() colorfamilies = (vs.GRAY, vs.YUV, vs.RGB, vs.YCOCG) intbitdepths = (8, 9, 10, 11, 12, 13, 14, 15, 16) floatbitdepths = (16, 32) yuvss = (0, 1, 2) formatids = [] for cfs in colorfamilies: for bps in intbitdepths: if cfs in (vs.YUV, vs.YCOCG): for wss in yuvss: for hss in yuvss: formatids.append( core.register_format(cfs, vs.INTEGER, bps, wss, hss).id) else: formatids.append( core.register_format(cfs, vs.INTEGER, bps, 0, 0).id) for cfs in colorfamilies: for bps in floatbitdepths: if cfs in (vs.YUV, vs.YCOCG): for wss in yuvss: for hss in yuvss: formatids.append( core.register_format(cfs, vs.FLOAT, bps, wss, hss).id) else:
def TextSub16(clip, file, mod=False, charset=None, fps=None, vfr=None, swapuv=None): core = vs.get_core() funcName = 'TextSub16' if clip.format.color_family != vs.YUV: raise TypeError(funcName + ': only planar YUV input is supported.') sw = clip.width sh = clip.height if clip.format.bits_per_sample != 16: src16 = core.fmtc.bitdepth(clip=clip, bits=16) else: src16 = clip src8 = core.fmtc.bitdepth(clip=clip, bits=8) yuv444 = src16.format.id == vs.YUV444P16 yuv422 = src16.format.id == vs.YUV422P16 yuv420 = src16.format.id == vs.YUV420P16 if mod: src8sub = core.VSFmod.VobSubMod(clip=src8, file=file, swapuv=swapuv) else: src8sub = core.xyvsf.TextSub(clip=src8, file=file, charset=charset, fps=fps, vfr=vfr, swapuv=swapuv) src16sub = core.fmtc.bitdepth(clip=src8sub, bits=16) submask = core.std.Expr([src8, src8sub], expr=["x y = 0 255 ?"]) submaskY = core.std.ShufflePlanes(clips=submask, planes=0, colorfamily=vs.GRAY) submaskY = core.fmtc.bitdepth(clip=submaskY, bits=16) submaskU = core.std.ShufflePlanes(clips=submask, planes=1, colorfamily=vs.GRAY).fmtc.resample( w=sw, h=sh, sx=0.25, kernel="bilinear") submaskV = core.std.ShufflePlanes(clips=submask, planes=2, colorfamily=vs.GRAY).fmtc.resample( w=sw, h=sh, sx=0.25, kernel="bilinear") submask = core.std.Expr([submaskY, submaskU, submaskV], expr=["x y max z max"]) if yuv444: submaskC = submask if yuv422: submaskC = core.fmtc.resample(submask, w=sw // 2, h=sh, sx=-0.5, kernel="bilinear") if yuv420: submaskC = core.fmtc.resample(submask, w=sw // 2, h=sh // 2, sx=-0.5, kernel="bilinear") submask = core.std.ShufflePlanes(clips=[submask, submaskC, submaskC], planes=[0, 0, 0], colorfamily=vs.YUV) res = core.std.MaskedMerge(clipa=src16, clipb=src16sub, mask=submask, planes=[0, 1, 2]) return res