Log in

View Full Version : vmulti/compensateMulti/degrainN/writevec/readvec for vsmvtools


feisty2
23rd May 2015, 13:35
def getvectors (src, supersearch, tr=6, pel=4, dct=5, thsad=400):
core = vs.get_core ()
supersoft = core.mv.Super (src, pel=pel, chroma=False, hpad=32, vpad=32, pelclip=supersearch, sharp=2, rfilter=4, levels=0)
supersharp = core.mv.Super (src, pel=pel, chroma=False, hpad=32, vpad=32, pelclip=supersearch, sharp=2, rfilter=2, levels=0)
def search (isb, delta):
vectors = core.mv.Analyse (supersoft, isb=isb, overlap=16, blksize=32, search=3, chroma=False, truemotion=True, delta=delta, trymany=True, searchparam=16, pelsearch=16, dct=0, levels=0, divide=2, badrange=-24)
vectors = core.mv.Recalculate (supersoft, vectors, overlap=8, blksize=16, thsad=thsad//2, chroma=False, truemotion=True, search=3, searchparam=16, dct=dct, smooth=1, divide=2)
vectors = core.mv.Recalculate (supersharp, vectors, overlap=4, blksize=8, thsad=thsad//2, chroma=False, truemotion=True, search=3, searchparam=16, dct=dct, smooth=1, divide=2)
vectors = core.mv.Recalculate (supersharp, vectors, overlap=2, blksize=4, thsad=thsad//2, chroma=False, truemotion=True, search=3, searchparam=16, dct=dct, smooth=1, divide=0)
return vectors
bv = [search (True, i) for i in range (tr, 0, -1)]
fv = [search (False, i) for i in range (1, tr+1)]
vmulti = bv + fv
vmulti = core.std.Interleave (vmulti)
return vmulti

def compensatemulti (src, comp, superclip, vmulti, tr=6, pel=4, thsad=400, thscd1=248, thscd2=130):
core = vs.get_core ()
super = core.mv.Super (comp, pel=pel, chroma=False, hpad=32, vpad=32, pelclip=superclip, sharp=2, rfilter=2, levels=0)
def compensate (delta):
vectors = core.std.SelectEvery (vmulti, tr*2, delta)
filter = core.mv.Compensate (src, super, vectors, thsad=thsad, thscd1=thscd1, thscd2=thscd2)
return filter
bcomp = [compensate (i) for i in range (0, tr)]
fcomp = [compensate (i) for i in range (tr, 2*tr)]
compmulti = bcomp + [src] + fcomp
compmulti = core.std.Interleave (compmulti)
return compmulti

def degrainn (src, comp, superclip, vmulti, tr=6, pel=4, thsad=400, thscd1=248, thscd2=130, full=True):
core = vs.get_core ()
super = core.mv.Super (comp, pel=pel, chroma=False, hpad=32, vpad=32, pelclip=superclip, sharp=2, rfilter=2, levels=0)
def MDG1 (a):
bv = core.std.SelectEvery (vmulti, tr*2, tr-1-a)
fv = core.std.SelectEvery (vmulti, tr*2, tr+a)
MDG = core.mv.Degrain1 (src, super, bv, fv, thsad=thsad, thscd1=thscd1, thscd2=thscd2, plane=0)
return MDG
MDGMulti = [MDG1 (i) for i in range (0, tr)]
MDGMulti = core.fmtc.bitdepth (core.std.Interleave (MDGMulti), bits=32, flt=True, fulls=full, fulld=full, dmode=1)
def MDGMerge (start=None, a=2):
start = core.std.Merge (core.std.SelectEvery (MDGMulti, tr, 0), core.std.SelectEvery (MDGMulti, tr, 1), 0.5) if start is None else start
merge = core.std.Merge (start, core.std.SelectEvery (MDGMulti, tr, a), 1/(a+1))
a = a+1
clip = merge if a == tr else MDGMerge (start=merge, a=a)
return clip
return MDGMerge ()

def writevec (vec, logout):
core = vs.get_core ()
w = vec.get_frame (0).width
with open (logout, "w") as f:
print (w, file=f)
vec = core.std.CropAbs (vec, width=w, height=1)
return vec

def readvec (vec, login):
core = vs.get_core ()
with open (login, "r") as f:
w = int (f.readline ())
vec = core.raws.Source (vec, w, 1, src_fmt="Y8")
return vec


works with a "tr" parameter, like in avisynth mvtools
degrainN takes tr >= 3 only, go mv.Degrain1/2 if tr<3, and degrainN ain't the exact extension of degrain1/2/3, it's a more convolved (averaged) variant, but gets you very similar results compared to the original one.

writevec=MStoreVec in avisynth MVTools
readvec=MRestoreVec in avisynth MVTools

Myrsloik
23rd May 2015, 16:22
This is where you simplify the script to figure out what's causing it.

feisty2
24th May 2015, 12:03
bump after update

feisty2
25th May 2015, 06:04
update: rewrote the merging part of degrainn, it won't lose precision for nothing now

feisty2
26th May 2015, 09:17
update:
new: writevec/readvec

MonoS
26th May 2015, 12:14
I suggest you to add something like that

def writevecs(vecs, files, log):
w = vecs[0].get_frame(0).width

f = [0 for x in range(len(files))]
for numFile in range(len(files)):
f[numFile] = open(files[numFile], "wb")

for i in range(vecs[0].num_frames):
if (i+1) % 100 == 0:
print(i+1, "/", vecs[0].num_frames)

for numVec in range(len(vecs)):
frame = vecs[numVec].get_frame(i)
view = frame.get_read_array(0)

for y in range(len(view)):
f[numVec].write(view[y])

for numFile in range(len(files)):
f[numFile].close()

open (log, "w").write (repr(w))


I made a little test and this gave me about 2x speedup to the single write version.
I don't know how to optimize python code, but maybe it can be further improved.

The function seems to works properly, tried saving the vector file with the single file version, reading it with rawsource and saving 4 vector files using this function [if you try to compare it saving the vector twice you get different md5 due to some initialized memory]

Myrsloik
26th May 2015, 12:18
Actually there's another trick you can use to make it doable with vspipe which will definitely beat any python based solution.

1. Get the width of the vector clip from the first frame
2. Use CropAbs(vector_clip, width=frame0width, height=1)
3. vspipe script.vpy vectors.bin -p

alternative 3. Use clip.output() which should also be faster at this point


The key here is that CropAbs can make a variable dimension clip have fixed dimensions (as long as the input frames are big enough to not leave blank parts in the output).

feisty2
26th May 2015, 13:15
done, looks super :)

splinter98
26th May 2015, 18:04
I'd tweak the single readvecs and writevecs to the following, you want to ensure you close the files after writing otherwise someone may have issues with too many files open (by using a context manager, the the file closes automatically when you exit the with block).


def writevec(vec, logout):
core = vs.get_core()
w = vec.get_frame(0).width
vec = core.std.CropAbs(vec, width=w, height=1)
with open(logout, "w") as f:
f.write(repr(w))
return vec

def readvec(vec, login):
core = vs.get_core()
with open(login, "r") as f:
w = int(f.read())
vec = core.raws.Source(vec, w, 1, src_fmt="Y8")
return vec


Personally I'd also swap f.write(repr(w)) with print(w, file=f) as then you get a new line in the file and f.read() with f.readline() as if the file provided is incorrect and is large you won't fill your memory with nearly as much data before int returns an error.

MonoS
26th May 2015, 19:51
Using Myrsloik suggestion i created this.
It's about 25% faster than my previous writevecs [i didn't made any test]

The resulting clip must be saved as a raw file.

ReadVecs works using the same indexes used writing.
Maybe opening the vecs file outside of the function could improve performance, i didn't made extensive testing [and don't appear to be faster than feisty2 readvec implementation]


def WriteVecs(vecs, prefix):
core = vs.get_core()

w = vecs[0].get_frame(0).width

for numVec in range(len(vecs)):
vecs[numVec] = core.std.CropAbs(vecs[numVec], width=w, height=1)

v = core.std.StackVertical(vecs)

log = open(prefix + ".len", "w")
log.write(repr(w))

return v

def ReadVecs(index, prefix, h):
core = vs.get_core()

f = open(prefix + ".len", "r")
w = int(f.read())
f.close()

vecs = core.raws.Source(prefix + ".vec", w, h, src_fmt="Y8")

v = core.std.CropAbs(vecs, y=index, height=1, width=w)

return v

feisty2
27th May 2015, 06:15
@MonoS
why putting all that extra work to make the 1xn clip mxn,:confused:

MonoS
27th May 2015, 08:46
@MonoS
why putting all that extra work to make the 1xn clip mxn,:confused:

Because i wanted an easy way to save all the vector in 1 call and have a nice speedup :D [this last one was not expected]

If you want to save only one vector clip than your method is the best [simple code, no strange modification to the clip, etc], but if you want to save more vector clips you must do it by hand and imho it's annoying

feisty2
27th May 2015, 11:31
update: degrainn always outputs float point clips now, to minimize the rounding error of the merging process

splinter98
27th May 2015, 17:54
Using Myrsloik suggestion i created this.
It's about 25% faster than my previous writevecs [i didn't made any test]

...


def WriteVecs(vecs, prefix):
core = vs.get_core()

w = vecs[0].get_frame(0).width

for numVec in range(len(vecs)):
vecs[numVec] = core.std.CropAbs(vecs[numVec], width=w, height=1)

v = core.std.StackVertical(vecs)

log = open(prefix + ".len", "w")
log.write(repr(w))

return v
...


You can squeeze even more performance out of this function by making it a little more pythonic, and also removes the mutation of vecs.


def WriteVecs(vecs, prefix):
core = vs.get_core()
w = vecs[0].width
v = core.std.StackVertical([core.std.CropAbs(vec, width=w, height=1) for vec in vecs])
with open(prefix + ".len", "w") as f:
print(w, file=f)
return v

MonoS
27th May 2015, 23:40
You can squeeze even more performance out of this function by making it a little more pythonic, and also removes the mutation of vecs.


Oh, that nice, thanks :D [i hope that my supreme skillfulness on python come through my code]

feisty2
29th May 2015, 16:17
update: fixed a "limit" bug, just found out not like in avisynth mvtools, "no limit" in mv.degrain does not stay constant as "255", actually bit depth related (2 ^ bitdepth - 1), simplified the merging expression, should run a little bit faster now

Myrsloik
29th May 2015, 16:31
update: fixed a "limit" bug, just found out not like in avisynth mvtools, "no limit" in mv.degrain does not stay constant as "255", actually bit depth related (2 ^ bitdepth - 1), simplified the merging expression, should run a little bit faster now

Generally speaking Expr is slower than anything else that does similar things. Its only advantage is that it can do things no other filter can sometimes...

start = core.std.Expr ([core.std.SelectEvery (MDGMulti, tr, 0), core.std.SelectEvery (MDGMulti, tr, 1)], ["x y + 2 /"]) if start is None else start
is faster if written as
core.std.Merge(core.std.SelectEvery (MDGMulti, tr, 0), clipb=core.std.SelectEvery (MDGMulti, tr, 1))

Likewise
merge = core.std.Expr ([start, core.std.SelectEvery (MDGMulti, tr, a)], ["x {a} * y + {a} 1 + /".format (a=a)])
can be accomplished faster by fiddling with the weight of the merge.

feisty2
30th May 2015, 06:47
update: replaced Expr with Merge, should work faster now