Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion.

Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules.

 

Go Back   Doom9's Forum > Capturing and Editing Video > VapourSynth

Reply
 
Thread Tools Search this Thread Display Modes
Old 15th January 2023, 12:02   #1  |  Link
Selur
Registered User
 
Selur's Avatar
 
Join Date: Oct 2001
Location: Germany
Posts: 7,259
Trying to port CQTGMC to Vapoursynth

I'm trying to port CQTGMC to Vapoursynth, but got a few issues:
here's what I got
Code:
# Imports
import vapoursynth as vs
import os
import sys
from typing import Optional, Union, Sequence
# getting Vapoursynth core
core = vs.core


def CQTGMC(clip: vs.VideoNode, Sharpness: float=0.25, thSAD1: int=192, thSAD2: int=320, thSAD3: int=128, thSAD4: int=320) -> vs.VideoNode:
  
  flip = core.std.FlipHorizontal(clip)
  flip = Padding(clip=clip,top=clip.width%64)
  flip = Padding(clip=clip,right=clip.height%64)
  padded = core.std.StackHorizontal([clip,flip])
  # todo: optional use nnedi3CL
  bobbed = core.znedi3.nnedi3(clip=padded, field=2)
  denoised = core.rgvs.RemoveGrain(clip=bobbed,mode=12)
  denoised = core.fmtc.resample(clip=denoised, kernel="gauss", w=denoised.width, h=denoised.height, scaleh=denoised.width+0.0001, interlaced=False, interlacedd=False)
  denoised = core.resize.Bicubic(clip=denoised, format=bobbed.format, dither_type="error_diffusion") # adjust format after fmtc
  denoised = core.std.Merge(clipa=denoised, clipb=bobbed,weight=0.25)
  
  srchClip = denoised
  csuper = core.mv.Super(clip=denoised);
  bvec = core.mv.Analyse(csuper,isb=True,blksize=64,overlap=32)
  fvec = core.mv.Analyse(csuper,isb=False,blksize=64,overlap=32)
  Comp1 = core.mv.Compensate(denoised,csuper,bvec,thsad=thSAD2)
  Comp2 = core.mv.Compensate(denoised,csuper,fvec,thsad=thSAD2)
  denoised = core.std.Interleave([Comp1,denoised,Comp2])
  csuper = core.mv.Super(clip=denoised)
  bvec = core.mv.Analyse(csuper,isb=True,blksize=64,overlap=32)
  fvec = core.mv.Analyse(csuper,isb=False,blksize=64,overlap=32)
  Inter = core.mv.FlowInter(denoised, csuper, bvec,fvec,blend=False)
  a = core.std.SelectEvery(clip=Inter, cycle=2, offsets=0)
  b = core.std.SelectEvery(clip=Inter, cycle=2, offsets=1)
  P = core.std.PlaneStats(srchClip, srchClip[0] + srchClip)
  N = core.std.Trim(srchClip,1)
  N = core.std.PlaneStats(N, N[0] + N)  

  srchClip = a # N < P doesn't work
  #srchClip = (N < P) ? a : b 
  
  csuper = core.mv.Super(srchClip)
  bVec1 = core.mv.Analyse(csuper,isb=True,overlap=4,delta=1)
  fVec1 = core.mv.Analyse(csuper,isb=False,overlap=4,delta=1)
  csuper = core.mv.Super(bobbed,levels=1)
  bComp1 = core.mv.Compensate(bobbed,csuper,bVec1,thsad=thSAD3)
  fComp1 = core.mv.Compensate(bobbed,csuper,fVec1,thsad=thSAD3)
  X=1 # no clue how to get field order
  Inter = core.std.Interleave([
     bobbed.std.SetFrameProp(prop="_FieldBased", intval=X).std.SeparateFields().std.SelectEvery(4,0),
     fComp1.std.SetFrameProp(prop="_FieldBased", intval=X).std.SeparateFields().std.SelectEvery(4,1),
     bComp1.std.SetFrameProp(prop="_FieldBased", intval=X).std.SeparateFields().std.SelectEvery(4,2),
     bobbed.std.SetFrameProp(prop="_FieldBased", intval=X).std.SeparateFields().std.SelectEvery(4,3)
  ])  
  weaved = core.std.DoubleWeave(Inter)[::2]
  csuper = core.mv.Super(weaved,levels=1)
  bComp1 = core.mv.Compensate(weaved, csuper, bVec1,thsad=thSAD4)
  fComp1 = core.mv.Compensate(weaved, csuper, fVec1,thsad=thSAD4)
  tMax = mt_logic(fComp1,mode="max").mt_logic(bComp1,mode="max")   # does not work, missing c1&c2 parameters
  tMin = mt_logic(fComp1,mode="min").mt_logic(bComp1,"min")    # does not work, missing c1&c2 parameters
  degrained = core.std.Degrain1(csuper,bVec1,fVec1,thsad=thSAD1)
  sharpen = mt_adddiff(degrained, mt_makediff(degrained.rgvs.RemoveGrain(mode=20)))
  sharpen = mt_clamp(sharpen,tMax,tMin,Sharpness,Sharpness,3,3)
  csuper = core.mv.Super(sharpen, levels=1)
  degrained = core.std.Degrain1(csuper,bVec1,fVec1,thsad=thSAD1)
  degrained = core.std.Crop(0,0,-(clip.width%64),-(clip.width%64))
  return degrained

def mt_adddiff(self, c1, c2, planes=[0]):
    expr = ('x y + {mid} -').format(mid=self.mid)
    expr = [(i in planes) * expr for i in range(3)]
    return self.std.Expr([c1, c2], expr)


#from dehalo_alpha.py   https://github.com/darealshinji/vapoursynth-plugins/blob/master/scripts/dehalo_alpha.py
def mt_logic(self, c1, c2, mode, th1=0, th2=0, planes=0):
    if mode == 'min':
        expr = lambda x, y: min(x + th1, y + th2)
    elif mode == 'max':
        expr = lambda x, y: max(x + th1, y + th2)
    else:
        raise InvalidArgument('%s is not a valid mode for mt_logic' % mode)
    return self.mt_lutxy(c1, c2, expr, planes)
  
# from havsfunc
def Padding(clip: vs.VideoNode, left: int = 0, right: int = 0, top: int = 0, bottom: int = 0) -> vs.VideoNode:
    if not isinstance(clip, vs.VideoNode):
        raise vs.Error('Padding: this is not a clip')

    if left < 0 or right < 0 or top < 0 or bottom < 0:
        raise vs.Error('Padding: border size to pad must not be negative')

    width = clip.width + left + right
    height = clip.height + top + bottom

    return clip.resize.Point(width, height, src_left=-left, src_top=-top, src_width=width, src_height=height)

# from havsfunc  
def mt_clamp(
    clip: vs.VideoNode,
    bright_limit: vs.VideoNode,
    dark_limit: vs.VideoNode,
    overshoot: int = 0,
    undershoot: int = 0,
    planes: Optional[Union[int, Sequence[int]]] = None,
) -> vs.VideoNode:
    if not (isinstance(clip, vs.VideoNode) and isinstance(bright_limit, vs.VideoNode) and isinstance(dark_limit, vs.VideoNode)):
        raise vs.Error('mt_clamp: this is not a clip')

    if bright_limit.format.id != clip.format.id or dark_limit.format.id != clip.format.id:
        raise vs.Error('mt_clamp: clips must have the same format')

    plane_range = range(clip.format.num_planes)

    if planes is None:
        planes = list(plane_range)
    elif isinstance(planes, int):
        planes = [planes]

    return core.std.Expr([clip, bright_limit, dark_limit], expr=[f'x y {overshoot} + min z {undershoot} - max' if i in planes else '' for i in plane_range])
Issue 1:
Code:
  a = core.std.SelectEvery(clip=Inter, cycle=2, offsets=0)
  b = core.std.SelectEvery(clip=Inter, cycle=2, offsets=1)
  P = core.std.PlaneStats(srchClip, srchClip[0] + srchClip)
  N = core.std.Trim(srchClip,1)
  N = core.std.PlaneStats(N, N[0] + N)  
  srchClip = (N < P) ? a : b
doesn't work since there is a syntax error in N < P, no clue which

Issue 2:
Code:
  Inter = core.std.Interleave([
     bobbed.std.SeparateFields().std.SelectEvery(4,0),
     fComp1.std.SeparateFields().std.SelectEvery(4,1),
     bComp1.std.SeparateFields().std.SelectEvery(4,2),
     bobbed.std.SeparateFields().std.SelectEvery(4,3)
  ])
fails since field isn't set.
I could change it to:
Code:
  X = 1
  Inter = core.std.Interleave([
     bobbed.std.SetFrameProp(prop="_FieldBased", intval=X).std.SeparateFields().std.SelectEvery(4,0),
     fComp1.std.SetFrameProp(prop="_FieldBased", intval=X).std.SeparateFields().std.SelectEvery(4,1),
     bComp1.std.SetFrameProp(prop="_FieldBased", intval=X).std.SeparateFields().std.SelectEvery(4,2),
     bobbed.std.SetFrameProp(prop="_FieldBased", intval=X).std.SeparateFields().std.SelectEvery(4,3)
  ])
but I don't know how to set X from the input clip.

Issue 3:
Code:
  tMax = mt_logic(fComp1,mode="max").mt_logic(bComp1,mode="max")
  tMin = mt_logic(fComp1,mode="min").mt_logic(bComp1,"min")
the mt_logic calls are missing c1 and c2, and I have no clue how to set them.

Would be nice if someone could help.

-----
Thanks to all that helped think I got a working (but still buggy) version https://github.com/Selur/Vapoursynth...ster/cqtgmc.py now.

Cu Selur
__________________
Hybrid here in the forum, homepage

Last edited by Selur; 8th March 2023 at 08:21.
Selur is offline   Reply With Quote
Old 15th January 2023, 12:13   #2  |  Link
kedautinh12
Registered User
 
Join Date: Jan 2018
Posts: 2,153
In issue 1, why don't change to cycle=3?
kedautinh12 is offline   Reply With Quote
Old 15th January 2023, 12:19   #3  |  Link
Selur
Registered User
 
Selur's Avatar
 
Join Date: Oct 2001
Location: Germany
Posts: 7,259
Code:
  a = core.std.SelectEvery(clip=Inter, cycle=3, offsets=0)
  b = core.std.SelectEvery(clip=Inter, cycle=3, offsets=1)
  P = core.std.PlaneStats(srchClip, srchClip[0] + srchClip)
  N = core.std.Trim(srchClip,1)
  N = core.std.PlaneStats(N, N[0] + N)
  srchClip = (N < P) ? a : b
still fails. ( suspect N&P are not int or floats,..)

Cu Selur
__________________
Hybrid here in the forum, homepage
Selur is offline   Reply With Quote
Old 16th January 2023, 09:01   #4  |  Link
kedautinh12
Registered User
 
Join Date: Jan 2018
Posts: 2,153
Quote:
Originally Posted by Selur View Post
Code:
  a = core.std.SelectEvery(clip=Inter, cycle=3, offsets=0)
  b = core.std.SelectEvery(clip=Inter, cycle=3, offsets=1)
  P = core.std.PlaneStats(srchClip, srchClip[0] + srchClip)
  N = core.std.Trim(srchClip,1)
  N = core.std.PlaneStats(N, N[0] + N)
  srchClip = (N < P) ? a : b
still fails. ( suspect N&P are not int or floats,..)

Cu Selur
can change to (maybe)
Code:
a = core.std.SelectEvery(clip=Inter, cycle=3, offsets=0)
b = core.std.SelectEvery(clip=Inter, cycle=3, offsets=1)
diffclip = core.std.PlaneStats(srchClip, srchClip[0] + srchClip)
P = f.props['PlaneStatsDiff']
N = P.core.std.Trim(srchClip,1)
def selectQTGMC(n, f):
    if N < P:
     return a
    else:
     return b

  srchClip = core.std.FrameEval(srchClip, selectQTGMC, prop_src=diffclip)
  return srchClip
kedautinh12 is offline   Reply With Quote
Old 16th January 2023, 16:18   #5  |  Link
Selur
Registered User
 
Selur's Avatar
 
Join Date: Oct 2001
Location: Germany
Posts: 7,259
Code:
P = f.props['PlaneStatsDiff']
Where does 'f' come from ?
__________________
Hybrid here in the forum, homepage

Last edited by Selur; 16th January 2023 at 16:26.
Selur is offline   Reply With Quote
Old 16th January 2023, 16:50   #6  |  Link
kedautinh12
Registered User
 
Join Date: Jan 2018
Posts: 2,153
Oh, my mistake
Code:
a = core.std.SelectEvery(clip=Inter, cycle=3, offsets=0)
b = core.std.SelectEvery(clip=Inter, cycle=3, offsets=1)
diffclip = core.std.PlaneStats(srchClip, srchClip[0] + srchClip)
def selectQTGMC(n, f):
  P = f.props['PlaneStatsDiff']
  N = P.core.std.Trim(srchClip,1)
    if N < P:
     return a
    else:
     return b

  srchClip = core.std.FrameEval(srchClip, selectQTGMC, prop_src=diffclip)
  return srchClip
kedautinh12 is offline   Reply With Quote
Old 16th January 2023, 20:17   #7  |  Link
_Al_
Registered User
 
Join Date: May 2011
Posts: 321
Code:
'''
srchClip
ScriptClip("""
P = YDifferenceFromPrevious()
N = Trim(1,0).YDifferenceFromPrevious()
N < P ? CQTGMC_A : CQTGMC_B 
""")
'''
that part might go like this:
Code:
a = core.std.SelectEvery(clip=Inter, cycle=3, offsets=0)#trusting your code
b = core.std.SelectEvery(clip=Inter, cycle=3, offsets=1)
srchClip = srchClip.std.PlaneStats(plane=0, prop='Y')
srchClip_next = srchClip[1:]+srchClip[-1:] #delete first frame and double last frame to have same frame count
srchClip_next = srchClip_next.std.PlaneStats(plane=0, prop='Y')
def Y_preference(n,f,a,b):
    if f[0].props['YAverage'] < f[0].props['YAverage']:
        return a
    else:
        return b
result = a.std.FrameEval(functools.partial(Y_preference, a=a,b=b), prop_src=[srchClip,srchClip_next])
_Al_ is offline   Reply With Quote
Old 16th January 2023, 20:38   #8  |  Link
_Al_
Registered User
 
Join Date: May 2011
Posts: 321
actually, it is just based on luma difference per pixel, so using Expr and Overlay:
Code:
srchClip_next = srchClip[1:]+srchClip[-1:] #delete first frame and double last frame to have same frame count
srchClip_Y = srchClip.std.ShufflePlanes(0, vs.GRAY)
srchClip_Y_next = srchClip_Y_next.std.ShufflePlanes(0, vs.GRAY)
mask = core.std.Expr([srchClipY, srchClip_Y_next], 'x y > 255 0 ?')#255 or max size value for bitdepth
result = havsfunc.Overlay(a, b, mask)
If it is a pixel difference, what actually YDifferenceFromPrevious() does?

Last edited by _Al_; 16th January 2023 at 20:51.
_Al_ is offline   Reply With Quote
Old 16th January 2023, 21:35   #9  |  Link
_Al_
Registered User
 
Join Date: May 2011
Posts: 321
well, isn't like this, there is two differences going and one trimming as well:
Code:
Y = srchClip.std.ShufflePlanes(0, vs.GRAY)
diffclip = core.std.PlaneStats(Y, Y[0]+Y[0:-1])
Y_trimmed =Y[1:]+Y[-1:]
diffclip_trimmed = core.std.PlaneStats(Y_trimmed,Y_trimmed[0]+Y_trimmed[0:-1])
def selectQTGMC(n, f, a, b):
    P = f[0].props['PlaneStatsDiff']
    N = f[1].props['PlaneStatsDiff']
    if N < P:
        return a
    else:
        return b
result = core.std.FrameEval(srchClip, partial(selectQTGMC,a=a,b=b), prop_src=diffclip,diffclip_trimmed)

Last edited by _Al_; 16th January 2023 at 21:42.
_Al_ is offline   Reply With Quote
Old 17th January 2023, 05:00   #10  |  Link
Selur
Registered User
 
Selur's Avatar
 
Join Date: Oct 2001
Location: Germany
Posts: 7,259
Thanks that works.
Code:
# Imports
import vapoursynth as vs
import os
import sys
from functools import partial
from typing import Optional, Union, Sequence
# getting Vapoursynth core
core = vs.core


def CQTGMC(clip: vs.VideoNode, Sharpness: float=0.25, thSAD1: int=192, thSAD2: int=320, thSAD3: int=128, thSAD4: int=320) -> vs.VideoNode:
  
  flip = core.std.FlipHorizontal(clip)
  flip = Padding(clip=clip,top=clip.width%64)
  flip = Padding(clip=clip,right=clip.height%64)
  padded = core.std.StackHorizontal([clip,flip])
  # todo: optional use nnedi3CL
  bobbed = core.znedi3.nnedi3(clip=padded, field=2)
  denoised = core.rgvs.RemoveGrain(clip=bobbed,mode=12)
  denoised = core.fmtc.resample(clip=denoised, kernel="gauss", w=denoised.width, h=denoised.height, scaleh=denoised.width+0.0001, interlaced=False, interlacedd=False)
  denoised = core.resize.Bicubic(clip=denoised, format=bobbed.format, dither_type="error_diffusion") # adjust format after fmtc
  denoised = core.std.Merge(clipa=denoised, clipb=bobbed,weight=0.25)
  
  srchClip = denoised
  csuper = core.mv.Super(clip=denoised);
  bvec = core.mv.Analyse(csuper,isb=True,blksize=64,overlap=32)
  fvec = core.mv.Analyse(csuper,isb=False,blksize=64,overlap=32)
  Comp1 = core.mv.Compensate(denoised,csuper,bvec,thsad=thSAD2)
  Comp2 = core.mv.Compensate(denoised,csuper,fvec,thsad=thSAD2)
  denoised = core.std.Interleave([Comp1,denoised,Comp2])
  csuper = core.mv.Super(clip=denoised)
  bvec = core.mv.Analyse(csuper,isb=True,blksize=64,overlap=32)
  fvec = core.mv.Analyse(csuper,isb=False,blksize=64,overlap=32)
  Inter = core.mv.FlowInter(denoised, csuper, bvec,fvec,blend=False)
  a = core.std.SelectEvery(clip=Inter, cycle=3, offsets=0)
  b = core.std.SelectEvery(clip=Inter, cycle=3, offsets=1)
  Y = srchClip.std.ShufflePlanes(0, vs.GRAY)
  diffclip = core.std.PlaneStats(Y, Y[0]+Y[0:-1])
  Y_trimmed =Y[1:]+Y[-1:]
  diffclip_trimmed = core.std.PlaneStats(Y_trimmed,Y_trimmed[0]+Y_trimmed[0:-1])
  def selectQTGMC(n, f, a, b):
    P = f[0].props['PlaneStatsDiff']
    N = f[1].props['PlaneStatsDiff']
    if N < P:
        return a
    else:
        return b

  srchClip = core.std.FrameEval(clip=srchClip, eval=partial(selectQTGMC,a=a,b=b), prop_src=diffclip, clip_src=diffclip_trimmed)
  
  csuper = core.mv.Super(srchClip)
  bVec1 = core.mv.Analyse(csuper,isb=True,overlap=4,delta=1)
  fVec1 = core.mv.Analyse(csuper,isb=False,overlap=4,delta=1)
  csuper = core.mv.Super(bobbed,levels=1)
  bComp1 = core.mv.Compensate(bobbed,csuper,bVec1,thsad=thSAD3)
  fComp1 = core.mv.Compensate(bobbed,csuper,fVec1,thsad=thSAD3)
  X=1 # no clue how to get field order
  Inter = core.std.Interleave([
     bobbed.std.SetFrameProp(prop="_FieldBased", intval=X).std.SeparateFields().std.SelectEvery(4,0),
     fComp1.std.SetFrameProp(prop="_FieldBased", intval=X).std.SeparateFields().std.SelectEvery(4,1),
     bComp1.std.SetFrameProp(prop="_FieldBased", intval=X).std.SeparateFields().std.SelectEvery(4,2),
     bobbed.std.SetFrameProp(prop="_FieldBased", intval=X).std.SeparateFields().std.SelectEvery(4,3)
  ])  
  weaved = core.std.DoubleWeave(Inter)[::2]
  csuper = core.mv.Super(weaved,levels=1)
  bComp1 = core.mv.Compensate(weaved, csuper, bVec1,thsad=thSAD4)
  fComp1 = core.mv.Compensate(weaved, csuper, fVec1,thsad=thSAD4)
  tMax = mt_logic(fComp1,mode="max").mt_logic(bComp1,mode="max")
  tMin = mt_logic(fComp1,mode="min").mt_logic(bComp1,"min")
  degrained = core.std.Degrain1(csuper,bVec1,fVec1,thsad=thSAD1)
  sharpen = mt_adddiff(degrained, mt_makediff(degrained.rgvs.RemoveGrain(mode=20)))
  sharpen = mt_clamp(sharpen,tMax,tMin,Sharpness,Sharpness,3,3)
  csuper = core.mv.Super(sharpen, levels=1)
  degrained = core.std.Degrain1(csuper,bVec1,fVec1,thsad=thSAD1)
  degrained = core.std.Crop(0,0,-(clip.width%64),-(clip.width%64))
  return degrained

def mt_adddiff(self, c1, c2, planes=[0]):
    expr = ('x y + {mid} -').format(mid=self.mid)
    expr = [(i in planes) * expr for i in range(3)]
    return self.std.Expr([c1, c2], expr)


#from dehalo_alpha.py   https://github.com/darealshinji/vapoursynth-plugins/blob/master/scripts/dehalo_alpha.py
def mt_logic(self, c1, c2, mode, th1=0, th2=0, planes=0):
    if mode == 'min':
        expr = lambda x, y: min(x + th1, y + th2)
    elif mode == 'max':
        expr = lambda x, y: max(x + th1, y + th2)
    else:
        raise InvalidArgument('%s is not a valid mode for mt_logic' % mode)
    return self.mt_lutxy(c1, c2, expr, planes)
  
# from havsfunc
def Padding(clip: vs.VideoNode, left: int = 0, right: int = 0, top: int = 0, bottom: int = 0) -> vs.VideoNode:
    if not isinstance(clip, vs.VideoNode):
        raise vs.Error('Padding: this is not a clip')

    if left < 0 or right < 0 or top < 0 or bottom < 0:
        raise vs.Error('Padding: border size to pad must not be negative')

    width = clip.width + left + right
    height = clip.height + top + bottom

    return clip.resize.Point(width, height, src_left=-left, src_top=-top, src_width=width, src_height=height)

# from havsfunc  
def mt_clamp(
    clip: vs.VideoNode,
    bright_limit: vs.VideoNode,
    dark_limit: vs.VideoNode,
    overshoot: int = 0,
    undershoot: int = 0,
    planes: Optional[Union[int, Sequence[int]]] = None,
) -> vs.VideoNode:
    if not (isinstance(clip, vs.VideoNode) and isinstance(bright_limit, vs.VideoNode) and isinstance(dark_limit, vs.VideoNode)):
        raise vs.Error('mt_clamp: this is not a clip')

    if bright_limit.format.id != clip.format.id or dark_limit.format.id != clip.format.id:
        raise vs.Error('mt_clamp: clips must have the same format')

    plane_range = range(clip.format.num_planes)

    if planes is None:
        planes = list(plane_range)
    elif isinstance(planes, int):
        planes = [planes]

    return core.std.Expr([clip, bright_limit, dark_limit], expr=[f'x y {overshoot} + min z {undershoot} - max' if i in planes else '' for i in plane_range])
Now I'm at:
Code:
bVec1 = core.mv.Analyse(csuper,isb=True,overlap=4,delta=1)
File "src\cython\vapoursynth.pyx", line 2612, in vapoursynth.Function.__call__
vapoursynth.Error: Analyse: failed to retrieve first frame from super clip. Error message: 'memoryview' object has no attribute 'props'


Cu Selur
__________________
Hybrid here in the forum, homepage
Selur is offline   Reply With Quote
Old 17th January 2023, 21:31   #11  |  Link
_Al_
Registered User
 
Join Date: May 2011
Posts: 321
I tested it and I could go thru that line but
I used:
Code:
srchClip = core.std.FrameEval(clip=srchClip, eval=partial(selectQTGMC,a=a,b=b), prop_src=[diffclip,diffclip_trimmed])
I forgot to put prop_src clips in a list, you used clip_src , not sure if that is correct and was introcuded in API4 anyway

my test on your last script ended up on this line:
tMax = mt_logic(fComp1,mode="max").mt_logic(bComp1,mode="max"), but that needs some fixing, I'm sure you know ...

Last edited by _Al_; 17th January 2023 at 21:34.
_Al_ is offline   Reply With Quote
Old 18th January 2023, 19:24   #12  |  Link
Selur
Registered User
 
Selur's Avatar
 
Join Date: Oct 2001
Location: Germany
Posts: 7,259
Quote:
my test on your last script ended up on this line:
tMax = mt_logic(fComp1,mode="max").mt_logic(bComp1,mode="max"), but that needs some fixing, I'm sure you know ...
That's issue 3 in my first post.

There's also the issue that I use:
Code:
X=1 # no clue how to get field order
  Inter = core.std.Interleave([
     bobbed.std.SetFrameProp(prop="_FieldBased", intval=X).std.SeparateFields().std.SelectEvery(4,0),
     fComp1.std.SetFrameProp(prop="_FieldBased", intval=X).std.SeparateFields().std.SelectEvery(4,1),
     bComp1.std.SetFrameProp(prop="_FieldBased", intval=X).std.SeparateFields().std.SelectEvery(4,2),
     bobbed.std.SetFrameProp(prop="_FieldBased", intval=X).std.SeparateFields().std.SelectEvery(4,3)
  ])
since I'm not certain how to get the field order.
__________________
Hybrid here in the forum, homepage
Selur is offline   Reply With Quote
Old 21st January 2023, 11:31   #13  |  Link
Selur
Registered User
 
Selur's Avatar
 
Join Date: Oct 2001
Location: Germany
Posts: 7,259
Now the script:
Code:
# Imports
import vapoursynth as vs
import os
import sys
from functools import partial
from typing import Optional, Union, Sequence
# getting Vapoursynth core
core = vs.core


def CQTGMC(clip: vs.VideoNode, Sharpness: float=0.25, thSAD1: int=192, thSAD2: int=320, thSAD3: int=128, thSAD4: int=320, tff: bool=True) -> vs.VideoNode:
  
  padded = core.std.AddBorders(clip, left=0, top=clip.height%4, right=clip.width%64, bottom=0)
  # alternative:
  #padded = core.std.StackHorizontal([clip, clip.std.FlipHorizontal().std.Crop(0,0,clip.width+clip.width()%64,0)])
  #padded = core.std.StackVertical([padded, padded.std.FlipVertical().std.Crop(0,0,0,clip.height+clip.height%64)])
    
  bobbed = core.znedi3.nnedi3(clip=padded, field=2)
  denoised = core.rgvs.RemoveGrain(clip=bobbed,mode=12)
  denoised = core.fmtc.resample(clip=denoised, kernel="gauss", w=denoised.width, h=denoised.height+0.0001, scaleh=denoised.width+0.0001, interlaced=False, interlacedd=False)
  denoised = core.resize.Bicubic(clip=denoised, format=bobbed.format, dither_type="error_diffusion") # adjust format after fmtc
  denoised = core.std.Merge(clipa=denoised, clipb=bobbed,weight=0.25)
  
  srchClip = denoised
  csuper = core.mv.Super(clip=denoised);
  bvec = core.mv.Analyse(csuper,isb=True,blksize=64,overlap=32)
  fvec = core.mv.Analyse(csuper,isb=False,blksize=64,overlap=32)
  Comp1 = core.mv.Compensate(clip=denoised,super=csuper,vectors=bvec,thsad=thSAD2)
  Comp2 = core.mv.Compensate(clip=denoised,super=csuper,vectors=fvec,thsad=thSAD2)
  denoised = core.std.Interleave([Comp1,denoised,Comp2])
  csuper = core.mv.Super(clip=denoised)
  bvec = core.mv.Analyse(csuper,isb=True,blksize=64,overlap=32)
  fvec = core.mv.Analyse(csuper,isb=False,blksize=64,overlap=32)
  Inter = core.mv.FlowInter(denoised, csuper, bvec,fvec,blend=False)
  a = core.std.SelectEvery(clip=Inter, cycle=3, offsets=0)
  b = core.std.SelectEvery(clip=Inter, cycle=3, offsets=1)
  Y = core.std.ShufflePlanes([srchClip],[0], vs.GRAY)
  diffclip = core.std.PlaneStats(Y, Y[0]+Y[0:-1])
  Y_trimmed =Y[1:]+Y[-1:]
  diffclip_trimmed = core.std.PlaneStats(Y_trimmed,Y_trimmed[0]+Y_trimmed[0:-1])
  def selectQTGMC(n, f, a, b):
    P = f[0].props['PlaneStatsDiff']
    N = f[1].props['PlaneStatsDiff']
    if N < P:
        return a
    else:
        return b

  srchClip = core.std.FrameEval(clip=srchClip, eval=partial(selectQTGMC,a=a,b=b), prop_src=[diffclip,diffclip_trimmed])
  
  csuper = core.mv.Super(clip=srchClip)
  bVec1 = core.mv.Analyse(super=csuper, isb=True, overlap=4, delta=1)
  fVec1 = core.mv.Analyse(super=csuper, isb=False, overlap=4, delta=1)
  csuper = core.mv.Super(clip=bobbed,levels=1)
  bComp1 = core.mv.Compensate(clip=bobbed, super=csuper, vectors=bVec1, thsad=thSAD3)
  fComp1 = core.mv.Compensate(clip=bobbed, super=csuper, vectors=fVec1, thsad=thSAD3)
  X = 2 if tff else 1 # no clue how to get field order
  Inter = core.std.Interleave([
     bobbed.std.SetFrameProp(prop="_FieldBased", intval=X).std.SeparateFields().std.SelectEvery(4,0),
     fComp1.std.SetFrameProp(prop="_FieldBased", intval=X).std.SeparateFields().std.SelectEvery(4,1),
     bComp1.std.SetFrameProp(prop="_FieldBased", intval=X).std.SeparateFields().std.SelectEvery(4,2),
     bobbed.std.SetFrameProp(prop="_FieldBased", intval=X).std.SeparateFields().std.SelectEvery(4,3)
  ])  
  weaved = core.std.DoubleWeave(clip=Inter)[::2]
  csuper = core.mv.Super(clip=weaved, levels=1)
  bComp1 = core.mv.Compensate(clip=weaved, super=csuper, vectors=bVec1, thsad=thSAD4)
  fComp1 = core.mv.Compensate(clip=weaved, super=csuper, vectors=fVec1, thsad=thSAD4)
  tMax = core.std.Expr(clips=[weaved, bComp1], expr=['x y max'])
  tMax = core.std.Expr(clips=[tMax, fComp1], expr=['x y max'])
  tMin = core.std.Expr(clips=[weaved, bComp1], expr=['x y min'])
  tMin = core.std.Expr(clips=[tMin, fComp1], expr=['x y min'])
  
  degrained = core.mv.Degrain1(clip=weaved, super=csuper, mvbw=bVec1, mvfw=fVec1, thsad=thSAD1)
  sharpen = core.std.MergeDiff(degrained, core.std.MakeDiff(degrained,degrained.rgvs.RemoveGrain(mode=20)))
  
  sharpen = mt_clamp(sharpen,tMax,tMin,Sharpness,Sharpness,[0])
  csuper = core.mv.Super(sharpen, levels=1)
  degrained = core.mv.Degrain1(degrained, csuper,bVec1,fVec1,thsad=thSAD1)
  degrained = core.std.Crop(degrained, left=0, top=clip.height%4, right=clip.width%64, bottom=0)
  return degrained

# from havsfunc  
def mt_clamp(
    clip: vs.VideoNode,
    bright_limit: vs.VideoNode,
    dark_limit: vs.VideoNode,
    overshoot: int = 0,
    undershoot: int = 0,
    planes: Optional[Union[int, Sequence[int]]] = None,
) -> vs.VideoNode:
    if not (isinstance(clip, vs.VideoNode) and isinstance(bright_limit, vs.VideoNode) and isinstance(dark_limit, vs.VideoNode)):
        raise vs.Error('mt_clamp: this is not a clip')

    if bright_limit.format.id != clip.format.id or dark_limit.format.id != clip.format.id:
        raise vs.Error('mt_clamp: clips must have the same format')

    plane_range = range(clip.format.num_planes)

    if planes is None:
        planes = list(plane_range)
    elif isinstance(planes, int):
        planes = [planes]

    return core.std.Expr([clip, bright_limit, dark_limit], expr=[f'x y {overshoot} + min z {undershoot} - max' if i in planes else '' for i in plane_range])
gets processed, but the output isn't properly deinerlaced.
Must have mixed up something somewhere.

=> does anyone see where I went wrong?

Cu Selur
__________________
Hybrid here in the forum, homepage

Last edited by Selur; 22nd January 2023 at 14:32.
Selur is offline   Reply With Quote
Old 23rd January 2023, 22:15   #14  |  Link
Ceppo
Registered User
 
Join Date: Feb 2016
Location: Nonsense land
Posts: 339
Just wondering? Does the avisynth version deinterlaces it correctly? You have to think like a much strong lossless of QTGMC, so combed pixels might show up.

I don't speak vapoursynth language but I can't catch something that looks like this code, but I might be wrong.

Quote:
bobbed
super = MSuper(levels=1)
bComp1 = MCompensate(super,bVec1,thSAD=thSAD3)
fComp1 = MCompensate(super,fVec1,thSAD=thSAD3)
Interleave(\
SeparateFields(bobbed).SelectEvery(4,0),\
SeparateFields(fComp1).SelectEvery(4,1),\
SeparateFields(bComp1).SelectEvery(4,2),\
SeparateFields(bobbed).SelectEvery(4,3))
Weave()


My bad I spot it :\

Last edited by Ceppo; 23rd January 2023 at 22:25.
Ceppo is offline   Reply With Quote
Old 24th January 2023, 00:03   #15  |  Link
Ceppo
Registered User
 
Join Date: Feb 2016
Location: Nonsense land
Posts: 339
Quote:
padded = core.std.AddBorders(clip, left=0, top=clip.height%4, right=clip.width%64, bottom=0)
Note: AddBorders is bad.

Quote:
Y = core.std.ShufflePlanes([srchClip],[0], vs.GRAY)
diffclip = core.std.PlaneStats(Y, Y[0]+Y[0:-1])
Y_trimmed =Y[1:]+Y[-1:]
diffclip_trimmed = core.std.PlaneStats(Y_trimmed,Y_trimmed[0]+Y_trimmed[0:-1])
What this piece of code does? Je ne comprends pas. It is YDifferenceFromPrevious()?
Quote:
X = 2 if tff else 1 # no clue how to get field order
You are working on a bobbed clip, you don't need the field order, and why you set it to field based? I'm missing something?
Quote:
degrained = core.std.Crop(degrained, left=0, top=clip.height%4, right=clip.width%64, bottom=0)
Nothing else catches my eyes with 1% brain usage as processing power and 64kbit of RAM.
Ceppo is offline   Reply With Quote
Old 24th January 2023, 03:46   #16  |  Link
_Al_
Registered User
 
Join Date: May 2011
Posts: 321
HolyWu is working with YDifferenceFromPrevious here:
https://github.com/HomeOfVapourSynth...sfunc.py#L3321
_Al_ is offline   Reply With Quote
Old 24th January 2023, 19:31   #17  |  Link
Selur
Registered User
 
Selur's Avatar
 
Join Date: Oct 2001
Location: Germany
Posts: 7,259
Quote:
Note: AddBorders is bad.
Fixed mod in crop&addborders

Quote:
You are working on a bobbed clip, you don't need the field order, and why you set it to field based? I'm missing something?
SeparateFields requires FieldBased info .
Without the 'std.SetFrameProp(prop="_FieldBased", intval=X)' part I get
Code:
bComp1 = core.mv.Compensate(clip=weaved, super=csuper, vectors=bVec1, thsad=thSAD4)
File "src\cython\vapoursynth.pyx", line 2612, in vapoursynth.Function.__call__
vapoursynth.Error: Compensate: failed to retrieve first frame from super clip. Error message: SeparateFields: no field order provided
later on.
the
Code:
    global CQTGMC_A = Inter.SelectEvery(3,0)
    global CQTGMC_B = Inter.SelectEvery(3,1)
    srchClip
    ScriptClip("""
    P = YDifferenceFromPrevious()
    N = Trim(1,0).YDifferenceFromPrevious()
    N < P ? CQTGMC_A : CQTGMC_B 
    """)
part currently is translated to:
Code:
  a = core.std.SelectEvery(clip=Inter, cycle=3, offsets=0)
  b = core.std.SelectEvery(clip=Inter, cycle=3, offsets=1)
  Y = core.std.ShufflePlanes([srchClip],[0], vs.GRAY)
  diffclip = core.std.PlaneStats(Y, Y[0]+Y[0:-1])
  Y_trimmed =Y[1:]+Y[-1:]
  diffclip_trimmed = core.std.PlaneStats(Y_trimmed,Y_trimmed[0]+Y_trimmed[0:-1])
  def selectQTGMC(n, f, a, b):
    P = f[0].props['PlaneStatsDiff']
    N = f[1].props['PlaneStatsDiff']
    if N < P:
        return a
    else:
        return b

  srchClip = core.std.FrameEval(clip=srchClip, eval=partial(selectQTGMC,a=a,b=b), prop_src=[diffclip,diffclip_trimmed])
but I have no clue whether this is correct.
-> if someone can translate this to Vapoursynth in a working way, please do.
__________________
Hybrid here in the forum, homepage
Selur is offline   Reply With Quote
Old 4th February 2023, 14:20   #18  |  Link
Selur
Registered User
 
Selur's Avatar
 
Join Date: Oct 2001
Location: Germany
Posts: 7,259
Thanks to all that helped think I got a working version now:
Code:
# Imports
import vapoursynth as vs
import os
import sys
from functools import partial
from typing import Optional, Union, Sequence
# getting Vapoursynth core
core = vs.core

# Vapoursynth port of CQTMC from https://forum.doom9.org/showthread.php?p=1963693
#
# dependencies:
#
# fmtc when boxed=False         https://github.com/EleonoreMizo/fmtconv
# mvtools                   https://github.com/dubhater/vapoursynth-mvtools 
# NNEDI3CL when openCL=True https://github.com/HomeOfVapourSynthEvolution/VapourSynth-NNEDI3CL
# NNEDI3 when openCL=False  https://github.com/sekrit-twc/znedi3


def CQTGMC(clip: vs.VideoNode, Sharpness: float=0.25, thSAD1: int=192, thSAD2: int=320, thSAD3: int=128, thSAD4: int=320, tff: bool=True, openCL: bool=False, boxed: bool=False) -> vs.VideoNode:
  
  # pad to mod64
  padded = core.std.AddBorders(clip, left=0, top=clip.height%64, right=clip.width%64, bottom=0) 
  
  # deinterlace
  X = 2 if tff else 1
  if openCL:
    bobbed = core.znedi3.nnedi3(clip=padded, field=X)
  else:
    bobbed = core.nnedi3cl.NNEDI3CL(clip=padded, field=X)
  
  # denoise
  denoised = core.rgvs.RemoveGrain(clip=bobbed,mode=12)
  if boxed:
    denoised = core.std.BoxBlur(clip=denoised)
  else:
    denoised = core.fmtc.resample(clip=denoised, kernel="gauss", w=denoised.width, h=denoised.height+0.0001, scaleh=denoised.width+0.0001, interlaced=False, interlacedd=False)
    denoised = core.resize.Bicubic(clip=denoised, format=bobbed.format, dither_type="error_diffusion") # adjust format after fmtc
  denoised = core.std.Merge(clipa=denoised, clipb=bobbed,weight=0.25)
  
  srchClip = denoised
  csuper = core.mv.Super(clip=denoised);
  bvec = core.mv.Analyse(csuper,isb=True,blksize=64,overlap=32)
  fvec = core.mv.Analyse(csuper,isb=False,blksize=64,overlap=32)
  Comp1 = core.mv.Compensate(clip=denoised,super=csuper,vectors=bvec,thsad=thSAD2)
  Comp2 = core.mv.Compensate(clip=denoised,super=csuper,vectors=fvec,thsad=thSAD2)
  denoised = core.std.Interleave([Comp1,denoised,Comp2])
  csuper = core.mv.Super(clip=denoised)
  bvec = core.mv.Analyse(csuper,isb=True,blksize=64,overlap=32)
  fvec = core.mv.Analyse(csuper,isb=False,blksize=64,overlap=32)
  Inter = core.mv.FlowInter(denoised, csuper, bvec,fvec,blend=False)
  
  a = core.std.SelectEvery(clip=Inter, cycle=3, offsets=0)
  b = core.std.SelectEvery(clip=Inter, cycle=3, offsets=1)
  Y = core.std.ShufflePlanes([srchClip],[0], vs.GRAY)
  diffclip = core.std.PlaneStats(Y, Y[0]+Y[0:-1])
  Y_trimmed =Y[1:]+Y[-1:]
  diffclip_trimmed = core.std.PlaneStats(Y_trimmed,Y_trimmed[0]+Y_trimmed[0:-1])
  def selectQTGMC(n, f, a, b):
    P = f[0].props['PlaneStatsDiff']
    N = f[1].props['PlaneStatsDiff']
    if N < P:
        return a
    else:
        return b

  srchClip = core.std.FrameEval(clip=srchClip, eval=partial(selectQTGMC,a=a,b=b), prop_src=[diffclip,diffclip_trimmed])
  
  csuper = core.mv.Super(clip=srchClip)
  bVec1 = core.mv.Analyse(super=csuper, isb=True, overlap=4, delta=1)
  fVec1 = core.mv.Analyse(super=csuper, isb=False, overlap=4, delta=1)
  csuper = core.mv.Super(clip=bobbed,levels=1)
  bComp1 = core.mv.Compensate(clip=bobbed, super=csuper, vectors=bVec1, thsad=thSAD3)
  fComp1 = core.mv.Compensate(clip=bobbed, super=csuper, vectors=fVec1, thsad=thSAD3)
  
  
  
  Inter = core.std.Interleave([
     bobbed.std.SeparateFields(tff=X).std.SelectEvery(4,0),
     fComp1.std.SeparateFields(tff=X).std.SelectEvery(4,1),
     bComp1.std.SeparateFields(tff=X).std.SelectEvery(4,2),
     bobbed.std.SeparateFields(tff=X).std.SelectEvery(4,3)
  ]) 
  
  
  weaved = core.std.DoubleWeave(clip=Inter)[::2]
  csuper = core.mv.Super(clip=weaved, levels=1)

  
  bComp1 = core.mv.Compensate(clip=weaved, super=csuper, vectors=bVec1, thsad=thSAD4)
  fComp1 = core.mv.Compensate(clip=weaved, super=csuper, vectors=fVec1, thsad=thSAD4)
  tMax = core.std.Expr(clips=[weaved, bComp1], expr=['x y max'])
  tMax = core.std.Expr(clips=[tMax, fComp1], expr=['x y max'])
  tMin = core.std.Expr(clips=[weaved, bComp1], expr=['x y min'])
  tMin = core.std.Expr(clips=[tMin, fComp1], expr=['x y min'])
  
  degrained = core.mv.Degrain1(clip=weaved, super=csuper, mvbw=bVec1, mvfw=fVec1, thsad=thSAD1)
  sharpen = core.std.MergeDiff(degrained, core.std.MakeDiff(degrained,degrained.rgvs.RemoveGrain(mode=20)))
  sharpen = mt_clamp(sharpen,tMax,tMin,Sharpness,Sharpness,[0])
  
  csuper = core.mv.Super(sharpen, levels=1)
  degrained = core.mv.Degrain1(clip=degrained, super=csuper, mvbw=bVec1,mvfw=fVec1,thsad=thSAD1)
  degrained = core.std.Crop(degrained, left=0, top=clip.height%64, right=clip.width%64, bottom=0)
  return degrained

# from havsfunc 
# https://github.com/HomeOfVapourSynthEvolution/havsfunc/blob/7f0a9a7a37b60a05b9f408024d203e511e544a61/havsfunc.py#L5911
def mt_clamp(
    clip: vs.VideoNode,
    bright_limit: vs.VideoNode,
    dark_limit: vs.VideoNode,
    overshoot: int = 0,
    undershoot: int = 0,
    planes: Optional[Union[int, Sequence[int]]] = None,
) -> vs.VideoNode:
    if not (isinstance(clip, vs.VideoNode) and isinstance(bright_limit, vs.VideoNode) and isinstance(dark_limit, vs.VideoNode)):
        raise vs.Error('mt_clamp: this is not a clip')

    if bright_limit.format.id != clip.format.id or dark_limit.format.id != clip.format.id:
        raise vs.Error('mt_clamp: clips must have the same format')

    plane_range = range(clip.format.num_planes)

    if planes is None:
        planes = list(plane_range)
    elif isinstance(planes, int):
        planes = [planes]

    return core.std.Expr([clip, bright_limit, dark_limit], expr=[f'x y {overshoot} + min z {undershoot} - max' if i in planes else '' for i in plane_range])
also under: https://github.com/Selur/Vapoursynth...ster/cqtgmc.py

Cu Selur
__________________
Hybrid here in the forum, homepage
Selur is offline   Reply With Quote
Old 19th February 2023, 18:35   #19  |  Link
Selur
Registered User
 
Selur's Avatar
 
Join Date: Oct 2001
Location: Germany
Posts: 7,259
Nope, the padding and cropping is wrong.
Using:
Code:
# Imports
import vapoursynth as vs
import os
import sys
from functools import partial
from typing import Optional, Union, Sequence
# getting Vapoursynth core
core = vs.core

# Vapoursynth port of CQTMC from https://forum.doom9.org/showthread.php?p=1963693
#
# dependencies:
#
# fmtc when boxed=False         https://github.com/EleonoreMizo/fmtconv
# mvtools                   https://github.com/dubhater/vapoursynth-mvtools 
# NNEDI3CL when openCL=True https://github.com/HomeOfVapourSynthEvolution/VapourSynth-NNEDI3CL
# NNEDI3 when openCL=False  https://github.com/sekrit-twc/znedi3


def CQTGMC(clip: vs.VideoNode, Sharpness: float=0.25, thSAD1: int=192, thSAD2: int=320, thSAD3: int=128, thSAD4: int=320, tff: bool=True, openCL: bool=False, boxed: bool=False) -> vs.VideoNode:
  
  # pad to mod64    
  padded = core.std.AddBorders(clip, left=0, top=clip.height%4, right=clip.width%64, bottom=0)
  
  # spatial deinterlace
  # field: 2: Double rate, start with bottom field, 3: Double rate, start with top field.
  X = 3 if tff else 2
  if openCL:
    spatial = core.nnedi3cl.NNEDI3CL(clip=padded, field=X)
  else:
    spatial = core.znedi3.nnedi3(clip=padded, field=X)

  # temporal deint
  # order: 0 = bottom field first (bff), 1 = top field first (tff)
  X = 1 if tff else 0
  bobbed = core.tdm.TDeintMod(clip=padded, order=X, mode=1, edeint=spatial)
    
  # denoise
  denoised = core.rgvs.RemoveGrain(clip=bobbed,mode=12)
  if boxed:
    denoised = core.std.BoxBlur(clip=denoised)
  else:
    denoised = core.fmtc.resample(clip=denoised, kernel="gauss", w=denoised.width, h=denoised.height+0.0001, scaleh=denoised.width+0.0001, interlaced=False, interlacedd=False)
    denoised = core.resize.Bicubic(clip=denoised, format=bobbed.format, dither_type="error_diffusion") # adjust format after fmtc
  denoised = core.std.Merge(clipa=denoised, clipb=bobbed,weight=0.25)
  
  srchClip = denoised
  csuper = core.mv.Super(clip=denoised);
  bvec = core.mv.Analyse(csuper,isb=True,blksize=64,overlap=32)
  fvec = core.mv.Analyse(csuper,isb=False,blksize=64,overlap=32)
  Comp1 = core.mv.Compensate(clip=denoised,super=csuper,vectors=bvec,thsad=thSAD2)
  Comp2 = core.mv.Compensate(clip=denoised,super=csuper,vectors=fvec,thsad=thSAD2)
  denoised = core.std.Interleave([Comp1,denoised,Comp2])
  csuper = core.mv.Super(clip=denoised)
  bvec = core.mv.Analyse(csuper,isb=True,blksize=64,overlap=32)
  fvec = core.mv.Analyse(csuper,isb=False,blksize=64,overlap=32)
  Inter = core.mv.FlowInter(denoised, csuper, bvec,fvec,blend=False)
  
  a = core.std.SelectEvery(clip=Inter, cycle=3, offsets=0)
  b = core.std.SelectEvery(clip=Inter, cycle=3, offsets=1)
  Y = core.std.ShufflePlanes([srchClip],[0], vs.GRAY)
  diffclip = core.std.PlaneStats(Y, Y[0]+Y[0:-1])
  Y_trimmed =Y[1:]+Y[-1:]
  diffclip_trimmed = core.std.PlaneStats(Y_trimmed,Y_trimmed[0]+Y_trimmed[0:-1])
  def selectQTGMC(n, f, a, b):
    P = f[0].props['PlaneStatsDiff']
    N = f[1].props['PlaneStatsDiff']
    if N < P:
        return a
    else:
        return b

  srchClip = core.std.FrameEval(clip=srchClip, eval=partial(selectQTGMC,a=a,b=b), prop_src=[diffclip,diffclip_trimmed])
  
  csuper = core.mv.Super(clip=srchClip)
  bVec1 = core.mv.Analyse(super=csuper, isb=True, overlap=4, delta=1)
  fVec1 = core.mv.Analyse(super=csuper, isb=False, overlap=4, delta=1)
  csuper = core.mv.Super(clip=bobbed,levels=1)
  bComp1 = core.mv.Compensate(clip=bobbed, super=csuper, vectors=bVec1, thsad=thSAD3)
  fComp1 = core.mv.Compensate(clip=bobbed, super=csuper, vectors=fVec1, thsad=thSAD3)
  
  
  
  Inter = core.std.Interleave([
     bobbed.std.SeparateFields(tff=tff).std.SelectEvery(4,0),
     fComp1.std.SeparateFields(tff=tff).std.SelectEvery(4,1),
     bComp1.std.SeparateFields(tff=tff).std.SelectEvery(4,2),
     bobbed.std.SeparateFields(tff=tff).std.SelectEvery(4,3)
  ]) 
  
  
  weaved = core.std.DoubleWeave(clip=Inter)[::2]
  csuper = core.mv.Super(clip=weaved, levels=1)

  
  bComp1 = core.mv.Compensate(clip=weaved, super=csuper, vectors=bVec1, thsad=thSAD4)
  fComp1 = core.mv.Compensate(clip=weaved, super=csuper, vectors=fVec1, thsad=thSAD4)
  tMax = core.std.Expr(clips=[weaved, bComp1], expr=['x y max'])
  tMax = core.std.Expr(clips=[tMax, fComp1], expr=['x y max'])
  tMin = core.std.Expr(clips=[weaved, bComp1], expr=['x y min'])
  tMin = core.std.Expr(clips=[tMin, fComp1], expr=['x y min'])
  
  degrained = core.mv.Degrain1(clip=weaved, super=csuper, mvbw=bVec1, mvfw=fVec1, thsad=thSAD1)
  sharpen = core.std.MergeDiff(degrained, core.std.MakeDiff(degrained,degrained.rgvs.RemoveGrain(mode=20)))
  sharpen = mt_clamp(sharpen,tMax,tMin,Sharpness,Sharpness,[0])
  
  csuper = core.mv.Super(sharpen, levels=1)
  degrained = core.mv.Degrain1(clip=degrained, super=csuper, mvbw=bVec1,mvfw=fVec1,thsad=thSAD1)
  degrained = core.std.Crop(degrained, left=0, top=clip.core%64, right=clip.width%64, bottom=0)
  return degrained


# from havsfunc 
# https://github.com/HomeOfVapourSynthEvolution/havsfunc/blob/7f0a9a7a37b60a05b9f408024d203e511e544a61/havsfunc.py#L5911
def mt_clamp(
    clip: vs.VideoNode,
    bright_limit: vs.VideoNode,
    dark_limit: vs.VideoNode,
    overshoot: int = 0,
    undershoot: int = 0,
    planes: Optional[Union[int, Sequence[int]]] = None,
) -> vs.VideoNode:
    if not (isinstance(clip, vs.VideoNode) and isinstance(bright_limit, vs.VideoNode) and isinstance(dark_limit, vs.VideoNode)):
        raise vs.Error('mt_clamp: this is not a clip')

    if bright_limit.format.id != clip.format.id or dark_limit.format.id != clip.format.id:
        raise vs.Error('mt_clamp: clips must have the same format')

    plane_range = range(clip.format.num_planes)

    if planes is None:
        planes = list(plane_range)
    elif isinstance(planes, int):
        planes = [planes]

    return core.std.Expr([clip, bright_limit, dark_limit], expr=[f'x y {overshoot} + min z {undershoot} - max' if i in planes else '' for i in plane_range])
the padding at the beginning and cropping at the end is wrong as it is implemented atm.
__________________
Hybrid here in the forum, homepage
Selur is offline   Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 18:30.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.