def __init__(self, clip, strength=0, down8=False, **args): super(AAEedi3, self).__init__(clip, strength, down8) self.eedi3_args = { 'alpha': args.get('alpha', 0.5), 'beta': args.get('beta', 0.2), 'gamma': args.get('gamma', 20), 'nrad': args.get('nrad', 3), 'mdis': args.get('mdis', 30) } self.opencl = args.get('opencl', False) if self.opencl is True: try: self.eedi3 = self.core.eedi3m.EEDI3CL self.eedi3_args['device'] = args.get('opencl_device', 0) except AttributeError: self.eedi3 = self.core.eedi3.eedi3 if self.process_depth > 8: self.clip = mvf.Depth(self.clip, 8) else: try: self.eedi3 = self.core.eedi3m.EEDI3 except AttributeError: self.eedi3 = self.core.eedi3.eedi3 if self.process_depth > 8: self.clip = mvf.Depth(self.clip, 8)
def BernsteinFilter(clip, iter=30, **depth_args): """Bernstein Filter Bernstein filter is an efficient filter solver, which can implicitly minimize the mean curvature. Internal precision is always float. Args: clip: Input. iter: (int) Num of iterations. Default is 30 depth_args: (dict) Additional arguments passed to mvf.Depth() in the form of keyword arguments. Default is {}. Ref: [1] Gong, Y. (2016, March). Bernstein filter: A new solver for mean curvature regularized models. In Acoustics, Speech and Signal Processing (ICASSP), 2016 IEEE International Conference on (pp. 1701-1705). IEEE. """ bits = clip.format.bits_per_sample sample = clip.format.sample_type clip = mvf.Depth(clip, depth=32, sample=vs.FLOAT, **depth_args) for i in range(iter): d1 = core.std.Convolution(clip, [1, -2, 1], divisor=2, mode='h') d2 = core.std.Convolution(clip, [1, -2, 1], divisor=2, mode='v') clip = core.std.Expr([clip, d1, d2], ['y abs z abs < x y + x z + ?']) return mvf.Depth(clip, depth=bits, sample=sample, **depth_args)
def Wiener2(input, radius_v=3, radius_h=None, noise=None, **depth_args): """2-D adaptive noise-removal filtering. (wiener2 from MATLAB) Wiener2 lowpass filters an intensity image that has been degraded by constant power additive noise. Wiener2 uses a pixel-wise adaptive Wiener method based on statistics estimated from a local neighborhood of each pixel. Estimate of the additive noise power will not be returned. Args: input: Input clip. Only the first plane will be processed. radius_v, radius_h: (int) Size of neighborhoods to estimate the local image mean and standard deviation. The size is (radius_v*2-1) * (radius_h*2-1). If "radius_h" is None, it will be set to "radius_v". Default is 3. noise: (float) Variance of addictive noise. If it is not given, average of all the local estimated variances will be used. Default is {}. depth_args: (dict) Additional arguments passed to mvf.Depth() in the form of keyword arguments. Default is {}. Ref: [1] Lim, J. S. (1990). Two-dimensional signal and image processing. Englewood Cliffs, NJ, Prentice Hall, 1990, 710 p, p. 538, equations 9.26, 9.27, and 9.29. [2] 2-D adaptive noise-removal filtering - MATLAB wiener2 - MathWorks (https://www.mathworks.com/help/images/ref/wiener2.html) """ core = vs.get_core() funcName = 'Wiener2' if not isinstance(input, vs.VideoNode) or input.format.num_planes > 1: raise TypeError(funcName + ': \"input\" must be a gray-scale/single channel clip!') bits = input.format.bits_per_sample sampleType = input.format.sample_type if radius_h is None: radius_h = radius_v input32 = mvf.Depth(input, depth=32, sample=vs.FLOAT, **depth_args) localMean = muf.BoxFilter(input32, radius_h+1, radius_v+1) localVar = muf.BoxFilter(core.std.Expr([input32], ['x dup *']), radius_h+1, radius_v+1) localVar = core.std.Expr([localVar, localMean], ['x y dup * -']) if noise is None: localVarStats = core.std.PlaneStats(localVar, plane=[0]) def FLT(n, f, clip, core, localMean, localVar): noise = f.props.PlaneStatsAverage return core.std.Expr([clip, localMean, localVar], ['y z {noise} - 0 max z {noise} max / x y - * +'.format(noise=noise)]) flt = core.std.FrameEval(input32, functools.partial(FLT, clip=input32, core=core, localMean=localMean, localVar=localVar), prop_src=[localVarStats]) else: flt = core.std.Expr([input32, localMean, localVar], ['y z {noise} - 0 max z {noise} max / x y - * +'.format(noise=noise)]) return mvf.Depth(flt, depth=bits, sample=sampleType, **depth_args)
def out(self): aaed = self.core.fmtc.resample(self.clip, self.clip_width, self.uph4, kernel="spline64") aaed = mvf.Depth(aaed, self.process_depth) aaed = self.core.sangnom.SangNom(aaed, aa=self.aa) aaed = self.core.std.Transpose(self.resize(aaed, self.clip_width, self.clip_height, 0)) aaed = self.core.fmtc.resample(aaed, self.clip_height, self.upw4, kernel="spline64") aaed = mvf.Depth(aaed, self.process_depth) aaed = self.core.sangnom.SangNom(aaed, aa=self.aa) aaed = self.core.std.Transpose(self.resize(aaed, self.clip_height, self.clip_width, 0)) return aaed
def SSR(clip, sigma=50, full=None, **args): """Single-scale Retinex Args: clip: Input. Only the first plane will be processed. sigma: (int) Standard deviation of gaussian blur. Default is 50. full: (bool) Whether input clip is of full range. Default is None. Ref: [1] Jobson, D. J., Rahman, Z. U., & Woodell, G. A. (1997). Properties and performance of a center/surround retinex. IEEE transactions on image processing, 6(3), 451-462. """ bits = clip.format.bits_per_sample sampleType = clip.format.sample_type isGray = clip.format.color_family == vs.GRAY if not isGray: clip_src = clip clip = mvf.GetPlane(clip) lowFre = gauss(clip, sigma=sigma, **args) clip = mvf.Depth(clip, 32, fulls=full) lowFre = mvf.Depth( lowFre, 32, fulls=full) # core.bilateral.Gaussian() doesn't support float input. expr = 'x 1 + log y 1 + log -' clip = core.std.Expr([clip, lowFre], [expr]) stats = core.std.PlaneStats(clip, plane=[0]) # Dynamic range stretching def Stretch(n, f, clip, core): alpha = f.props['PlaneStatsMax'] - f.props['PlaneStatsMin'] beta = f.props['PlaneStatsMin'] expr = 'x {beta} - {alpha} /'.format(beta=beta, alpha=alpha) return core.std.Expr([clip], [expr]) clip = core.std.FrameEval(clip, functools.partial(Stretch, clip=clip, core=core), prop_src=stats) clip = mvf.Depth(clip, depth=bits, sample=sampleType, fulld=full) if not isGray: clip = core.std.ShufflePlanes([clip, clip_src], list(range(clip_src.format.num_planes)), clip_src.format.color_family) return clip
def out(self): aa_spline64 = self.core.fmtc.resample(self.clip, self.upw4, self.uph4, kernel='spline64') aa_spline64 = mvf.Depth(aa_spline64, self.process_depth) aa_gaussian = self.core.fmtc.resample(self.clip, self.upw4, self.uph4, kernel='gaussian', a1=100) aa_gaussian = mvf.Depth(aa_gaussian, self.process_depth) aaed = self.core.rgvs.Repair(aa_spline64, aa_gaussian, 1) aaed = self.core.sangnom.SangNom(aaed, aa=self.aa) aaed = self.core.std.Transpose(aaed) aaed = self.core.sangnom.SangNom(aaed, aa=self.aa) aaed = self.core.std.Transpose(aaed) aaed = self.resize(aaed, self.clip_width, self.clip_height, shift=0) return aaed
def __init__(self, clip): super(MaskParent, self).__init__(clip) if clip.format.color_family is not vs.GRAY: self.clip = self.core.std.ShufflePlanes(self.clip, 0, vs.GRAY) self.clip = mvf.Depth(self.clip, 8) # Mask will always be processed in 8bit scale self.mask = None self.multi = ((1 << self.clip_bits) - 1) // 255
def mask_lthresh(clip, mthrs, lthreshes, mask_kernel, inexpand, **kwargs): core = vs.get_core() gray8 = mvf.Depth(clip, 8) if clip.format.bits_per_sample != 8 else clip gray8 = core.std.ShufflePlanes( gray8, 0, vs.GRAY) if clip.format.color_family != vs.GRAY else gray8 mthrs = mthrs if isinstance(mthrs, (list, tuple)) else [mthrs] lthreshes = lthreshes if isinstance(lthreshes, (list, tuple)) else [lthreshes] inexpand = inexpand if isinstance( inexpand, (list, tuple)) and len(inexpand) >= 2 else [inexpand, 0] mask_kernels = [mask_kernel(mthr, **kwargs) for mthr in mthrs] masks = [kernel(gray8) for kernel in mask_kernels] mask = ((len(mthrs) - len(lthreshes) == 1) and functools.reduce( lambda x, y: core.std.Expr([x, y, gray8], 'z %d < x y ?' % lthreshes[ masks.index(y) - 1]), masks)) or masks[0] mask = [mask] + [core.std.Maximum] * inexpand[0] mask = functools.reduce(lambda x, y: y(x), mask) mask = [mask] + [core.std.Minimum] * inexpand[1] mask = functools.reduce(lambda x, y: y(x), mask) bps = clip.format.bits_per_sample mask = (bps > 8 and core.std.Expr( mask, 'x %d *' % (((1 << clip.format.bits_per_sample) - 1) // 255), eval('vs.GRAY' + str(bps)))) or mask return lambda clip_a, clip_b, show=False: ( show is False and core.std.MaskedMerge(clip_a, clip_b, mask)) or mask
def resize(self, clip, w, h, shift): try: resized = self.core.resize.Spline36(clip, w, h, src_top=shift) except vs.Error: resized = self.core.fmtc.resample(clip, w, h, sy=shift) if resized.format.bits_per_sample != self.process_depth: mvf.Depth(resized, self.process_depth) return resized
def output(self, aaed): if self.process_depth != self.clip_bits: return mvf.LimitFilter(self.clip, mvf.Depth(aaed, self.clip_bits), thr=1.0, elast=2.0) else: return aaed
def out(self): aaed = self.eedi3(self.clip, field=1, dh=True, **self.eedi3_args) aaed = self.resize(aaed, self.dw, self.clip_height, shift=-0.5) aaed = self.core.std.Transpose(aaed) aaed = self.eedi3(aaed, field=1, dh=True, **self.eedi3_args) aaed = self.resize(aaed, self.clip_height, self.clip_width, shift=-0.5) aaed = self.core.std.Transpose(aaed) aaed_bits = aaed.format.bits_per_sample return aaed if aaed_bits == self.process_depth else mvf.Depth(aaed, self.process_depth)
def camp(src): src16 = core.fmtc.bitdepth(src, bits=16) src_rgb = mvf.ToRGB(src16,depth=32) nr16_rgb = core.pdn.BM3DBasic(src_rgb, sigma=[0.5, 0.2, 0.2]) nr16 = mvf.ToYUV(nr16_rgb, css="420",depth=16) noise16 = core.std.MakeDiff(src16, nr16) pre16 = core.std.ShufflePlanes([nr16,src16],[0,1,2],vs.YUV) pre8 = mvf.Depth(pre16, depth=8, dither=5) eemask = core.tcanny.TCanny(pre8,sigma=0.6,op=2,gmmax=255,planes=[0,1,2],mode=1) eemask_u = core.std.ShufflePlanes(eemask, [1,1,1], vs.YUV).fmtc.resample(1920,1080,sx=0.25,css="420") eemask_v = core.std.ShufflePlanes(eemask, [2,2,2], vs.YUV).fmtc.resample(1920,1080,sx=0.25,css="420") weighted = core.std.Expr([eemask,eemask_u,eemask_v],["x 64 * y + z +",""],vs.YUV420P16) luma = core.std.ShufflePlanes(pre8, 0, vs.YUV).resize.Bilinear(format=vs.YUV420P8) eemask = core.std.Expr([eemask,luma],["x x * 20 * 255 y - dup * 0.2 * + 50000 min","x x * 30 * 255 y - dup * 0.3 * + 60000 min"],vs.YUV420P16) eemask = core.std.Maximum(eemask,planes=[0,1,2]) eemask = core.rgvs.RemoveGrain(eemask, [20,11]).rgvs.RemoveGrain([20,11]).rgvs.RemoveGrain([20,11]) aamask = core.std.Binarize(weighted, 8000, 0) Y = core.std.ShufflePlanes(src16, 0, vs.YUV).resize.Bicubic(1920, 1080, format=vs.YUV420P16, filter_param_a=0, filter_param_b=0.5) U = core.std.ShufflePlanes(src16, [1,1,1], vs.YUV).resize.Bicubic(1920, 1080, format=vs.YUV420P16, filter_param_a=0, filter_param_b=0.5) V = core.std.ShufflePlanes(src16, [2,2,2], vs.YUV).resize.Bicubic(1920, 1080, format=vs.YUV420P16, filter_param_a=0, filter_param_b=0.5) textmask0 = core.std.Expr([Y,U,V], ["x 60000 > y 32768 - abs 768 < and z 32768 - abs 768 < and 65535 0 ?","0"]) #textmasks = core.std.Expr([Y,U,V], ["x 58000 > y 32768 - abs 512 < and z 32768 - abs 512 < and 65535 0 ?","0"]) textmask1 = core.std.Minimum(textmask0, 0).std.Minimum(planes=0).std.Minimum(planes=0).std.Maximum(0).std.Maximum(0).std.Maximum(0) textmask2 = core.misc.Hysteresis(textmask1, textmask0, planes=0) textmask = core.std.Expr([textmask0, textmask2], "x y > x 0 ?") #textmask = core.misc.Hysteresis(textmasks, textmaskb, planes=0) textmask = core.std.Maximum(textmask,0).std.Maximum(0).std.Maximum(0)#.std.Maximum(0)#.std.Maximum(0)#.std.Maximum(0)#.std.Minimum(0) debd = bbf.deband_2pass(nr16) w = 1920 h = 1080 oaa_y = core.std.ShufflePlanes(nr16, 0, vs.GRAY) aa_y = core.eedi2.EEDI2(oaa_y,field=1,mthresh=10,lthresh=20,vthresh=20,maxd=24,nt=50).fmtc.resample(w,h,sy=-0.5, kernel='bicubic', a1=0, a2=0.5,).std.Transpose() aa_y = core.eedi2.EEDI2(aa_y,field=1,mthresh=10,lthresh=20,vthresh=20,maxd=24,nt=50).fmtc.resample(h,w,sy=-0.5, kernel='bicubic', a1=0, a2=0.5,).std.Transpose() aa_clip = core.std.ShufflePlanes([aa_y,debd], [0,1,2], vs.YUV) aaed = core.std.MaskedMerge(debd, aa_clip, aamask, 0, True) aaed = core.std.MaskedMerge(aaed, debd, textmask, 0, False) dif = core.std.MakeDiff(aaed, core.rgvs.RemoveGrain(aaed,20)) sharp = core.std.MergeDiff(aaed, dif) sharped = core.std.MaskedMerge(sharp, aaed, eemask, [0,1,2], False) noise16 = core.std.Expr(noise16,["x 32768 - 1.05 * 32768 +",""]) nullclip = core.std.Expr(src16,["32768",""]) nrweight = core.std.Expr(pre8, ["x 48 - 0 max dup * 5 * ",""], vs.YUV420P16) noise16 = core.std.MaskedMerge(noise16,nullclip,nrweight,0,True) res = core.std.MergeDiff(sharped,noise16,0) return res
def retinex_edgemask(src: vs.VideoNode, sigma=1, draft=False) -> vs.VideoNode: core = vs.core import mvsfunc as mvf src = mvf.Depth(src, 16) luma = mvf.GetPlane(src, 0) if draft: ret = core.std.Expr(luma, 'x 65535 / sqrt 65535 *') else: ret = core.retinex.MSRCP(luma, sigma=[50, 200, 350], upper_thr=0.005) mask = core.std.Expr([ kirsch(luma), ret.tcanny.TCanny(mode=1, sigma=sigma).std.Minimum( coordinates=[1, 0, 1, 0, 0, 1, 0, 1]) ], 'x y +') return mask
import sys sys.path.append("/usr/local/share/vsscripts") import vapoursynth as vs import math core = vs.get_core(threads=20) import mvsfunc as mvf import havsfunc as haf import CSMOD as cs ret = core.lsmas.LWLibavSource( source= "/opt/How.to.Train.Your.Dragon.The.Hidden.World.2019.1080p.BluRay.x264.TrueHD.7.1.Atmos-FGT.mkv", format="YUV420P16") # #ret = core.ffms2.Source(source=r'H:\115download\509 Blood Money\BDMV\STREAM\00000.m2ts') #ret = core.std.CropRel(ret, left=0, right=0, top=138, bottom=138) ret = mvf.Depth(ret, depth=16) ret = haf.SMDegrain(input=ret, tr=3, contrasharp=30) # plane=3 ,contrasharp=30 # ret = core.knlm.KNLMeansCL(clip=ret,d = 1, a = 4, h = 2,device_type="cpu") # ret = mvf.BM3D(ret, sigma=[10,10,10], radius1=1) # ret =cs.CSMOD(ret,preset = "medium",strength=16)#, edgemode=1 ret = haf.LSFmod(ret, strength=10) # ret = core.f3kdb.Deband(ret,output_depth=16) # ret = mvf.Depth(ret, depth=10) ret.set_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 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 down_8(self): self.process_depth = 8 self.aa_clip = mvf.Depth(self.aa_clip, 8)
prefix = 'train' suffix = '.h5' labelOutput = prefix + '_label' + suffix dataOutput = prefix + '_data' + suffix data = '00003.mp4' # Edit it to your video source label = '00003.m2ts' dataDim = 80 padDim = 6 # Actually 6 on each side paddedDim = dataDim + 2 * padDim # Get source and extract Y core = vs.get_core() dataClip = mvf.Depth(core.lsmas.LWLibavSource(data), 32).std.ShufflePlanes(0, vs.GRAY) labelClip = mvf.Depth(core.lsmas.LWLibavSource(label), 32).std.ShufflePlanes(0, vs.GRAY) assert isinstance(dataClip, vs.VideoNode) assert isinstance(labelClip, vs.VideoNode) assert labelClip.num_frames == dataClip.num_frames assert dataClip.height == labelClip.height assert dataClip.width == labelClip.width frameNum = dataClip.num_frames frame_h = dataClip.height frame_w = dataClip.width sampleFrameNum = 5000 samplePerFrame = 10 sampleNum = sampleFrameNum * samplePerFrame assert labelClip.num_frames >= sampleFrameNum
def fade_text_mask(src, lthr=225, cthr=2, expand=2, fade_nums=8, apply_range=None): """ A very very simple textmask creating function to handle fading text on screen Version: 0.2.0 :param src: source clip, vs.YUV :param lthr: <int> threshold of luma in 8bit scale. Default:225 :param cthr: <int> threshold of chroma in 8bit scale. Default:2 :param expand: <int> times of expansion of textmask. Default:2 :param fade_nums: <int, list or tuple> the length of fading. Use list or tuple to specify fade-in and fade-out separately. Default:8 :param apply_range: <list or tuple> range of src clip to apply mask. :return: mask clip, vs.GRAY """ core = vs.get_core() depth = src.format.bits_per_sample color_family = src.format.color_family w = src.width h = src.height func_name = 'Fade Text Mask' if not isinstance(src, vs.VideoNode): raise TypeError(func_name + ': src is not a video clip.') if color_family is not vs.YUV: raise TypeError(func_name + ': src should be a YUV clip.') if depth > 8: src = mvf.Depth(src, 8) y = core.std.ShufflePlanes(src, 0, vs.GRAY) u = core.std.ShufflePlanes(src, 1, vs.GRAY) v = core.std.ShufflePlanes(src, 2, vs.GRAY) try: u = core.resize.Bicubic(u, w, h, src_left=0.25) v = core.resize.Bicubic(v, w, h, src_left=0.25) except vs.Error: u = mvf.Depth(core.fmtc.resample(u, w, h, sx=0.25), 8) v = mvf.Depth(core.fmtc.resample(v, w, h, sx=0.25), 8) expr = "x {lthr} > y 128 - abs {cthr} < and z 128 - abs {cthr} < and 255 0 ?".format( lthr=lthr, cthr=cthr) tmask = core.std.Expr([y, u, v], expr) if expand > 1: for i in range(expand): tmask = core.std.Maximum(tmask) frame_count = src.num_frames def shift_backward(n, clip, num): if n + num > frame_count - 1: return clip[frame_count - 1] else: return clip[n + num] def shift_forward(n, clip, num): if n - num < 0: return clip[0] else: return clip[n - num] if isinstance(fade_nums, int): in_num = fade_nums out_num = fade_nums elif isinstance(fade_nums, (list, tuple)): if len(fade_nums) != 2: raise ValueError(func_name + ': incorrect fade_nums setting.') in_num = fade_nums[0] out_num = fade_nums[1] else: raise TypeError(func_name + ': fade_num can only be int, list or tuple.') fade_in = core.std.FrameEval( tmask, functools.partial(shift_backward, clip=tmask, num=in_num)) fade_out = core.std.FrameEval( tmask, functools.partial(shift_forward, clip=tmask, num=out_num)) combined = core.std.Expr([tmask, fade_in, fade_out], "x y max z max") if apply_range is not None: if not isinstance(apply_range, (list, tuple)): raise TypeError(func_name + ': apply range can only be list or tuple') elif len(apply_range) != 2: raise ValueError(func_name + ': incorrect apply range setting.') else: try: blank_clip = core.std.BlankClip(tmask) if 0 in apply_range: combined = combined[apply_range[0]:apply_range[ 1]] + blank_clip[apply_range[1]:] elif frame_count in apply_range: combined = blank_clip[0:apply_range[0]] + combined[ apply_range[0]:apply_range[1]] else: combined = (blank_clip[0:apply_range[0]] + combined[apply_range[0]:apply_range[1]] + blank_clip[apply_range[1]:]) except vs.Error: raise ValueError( func_name + ': incorrect apply range setting. Possible end less than start.' ) if depth > 8: scale = ((1 << depth) - 1) // 255 out_depth = "vs.GRAY{out_depth}".format(out_depth=depth) combined = core.std.Expr(combined, "x " + str(scale) + " *", eval(out_depth)) return combined
def __init__(self, clip, **kwargs): super(FadeTextMask, self).__init__(clip) self.clip = mvf.Depth(clip, 8) self.lthr = kwargs.get('lthr', 225) self.cthr = kwargs.get('cthr', 2) self.mexpand = kwargs.get('expand', 2) self.fade_nums = kwargs.get('fade_num', 8) self.apply_range = kwargs.get('apply_range', None) if self.clip_color_family is not vs.YUV: raise TypeError(MODULE_NAME + ': clip should be a YUV clip') y = self.core.std.ShufflePlanes(self.clip, 0, vs.GRAY) u = self.core.std.ShufflePlanes(self.clip, 1, vs.GRAY) v = self.core.std.ShufflePlanes(self.clip, 2, vs.GRAY) try: u = self.core.resize.Bicubic(u, self.clip_width, self.clip_height, src_left=0.25) v = self.core.resize.Bicubic(v, self.clip_width, self.clip_height, src_left=0.25) except vs.Error: u = mvf.Depth( self.core.fmtc.resample(u, self.clip_width, self.clip_height, sx=0.25), 8) v = mvf.Depth( self.core.fmtc.resample(v, self.clip_width, self.clip_height, sx=0.25), 8) expr = "x {lthr} > y 128 - abs {cthr} < and z 128 - abs {cthr} < and 255 0 ?".format( lthr=self.lthr, cthr=self.cthr) self.mask = self.core.std.Expr([y, u, v], expr) if self.mexpand > 0: self.expand(self.mexpand) frame_count = self.clip.num_frames def shift_backward(n, clip, num): if n + num > frame_count - 1: return clip[frame_count - 1] else: return clip[n + num] def shift_forward(n, clip, num): if n - num < 0: return clip[0] else: return clip[n - num] if isinstance(self.fade_nums, int): in_num = self.fade_nums out_num = self.fade_nums elif isinstance(self.fade_nums, (list, tuple)): if len(self.fade_nums) != 2: raise ValueError(MODULE_NAME + ': incorrect fade_nums setting.') in_num = self.fade_nums[0] out_num = self.fade_nums[1] else: raise TypeError(MODULE_NAME + ': fade_num can only be int, tuple or list.') if self.fade_nums is not 0: fade_in = self.core.std.FrameEval( self.mask, functools.partial(shift_backward, clip=self.mask, num=in_num)) fade_out = self.core.std.FrameEval( self.mask, functools.partial(shift_forward, clip=self.mask, num=out_num)) self.mask = self.core.std.Expr([self.mask, fade_in, fade_out], " x y max z max") if self.apply_range is not None: if not isinstance(self.apply_range, (list, tuple)): raise TypeError(MODULE_NAME + ': apply range can only be list or tuple.') elif len(self.apply_range) != 2: raise ValueError(MODULE_NAME + ': incorrect apply range setting.') else: try: blank_clip = self.core.std.BlankClip(self.mask) if 0 in self.apply_range: self.mask = self.mask[self.apply_range[0]:self.apply_range[1]] + \ blank_clip[self.apply_range[1]:] elif frame_count in self.apply_range: self.mask = blank_clip[0:self.apply_range[0]] + \ self.mask[self.apply_range[0]:self.apply_range[1]] else: self.mask = blank_clip[0:self.apply_range[0]] + \ self.mask[self.apply_range[0]:self.apply_range[1]] + \ blank_clip[self.apply_range[1]:] except vs.Error: raise ValueError( MODULE_NAME + ': incorrect apply range setting. Possible end less than start.' )
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 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
scale = 2 linear_scale = False upfilter = 'bicubic' # data = '00003.m2ts' data = r'I:\Anime\The Garden of Words\BDROM\BDMV\STREAM\00000.m2ts' data_dim = 41 planes = 3 if useRGB else 1 # Get source and do format conversion core = vs.get_core() label_clip = core.lsmas.LWLibavSource(data) if useRGB: label_clip = mvf.ToRGB(label_clip, depth=32) else: label_clip = mvf.Depth(label_clip.std.ShufflePlanes(0, vs.GRAY), 32) # Prepare data down_lists = list(range(1, 8)) data_clip = core.std.Interleave([ resample(label_clip, scale, linear_scale, d, upfilter) for d in down_lists ]) label_clip = core.std.Interleave([label_clip for d in down_lists]) w = data_clip.width h = data_clip.height nb_frame = data_clip.num_frames assert w == label_clip.width assert h == label_clip.height assert nb_frame == label_clip.num_frames
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 GPA(clip, sigmaS=3, sigmaR=0.15, mode=0, iteration=0, eps=1e-3, **depth_args): """Fast and Accurate Bilateral Filtering using Gaussian-Polynomial Approximation This filter approximates the bilateral filter when the range kernel is Gaussian. The exponential function of the weight function of bilateral filter is approximated, and the bilateral is therefore decomposed into a series of spatial convolutions. The number of iteration depends on the value of "sigmaR", which increases as "sigmaR" decreases. A small value of "sigmaR" may lead to presicion problem. All the internal calculations are done at 32-bit float. Part of description of bilateral filter is copied from https://github.com/HomeOfVapourSynthEvolution/VapourSynth-Bilateral Args: clip: Input clip. sigmaS: (float) Sigma of Gaussian function to calculate spatial weight. The scale of this parameter is equivalent to pixel distance. Larger sigmaS results in larger filtering radius as well as stronger smoothing. Default is 3. sigmaR: (float) Sigma of Gaussian function to calculate range weight. The scale of this parameter is the same as pixel value ranging in [0,1]. Smaller sigmaR preserves edges better, may also leads to weaker smoothing. It should be pointed out that a small "sigmaR" results in more iteration and higher error. Default is 0.15. mode: (0 or 1) 0: Guassian bilateral filter, 1: Box bilateral filter Default is 0. iteration: (int) Number of iteration or the order of approximation. If it is 0, it is calculated automatically according to "sigmaR" and "eps". Default is 0. eps: (float) Filtering Accuracy. Default is 1e-3. depth_args: (dict) Additional arguments passed to mvf.Depth(). Default is {}. Ref: [1] Chaudhury, K. N., & Dabhade, S. D. (2016). Fast and provably accurate bilateral filtering. IEEE Transactions on Image Processing, 25(6), 2519-2528. [2] http://www.mathworks.com/matlabcentral/fileexchange/56158 """ def estimate_iteration(sigmaR, T, eps): if sigmaR > 70: return 10 elif sigmaR < 5: return 800 else: lam = (T / sigmaR) ** 2 p = 1 + math.log(lam) q = -lam - math.log(eps) t = q / math.e / lam W = t - t ** 2 + 1.5 * t ** 3 - (8 / 3) * t ** 4 N = min(max(q / W, 10), 300) if sigmaR < 30: for i in range(5): N -= (N * math.log(N) - p * N - q) / (math.log(N) + 1 - p) return math.ceil(N) T = 0.5 bits = clip.format.bits_per_sample sampleType = clip.format.sample_type if mode == 0: # Gaussian bilateral filter Filter = functools.partial(core.tcanny.TCanny, sigma=sigmaS, mode=-1) else: # Box bilateral filter Filter = functools.partial(muf.BoxFilter, radius=sigmaS + 1) if iteration == 0: iteration = estimate_iteration(sigmaR * 255, T, eps) clip = mvf.Depth(clip, depth=32, sample=vs.FLOAT, **depth_args) H = core.std.Expr(clip, f'x {T} - {sigmaR} /') F = core.std.Expr(H, '-0.5 x dup * * exp') G = core.std.BlankClip(clip, color=[1] * clip.format.num_planes) P = core.std.BlankClip(clip, color=[0] * clip.format.num_planes) Q = core.std.BlankClip(clip, color=[0] * clip.format.num_planes) Fbar = Filter(F) for i in range(1, iteration+1): sqrt_i = math.sqrt(i) inv_sqrt_i = 1 / sqrt_i Q = core.std.Expr([Q, G, Fbar], 'x y z * +') F = core.std.Expr([H, F], f'x y * {inv_sqrt_i} *') Fbar = Filter(F) P = core.std.Expr([P, G, Fbar], f'x y z * {sqrt_i} * +') G = core.std.Expr([H, G], f'x y * {inv_sqrt_i} *') res = core.std.Expr([P, Q], f'x {sigmaR} * y 1e-5 + / {T} +') return mvf.Depth(res, depth=bits, sample=sampleType, **depth_args)
def nnedi3_dh(input, field=1, nsize=None, nns=None, qual=None, etype=None, pscrn=None, device=None, fast=None, flat_kernel=None, flat_a1=None, flat_a2=None, flat_taps=None): core = vs.core sFormat = input.format sSType = sFormat.sample_type sbitPS = sFormat.bits_per_sample sVSubS = 1 << sFormat.subsampling_h if fast is None: fast = False if flat_kernel is None: flat_kernel = "nnedi3" else: flat_kernel = flat_kernel.lower() if (field == 0 or field == 1) and ((fast and sbitPS > 8)): if flat_kernel == "nnedi3": flat_kernel = "bicubic" input8 = mvf.Depth(input, depth=8, sample=vs.INTEGER) nn = core.nnedi3cl.NNEDI3CL(input8, field=field, dh=True, nsize=nsize, nns=nns, qual=qual, etype=etype, pscrn=pscrn, device=device) lr = core.fmtc.resample(input, sy=[-0.5, -0.5 * sVSubS] if field == 0 else 0, scaleh=1, scalev=2, kernel=flat_kernel, a1=flat_a1, a2=flat_a2, taps=flat_taps, center=False) return mvf.LimitFilter(mvf.Depth(lr, depth=sbitPS, sample=sSType), mvf.Depth(nn, depth=sbitPS, sample=sSType), thr=1.0, elast=2.0) elif flat_kernel == "nnedi3": return core.nnedi3cl.NNEDI3CL(input, field=field, dh=True, nsize=nsize, nns=nns, qual=qual, etype=etype, pscrn=pscrn, device=device) else: nn = core.nnedi3cl.NNEDI3CL(input, field=field, dh=True, nsize=nsize, nns=nns, qual=qual, etype=etype, pscrn=pscrn, device=device) lr = core.fmtc.resample(input, sy=[-0.5, -0.5 * sVSubS] if field == 0 else 0, scaleh=1, scalev=2, kernel=flat_kernel, a1=flat_a1, a2=flat_a2, taps=flat_taps, center=False) return mvf.LimitFilter(mvf.Depth(lr, depth=sbitPS, sample=sSType), mvf.Depth(nn, depth=sbitPS, sample=sSType), thr=1.0, elast=2.0)
def mts(src): src8 = mvf.ToYUV(src, css='420') src16 = core.fmtc.bitdepth(src8,bits=16) # Denoise src_rgb = mvf.ToRGB(src16,depth=32) #nr16_rgb = core.pdn.BM3DBasic(src_rgb, sigma=[0.5, 0.2, 0.2],group_size=16, bm_range=8) nr16_rgb = core.pdn.BM3DBasic(src_rgb, sigma=[1.0, 0.5, 0.5]) nr16 = mvf.ToYUV(nr16_rgb, css="420",depth=16) noise16 = core.std.MakeDiff(src16, nr16) # Mask pre16 = core.std.ShufflePlanes([nr16,src16],[0,1,2],vs.YUV) pre8 = mvf.Depth(pre16, depth=8, dither=5) eemask = core.tcanny.TCanny(pre8,sigma=0.6,op=2,gmmax=255,planes=[0,1,2],mode=1) eemask_u = core.std.ShufflePlanes(eemask, [1,1,1], vs.YUV).fmtc.resample(1920,1080,sx=0.25,css="420") eemask_v = core.std.ShufflePlanes(eemask, [2,2,2], vs.YUV).fmtc.resample(1920,1080,sx=0.25,css="420") weighted = core.std.Expr([eemask,eemask_u,eemask_v],["x 64 * y + z +",""],vs.YUV420P16) luma = core.std.ShufflePlanes(pre8, 0, vs.YUV).resize.Bilinear(format=vs.YUV420P8) eemask = core.std.Expr([eemask,luma],["x x * 20 * 255 y - dup * 0.2 * + 50000 min","x x * 30 * 255 y - dup * 0.3 * + 60000 min"],vs.YUV420P16) eemask = core.std.Maximum(eemask,planes=[0,1,2]) eemask = core.rgvs.RemoveGrain(eemask, [20,11]).rgvs.RemoveGrain([20,11]).rgvs.RemoveGrain([20,11]) aamask = core.std.Binarize(weighted, 12000, 0) nrmasks = core.std.Binarize(weighted, 4500, 0) dmaskb = core.std.Binarize(weighted, 3000, 0) dmaskm = core.std.Binarize(weighted, 3500, 0) dmasks = core.std.Binarize(weighted, 3800, 0) dmask_dark = core.misc.Hysteresis(dmaskm, dmaskb) dmask_bright = core.misc.Hysteresis(dmasks, dmaskm) dmask = core.std.Expr([src16, dmask_dark, dmask_bright], "x 24672 < y z ?") nrmaskg = core.tcanny.TCanny(pre8,sigma=1.5,t_l=8,t_h=15,op=2,planes=0) nrmaskb = core.tcanny.TCanny(pre8,sigma=1.2,t_l=8,t_h=11,op=2,planes=0) nrmask = core.std.Expr([nrmaskg,nrmaskb,nrmasks,pre8,dmask],["a 20 < 65535 a 64 < x 257 * b max a 160 < y 257 * z ? ? ?","",""],vs.YUV420P16) nrmask = core.std.Maximum(nrmask,0).std.Maximum(0).std.Minimum(0).std.Minimum(0) nrmask = core.rgvs.RemoveGrain(core.rgvs.RemoveGrain(nrmask,[20,0]),[20,0]) Y = core.std.ShufflePlanes(src16, 0, vs.YUV).resize.Bicubic(1920, 1080, format=vs.YUV420P16, filter_param_a=0, filter_param_b=0.5) U = core.std.ShufflePlanes(src16, [1,1,1], vs.YUV).resize.Bicubic(1920, 1080, format=vs.YUV420P16, filter_param_a=0, filter_param_b=0.5) V = core.std.ShufflePlanes(src16, [2,2,2], vs.YUV).resize.Bicubic(1920, 1080, format=vs.YUV420P16, filter_param_a=0, filter_param_b=0.5) textmask0 = core.std.Expr([Y,U,V], ["x 60000 > y 32768 - abs 768 < and z 32768 - abs 768 < and 65535 0 ?","0"]) #textmasks = core.std.Expr([Y,U,V], ["x 58000 > y 32768 - abs 512 < and z 32768 - abs 512 < and 65535 0 ?","0"]) textmask1 = core.std.Minimum(textmask0, 0).std.Minimum(planes=0).std.Minimum(planes=0).std.Maximum(0).std.Maximum(0).std.Maximum(0) textmask2 = core.misc.Hysteresis(textmask1, textmask0, planes=0) textmask = core.std.Expr([textmask0, textmask2], "x y > x 0 ?") #textmask = core.misc.Hysteresis(textmasks, textmaskb, planes=0) textmask = core.std.Maximum(textmask,0).std.Maximum(0).std.Maximum(0)#.std.Maximum(0)#.std.Maximum(0)#.std.Maximum(0)#.std.Minimum(0) debd = core.f3kdb.Deband(nr16,8,48,32,32,0,0,output_depth=16) debd = core.f3kdb.Deband(debd,15,32,24,24,0,0,output_depth=16) debd = mvf.LimitFilter(debd,nr16,thr=0.7,thrc=0.5,elast=2.0) debd = core.std.MaskedMerge(debd, nr16, nrmask, first_plane=1) w = 1920 h = 1080 oaa_y = core.std.ShufflePlanes(nr16, 0, vs.GRAY) aa_y = core.eedi2.EEDI2(oaa_y,field=1,mthresh=10,lthresh=20,vthresh=20,maxd=24,nt=50).fmtc.resample(w,h,sy=-0.5, kernel='bicubic', a1=0, a2=0.5,).std.Transpose() aa_y = core.eedi2.EEDI2(aa_y,field=1,mthresh=10,lthresh=20,vthresh=20,maxd=24,nt=50).fmtc.resample(h,w,sy=-0.5, kernel='bicubic', a1=0, a2=0.5,).std.Transpose() aa_clip = core.std.ShufflePlanes([aa_y,nr16], [0,1,2], vs.YUV) aaed = core.std.MaskedMerge(debd, aa_clip, aamask, 0, True) aaed = core.std.MaskedMerge(aaed, debd, textmask, 0, False) dif = core.std.MakeDiff(aaed, core.rgvs.RemoveGrain(aaed,20)) sharp = core.std.MergeDiff(aaed, dif) sharped = core.std.MaskedMerge(sharp, aaed, eemask, [0,1,2], False) noise16 = core.std.Expr(noise16,["x 32768 - 1.05 * 32768 +",""]) nullclip = core.std.Expr(src16,["32768",""]) nrweight = core.std.Expr(pre8, ["x 48 - 0 max dup * 5 * ",""], vs.YUV420P16) noise16 = core.std.MaskedMerge(noise16,nullclip,nrweight,0,True) res = core.std.MergeDiff(sharped,noise16,0) return res
## 2x.vpy import vapoursynth as vs import mvsfunc as mvf sourceFile = r"*.mp4" core = vs.get_core(threads = 12) core.max_cache_size = 8000 src = core.ffms2.Source(source = sourceFile) src = mvf.Depth(src, depth = 32) block_w = src.width / 10 block_h = src.height / 10 src = core.caffe.Waifu2x( clip = src, noise = 3, scale = 2, block_w = block_w, block_h = block_h, model = 6, cudnn = True, tta = False, batch = 1) src = mvf.ToYUV(src, full = False, depth = 8, css = "420", matrix = 1) src.set_output()