Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import vapoursynth as vs
- import math
- from vapoursynth import core
- from functools import partial
- def logic(clipa, clipb=None, mode='and', min=None, max=None, bits=None, flt=None, planes=None):
- """
- mt_logic with some modifications
- Changing the output format crashes VS Editor whenever I try it so... buyer beware and all that.
- Works on single clips when clipb is an integer, float, or string ('pi', 'e', 'tau')
- New parameters 'min' and 'max' can be used to clip the final output
- 'max' default to the maximum allowed value when output is an integer format to avoid overflows with depths between 8 and 16
- this isn't strictly necessary, just a safety check since it will crash if you try to preview it
- mode='andn' still has its arguments flipped (binary 'clipb and not clipa'), mostly for backward compatibility
- ~~~New modes for one or more clips~~~
- dif - return abs(clipa - clipb)
- add/sub/mul/div/pow/root/log - for simple math operations
- ~~~New modes for a single clip only~~~
- sqrt - equal to std.Expr('x 255 / sqrt 255 *')
- sin/cos/tan/asin/acos/atan - for trigonometric approximations
- This always uses std.Lut/std.Lut2 so everything is pre-calculated with very high precision
- The exact order things happen are as follows, simplified so you can understand it without understanding lookup tables:
- clipb = Depth(clipb, bits=clipa.bits_per_sample) # no actual processing on the clip
- lut = mode_function(clipa, clipb) # float processing in integer space
- clmp = clamp(lut, min, max) # limit values if specified
- return Depth(clmp, bits=bits, dither_type='none') # round to target bit depth & sample type
- """
- def fill_lut(clipa, clipb, mode, bits, bitsa, bitsb, full, chroma, flt):
- scaleo = partial(scalef if full else scalebc if chroma else scaleb, i=bitsa, o=bits, f=flt)
- scaley = partial(scalef if full else scalebc if chroma else scaleb, i=bitsb, o=bitsa, f=False)
- setnumfmt = float if flt else round
- func = get_func(mode, bits, flt)
- lut = []
- if isinstance(clipb, vs.VideoNode):
- for y in range(2 ** bitsb):
- for x in range(2 ** bitsa):
- lut.append(setnumfmt(clamp_value(scaleo(func(x, scaley(y))), mi, ma)))
- else:
- if isinstance(clipb, str):
- clipb = clipb.lower()
- clipb = math.pi if clipb in ('π', 'pi') else e if clipb=='e' else math.tau
- clipb = (1<<bitsa)-1 if mode == 'sqrt' else clipb
- for x in range(2 ** bitsa):
- lut.append(setnumfmt(clamp_value(scaleo(func(x, clipb)), mi, ma)))
- return lut
- f = clipa.format
- bitsa = f.bits_per_sample
- bitsb = None if not isinstance(clipb, vs.VideoNode) else clipb.format.bits_per_sample
- numplanes = f.num_planes
- mode = mode.lower()
- full = f.color_family in (vs.RGB, vs.YCOCG)
- planes = list(range(numplanes)) if planes is None else [planes] if isinstance(planes, int) else planes
- bits = bitsa if bits is None else bits
- flt = True if bits==32 else flt if flt is not None else False
- mi = min
- ma = max
- if not flt:
- mi = max(mi, 0) if mi is not None else 0
- ma = min(ma, (1<<bits)-1) if ma is not None else (1<<bits)-1
- lut = fill_lut(clipa, clipb, mode, bits, bitsa, bitsb, full, False, flt)
- lutc = fill_lut(clipa, clipb, mode, bits, bitsa, bitsb, full, True, flt)
- args = dict(bits=bits, floatout=flt)
- split = False
- for i in range(len(lut)):
- if lut[i] != lutc[i]:
- split = True
- if split and 0 in planes and any_of(planes, '>', 0):
- if isinstance(clipb, vs.VideoNode):
- clipa = core.std.Lut2(clipa, clipb, 0, lut, **args)
- return core.std.Lut2(clipa, clipb, planes.remove(0), lutc, **args)
- else:
- clipa = core.std.Lut(clipa, 0, lut, **args)
- return core.std.Lut(clipa, planes.remove(0), lutc, **args)
- else:
- if isinstance(clipb, vs.VideoNode):
- return core.std.Lut2(clipa, clipb, planes, lut, **args)
- else:
- return core.std.Lut(clipa, planes, lut, **args)
- #Internal
- def clamp_value(val, mi, ma):
- val = max(val, mi) if mi is not None else val
- return min(val, ma) if ma is not None else val
- def scalef(x, i, o, f):
- x /= (1<<i)-1
- return x if f else x * ((1<<o)-1)
- def scaleb(x, i, o, f):
- return (x - (1<<(i-4))) / (219<<(i-8)) if f else x * (1<<i) / (1<<o)
- def scalebc(x, i, o, f):
- return (x - (1<<(i-4))) / (224<<(i-8)) if f else x * (1<<i) / (1<<o)
- def add(x, y): return x + y
- def sub(x, y): return x - y
- def mul(x, y): return x * y
- def div(x, y): return x / y
- def root(x, y): return math.pow(x, 1/max(y, 1))
- def log(x, y): return math.log(x, y)
- def sin(x, y): return math.sin(x)
- def cos(x, y): return math.cos(x)
- def tan(x, y): return math.tan(x)
- def asin(x, y): return math.asin(x)
- def acos(x, y): return math.acos(x)
- def atan(x, y): return math.atan(x)
- def sqrt(x, y, z): return math.sqrt(x / y) if z is None else math.sqrt(x / y) * z
- def dif(x, y): return abs(x - y)
- def avg(x, y): return (x + y)/2
- def get_max(x, y): return max(x, y)
- def get_min(x, y): return min(x, y)
- def bitwise_and(x, y): return x & y
- def bitwise_or(x, y): return x | y
- def bitwise_xor(x, y): return x ^ y
- def bitwise_andnot(x, y):
- x, y = list(bin(y))[2:], list(bin(x))[2:]
- while len(x) > len(y):
- y.insert(0, '0')
- while len(x) < len(y):
- x.insert(0, '0')
- out = '0b'
- for i in range(len(x)):
- out += '1' if (x[i], y[i]) == ('1', '0') else '0'
- return int(out, base=2)
- def any_of(arr, mode, val):
- def ts(x, m, y): return x in y if m=='in' else x not in y if mode=='not in' else isinstance(x, y) if mode=='isinstance' else not isinstance(x, y)
- mode = mode.lower()
- if mode in ('isinstance', 'not isinstance', 'in', 'not in'):
- for obj in arr:
- if ts(obj, mode, val):
- return True
- return False
- else:
- op_table = op_table = {'==': operator.eq, '!=': operator.ne, '>': operator.gt, '<': operator.lt, '>=': operator.ge, '<=': operator.le, 'is': operator.is_, 'is not': operator.is_not}
- return any(map(lambda x: op_table[mode](x, val), arr))
- def get_func(mode, bits, flt): return {'and': bitwise_and, '&': bitwise_and, 'or': bitwise_or, '|': bitwise_or, 'xor': bitwise_xor, '^': bitwise_xor, 'andn': bitwise_andnot, 'andnot': bitwise_andnot, 'max': get_max, 'min': get_min, 'add': add, '+': add, 'sub': sub, '-': sub, 'mul': mul, '*': mul, 'div': div, '/': div, 'exp': math.pow, 'pow': math.pow, '**': math.pow, 'root': root, 'sin': sin, 'cos': cos, 'tan': tan, 'asin': asin, 'acos': acos, 'atan': atan, 'diff': dif, 'dif': dif, 'abs': dif, 'avg': avg, 'average': avg, 'mean': avg, 'sqrt': partial(sqrt, z=None if flt else (1<<bits)-1)}.get(mode, 'and')
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement