scharfis_brain
24th February 2004, 11:25
Everytime i deinterlaced artificial interlaced progressive streams
(the long form of blended streams), I recognized, that every bobber
out there is not able to handle the phase-shift in the video.
This means, that false-phased parts of the video are always getting
deinterlaced, thus reducing image quality and resolution.
My bobber is something like a (very) simple telecide. But in
comparision to telecide, it will return a fullframerate clip that
provides a higher quality due to the internal field-matching
here is the script:
# Test-Mask-Deinterlacer (for Restore24)
function Tomsbobsoft(clip c)
{ input=c.separatefields.tomsmocomp(1,-1,1)
a = getparity(input) ? input.selectodd : input.selecteven
b = getparity(input) ? input.selecteven : input.selectodd
a=stackvertical(a.crop(0,0,0,1-a.height),a.crop(0,0,0,-1))
output = getparity(input) ? interleave(b,a) : interleave(a,b)
output.assumeframebased
}
# Pre-Deinterlacer for Bobmatcher
# can also be used as standalone-bobber
# Kernelbob, using kernel-interpolation for achieving
# a higher resolution at slow-, and nonmoving locations
function kernelbob(clip a, int th)
{ ord = getparity(a) ? 1 : 0
f=a.kerneldeint(order=ord, sharp=true, twoway=true, threshold=th)
e=a.separatefields.trim(1,0).weave.kerneldeint(order=1-ord, sharp=true, twoway=true, threshold=th)
interleave(f,e).assumeframebased
}
# TMCbob, uses tomsmocomp-interpolation for getting
# diagonal lines with reduced stairstepping
function TMCbob(clip c)
{ ord = getparity(c) ? 1 : 0
c = c.SeparateFields.TomsMoComp(1,-1,0)
c = stackvertical(c.crop(0,0,0,1-c.height),c,c.crop(0,c.height-1,0,0))
evn = c.SelectEven
odd = c.SelectOdd
evn = (ord == 0) ? evn : evn.crop(0,1,0,0).addborders(0,0,0,1)
odd = (ord == 1) ? odd : odd.crop(0,1,0,0).addborders(0,0,0,1)
interleave(evn,odd).crop(0,0,0,-2).assumeframebased()
}
# Hehe, the TV-Simulator:
function TVdeint(clip clip, float kell)
{
clip=clip.addborders(0,4,0,4)
input=clip.converttoyuy2().separatefields()
blank=blankclip(selecteven(input))
even=interleave(selecteven(input),blank).weave()
odd =interleave(selectodd(input) ,blank).weave()
output=interleave(even,odd)
kell = (kell < 0 ) || (kell > 1) ? 0 : kell
(kell == 0) ? output : output.blur(0,kell).levels(0,1,255-int(128*kell),0,255)
crop(0,4,0,-4)
}
# And finally: the bobmatcher
function bobmatcher(clip fg, int "md", int "deintth", bool "showmask", bool "showmatch", bool "domatch",float "matchth", int "bobmethod")
{
# add borders to prevent the border-bug of motionmask
fg.AddBorders(8,0,8,0)
x1=last .converttoyuy2(interlaced=true)
# set vars
md = default(md,3)
deintth = default(deintth,3)
# maskedtmc = default(maskedtmc,true)
matchth = default(matchth, 0.3)
showmask = default(showmask,false)
showmatch = default(showmatch,false)
domatch = default(domatch,true)
bobmethod = default(bobmethod,128)
# create bobbing motionmask
evn = x1.motionmask(md,deintth)
odd = x1.doubleweave.selectodd.motionmask(md,deintth)
mask = interleave(evn,odd)
# create bobbed clip
# bobmethod = 0 only uses kernelbob for getting the interpolated data
# bobmethod = 255 only uses TMCbob
# bobmethod = 1..254 uses a weighted mix of kernelbob and TMCbob for getting
# the interpolated data, 128 creates a 1:1-blend (default)
bobx = (bobmethod == 0 ) ? x1.kernelbob(5) :
\ (bobmethod == 255) ? x1.tmcbob() :
\ layer(x1.kernelbob(5),x1.tmcbob(),"add",level=bobmethod)
bobx = showmask ? bobx.coloryuv(gain_v=-48) : bobx
# create doubleweaved clip
douw = x1.doubleweave
douw = showmask ? douw.coloryuv(gain_u=48) : douw
# calculate smartbobbed streams:
# using previous field to get the interpolation of the current field
global out1 = maskedmix(douw,bobx.trim(1,0),mask)
# using next field to get the interpolation of the current field
global out2 = maskedmix(douw,bobx,mask).trim(1,0)
# setup mask for matching
global mask1 = mask.converttoyv12
global mask2 = mask1.trim(1,0)
# if masks are to similar (No Matching), blend both bobbed streams together for best output
global outnomatch = overlay(out2,out1,opacity=0.5,mode="blend")
# create debug messages
global outnomatch = showmatch ?
\outnomatch.subtitle("Using Both Fields - No Matching") : outnomatch
global out1 = showmatch ? out1.subtitle("Using Previous Field") : out1
global out2 = showmatch ? out2.subtitle("Using Next Field") : out2
# do the matching
global outmatch = domatch ? ConditionalFilter(out1, out2, "averageluma(mask1)",
\ "<", "averageluma(mask2)") : outnomatch
# disable matching, if lumadifference between the prev-mask and the next-mask is smaller than p*100 percent
global p = matchth
o6 = ScriptClip(blankclip(out1), "outx")
o8 = FrameEvaluate(o6, "global outx = ((AL1*(1+p) > AL2) && (AL2 > AL1*(1-p))) ? outnomatch : outmatch")
o9 = Frameevaluate(o8,"global AL1 = averageluma(mask1)")
out= Frameevaluate(o9,"global AL2 = averageluma(mask2)")
# do some final things to get the output in sync with other bobbers
out = bobx.trim(0,-3) + out.assumeframebased().trim(2,0)
out.Crop(8,0,-8,0)
}
please be sure to have set up the fieldorder right before calling bobmatcher. assumetff or assumebff are okay...
Okay, lets get us to the parameters:
md sets the mode, which creates the interlacing-mask:
md = 1 : frame-differencing
md = 2 : field-differencing
md = 3 : frame & field-differencing (default)
deintth sets the interlacing threshold.
lower values are making it moresensitive for motion and noise
default = 3
matchth sets the threshold to prevent the deinterlacer from
irrgeular field-jumping in pure video-scenes (default=0.3)
higher values gives more stability in video, but lesser fieldmatching
in telecined parts.
domatch disables matching, if set to false (default=true)
showmask if true, it makes interpolated areas visible (default=false)
blueish = video is passed through as it is
greenish = video gets deinterlaced
showmatch if true it shows, which field is used to match on
the current one (default=false)
bobmethod = 0 only uses kernelbob for getting the interpolated data
bobmethod = 255 only uses TMCbob
bobmethod = 1..254 uses a weighted mix of kernelbob and TMCbob for getting the interpolated data
bobmethod = 128 is default
example:
loadplugin("C:\x\kerneldeint140.dll")
loadplugin("C:\x\tomsmocomp.dll")
loadplugin("C:\x\mpeg2dec.dll") #must be loaded before mpeg2dec3!
loadplugin("C:\x\mpeg2dec3.dll")
mpeg2source("wall.d2v",cpu=4,iPP=true).crop(0,76,0,-76)
bobmatcher()
(the long form of blended streams), I recognized, that every bobber
out there is not able to handle the phase-shift in the video.
This means, that false-phased parts of the video are always getting
deinterlaced, thus reducing image quality and resolution.
My bobber is something like a (very) simple telecide. But in
comparision to telecide, it will return a fullframerate clip that
provides a higher quality due to the internal field-matching
here is the script:
# Test-Mask-Deinterlacer (for Restore24)
function Tomsbobsoft(clip c)
{ input=c.separatefields.tomsmocomp(1,-1,1)
a = getparity(input) ? input.selectodd : input.selecteven
b = getparity(input) ? input.selecteven : input.selectodd
a=stackvertical(a.crop(0,0,0,1-a.height),a.crop(0,0,0,-1))
output = getparity(input) ? interleave(b,a) : interleave(a,b)
output.assumeframebased
}
# Pre-Deinterlacer for Bobmatcher
# can also be used as standalone-bobber
# Kernelbob, using kernel-interpolation for achieving
# a higher resolution at slow-, and nonmoving locations
function kernelbob(clip a, int th)
{ ord = getparity(a) ? 1 : 0
f=a.kerneldeint(order=ord, sharp=true, twoway=true, threshold=th)
e=a.separatefields.trim(1,0).weave.kerneldeint(order=1-ord, sharp=true, twoway=true, threshold=th)
interleave(f,e).assumeframebased
}
# TMCbob, uses tomsmocomp-interpolation for getting
# diagonal lines with reduced stairstepping
function TMCbob(clip c)
{ ord = getparity(c) ? 1 : 0
c = c.SeparateFields.TomsMoComp(1,-1,0)
c = stackvertical(c.crop(0,0,0,1-c.height),c,c.crop(0,c.height-1,0,0))
evn = c.SelectEven
odd = c.SelectOdd
evn = (ord == 0) ? evn : evn.crop(0,1,0,0).addborders(0,0,0,1)
odd = (ord == 1) ? odd : odd.crop(0,1,0,0).addborders(0,0,0,1)
interleave(evn,odd).crop(0,0,0,-2).assumeframebased()
}
# Hehe, the TV-Simulator:
function TVdeint(clip clip, float kell)
{
clip=clip.addborders(0,4,0,4)
input=clip.converttoyuy2().separatefields()
blank=blankclip(selecteven(input))
even=interleave(selecteven(input),blank).weave()
odd =interleave(selectodd(input) ,blank).weave()
output=interleave(even,odd)
kell = (kell < 0 ) || (kell > 1) ? 0 : kell
(kell == 0) ? output : output.blur(0,kell).levels(0,1,255-int(128*kell),0,255)
crop(0,4,0,-4)
}
# And finally: the bobmatcher
function bobmatcher(clip fg, int "md", int "deintth", bool "showmask", bool "showmatch", bool "domatch",float "matchth", int "bobmethod")
{
# add borders to prevent the border-bug of motionmask
fg.AddBorders(8,0,8,0)
x1=last .converttoyuy2(interlaced=true)
# set vars
md = default(md,3)
deintth = default(deintth,3)
# maskedtmc = default(maskedtmc,true)
matchth = default(matchth, 0.3)
showmask = default(showmask,false)
showmatch = default(showmatch,false)
domatch = default(domatch,true)
bobmethod = default(bobmethod,128)
# create bobbing motionmask
evn = x1.motionmask(md,deintth)
odd = x1.doubleweave.selectodd.motionmask(md,deintth)
mask = interleave(evn,odd)
# create bobbed clip
# bobmethod = 0 only uses kernelbob for getting the interpolated data
# bobmethod = 255 only uses TMCbob
# bobmethod = 1..254 uses a weighted mix of kernelbob and TMCbob for getting
# the interpolated data, 128 creates a 1:1-blend (default)
bobx = (bobmethod == 0 ) ? x1.kernelbob(5) :
\ (bobmethod == 255) ? x1.tmcbob() :
\ layer(x1.kernelbob(5),x1.tmcbob(),"add",level=bobmethod)
bobx = showmask ? bobx.coloryuv(gain_v=-48) : bobx
# create doubleweaved clip
douw = x1.doubleweave
douw = showmask ? douw.coloryuv(gain_u=48) : douw
# calculate smartbobbed streams:
# using previous field to get the interpolation of the current field
global out1 = maskedmix(douw,bobx.trim(1,0),mask)
# using next field to get the interpolation of the current field
global out2 = maskedmix(douw,bobx,mask).trim(1,0)
# setup mask for matching
global mask1 = mask.converttoyv12
global mask2 = mask1.trim(1,0)
# if masks are to similar (No Matching), blend both bobbed streams together for best output
global outnomatch = overlay(out2,out1,opacity=0.5,mode="blend")
# create debug messages
global outnomatch = showmatch ?
\outnomatch.subtitle("Using Both Fields - No Matching") : outnomatch
global out1 = showmatch ? out1.subtitle("Using Previous Field") : out1
global out2 = showmatch ? out2.subtitle("Using Next Field") : out2
# do the matching
global outmatch = domatch ? ConditionalFilter(out1, out2, "averageluma(mask1)",
\ "<", "averageluma(mask2)") : outnomatch
# disable matching, if lumadifference between the prev-mask and the next-mask is smaller than p*100 percent
global p = matchth
o6 = ScriptClip(blankclip(out1), "outx")
o8 = FrameEvaluate(o6, "global outx = ((AL1*(1+p) > AL2) && (AL2 > AL1*(1-p))) ? outnomatch : outmatch")
o9 = Frameevaluate(o8,"global AL1 = averageluma(mask1)")
out= Frameevaluate(o9,"global AL2 = averageluma(mask2)")
# do some final things to get the output in sync with other bobbers
out = bobx.trim(0,-3) + out.assumeframebased().trim(2,0)
out.Crop(8,0,-8,0)
}
please be sure to have set up the fieldorder right before calling bobmatcher. assumetff or assumebff are okay...
Okay, lets get us to the parameters:
md sets the mode, which creates the interlacing-mask:
md = 1 : frame-differencing
md = 2 : field-differencing
md = 3 : frame & field-differencing (default)
deintth sets the interlacing threshold.
lower values are making it moresensitive for motion and noise
default = 3
matchth sets the threshold to prevent the deinterlacer from
irrgeular field-jumping in pure video-scenes (default=0.3)
higher values gives more stability in video, but lesser fieldmatching
in telecined parts.
domatch disables matching, if set to false (default=true)
showmask if true, it makes interpolated areas visible (default=false)
blueish = video is passed through as it is
greenish = video gets deinterlaced
showmatch if true it shows, which field is used to match on
the current one (default=false)
bobmethod = 0 only uses kernelbob for getting the interpolated data
bobmethod = 255 only uses TMCbob
bobmethod = 1..254 uses a weighted mix of kernelbob and TMCbob for getting the interpolated data
bobmethod = 128 is default
example:
loadplugin("C:\x\kerneldeint140.dll")
loadplugin("C:\x\tomsmocomp.dll")
loadplugin("C:\x\mpeg2dec.dll") #must be loaded before mpeg2dec3!
loadplugin("C:\x\mpeg2dec3.dll")
mpeg2source("wall.d2v",cpu=4,iPP=true).crop(0,76,0,-76)
bobmatcher()