Mug Funky
1st August 2005, 09:04
hi all. for a while i've been trying to emulate a hardware standards-converter in avisynth. kernelbob and convertfps work to a certain extent, but i could never get very accurate static area detection out of kernelbob (or anything else, really). the converter i use has an auto motion threshold that is difficult to figure out.
well, here's an attempt at doing just that. at default settings, it'll output a smart-bobbed stream and change nothing. you can enter an output fps, and an output height, as well as tweaking the noise thresholds.
function ixion (clip c, float "fps",int "height", int "nth", int "dth",bool "interlaced")
{
fps=default(fps,c.framerate())
out_height=default(height,c.height())
nth=default(nth,8)
dth=default(dth,4)
interlaced=default(interlaced,false)
map=c.horizontalreduceby2().coloryuv(cont_y=-32).temporalsoften(1,nth,0,nth+1,2).leakkerneldeint(order=1,map=true,threshold=dth,twoway=true).binarize(234,false).expand().converttoyuy2().bilinearresize(c.width,c.height)
lowrate_even=overlay(c,c.leakkerneldeint(order=1,threshold=dth,twoway=true),mask=map).converttoyuy2().bicubicresize(c.width,out_height,0,.5).convertfps(fps*2).selecteven()
lowrate_odd=overlay(c,c.leakkerneldeint(order=0,threshold=dth,twoway=true),mask=map).converttoyuy2().bicubicresize(c.width,out_height,0,.5).convertfps(fps*2).selectodd()
lowrate=interleave(lowrate_even,lowrate_odd)
highrate=c.leakkernelbob(order=1,threshold=dth,sharp=true,twoway=true).converttoyuy2().bicubicresize(c.width,out_height,0,.5)
overlay(lowrate,highrate.convertfps(fps*2),mask=map.bicubicresize(c.width,out_height,0,.5).convertfps(fps*2))
assumebff()
interlaced==true? last.separatefields().selectevery(4,1,2).weave() : last
}
nth = noise threshold. this thing ignores noise by running a hard temporal smooth on the luma, and this threshold says just how hard it is. the default value is for a (noisy) analog broadcast i used for testing, but for REALLY noisy sources it'll need to be raised to avoid lots of shimmer. for a smooth source (CG anime?) you can drop this value to 0 and get a speed gain, but then it'll just be like using kernelbob without noise detection.
dth = the regular kernelbob thresold. probably should be left as it is to avoid shimmer, but can be lowered on clean sources (again, no point using this at all on really clean stuff).
interlaced = true/false. if true it weaves the 2 bobbed frames together. useful for standards conversion, ie "ixion(fps=30/1.001,height=480,interlaced=true)" will go PAL to NTSC. if false, you'll get bobbed output at twice the "fps" value entered.
this is not at all speed-optimised (i want to masktool the hell out of it eventually, but i wanted to prove the concept first), and it only works with top-field first sources. in my opinion bottom-first should be ditched, and a standard of top-first always should be adopted, as people just get it wrong way too often and it makes things harder for everyone. there's a bunch of ways to reverse field-dominance out there, or some kind soul could modify this script to handle both...
enjoy!
[edit]
btw, you'll need leakkerneldeint to run this...
well, here's an attempt at doing just that. at default settings, it'll output a smart-bobbed stream and change nothing. you can enter an output fps, and an output height, as well as tweaking the noise thresholds.
function ixion (clip c, float "fps",int "height", int "nth", int "dth",bool "interlaced")
{
fps=default(fps,c.framerate())
out_height=default(height,c.height())
nth=default(nth,8)
dth=default(dth,4)
interlaced=default(interlaced,false)
map=c.horizontalreduceby2().coloryuv(cont_y=-32).temporalsoften(1,nth,0,nth+1,2).leakkerneldeint(order=1,map=true,threshold=dth,twoway=true).binarize(234,false).expand().converttoyuy2().bilinearresize(c.width,c.height)
lowrate_even=overlay(c,c.leakkerneldeint(order=1,threshold=dth,twoway=true),mask=map).converttoyuy2().bicubicresize(c.width,out_height,0,.5).convertfps(fps*2).selecteven()
lowrate_odd=overlay(c,c.leakkerneldeint(order=0,threshold=dth,twoway=true),mask=map).converttoyuy2().bicubicresize(c.width,out_height,0,.5).convertfps(fps*2).selectodd()
lowrate=interleave(lowrate_even,lowrate_odd)
highrate=c.leakkernelbob(order=1,threshold=dth,sharp=true,twoway=true).converttoyuy2().bicubicresize(c.width,out_height,0,.5)
overlay(lowrate,highrate.convertfps(fps*2),mask=map.bicubicresize(c.width,out_height,0,.5).convertfps(fps*2))
assumebff()
interlaced==true? last.separatefields().selectevery(4,1,2).weave() : last
}
nth = noise threshold. this thing ignores noise by running a hard temporal smooth on the luma, and this threshold says just how hard it is. the default value is for a (noisy) analog broadcast i used for testing, but for REALLY noisy sources it'll need to be raised to avoid lots of shimmer. for a smooth source (CG anime?) you can drop this value to 0 and get a speed gain, but then it'll just be like using kernelbob without noise detection.
dth = the regular kernelbob thresold. probably should be left as it is to avoid shimmer, but can be lowered on clean sources (again, no point using this at all on really clean stuff).
interlaced = true/false. if true it weaves the 2 bobbed frames together. useful for standards conversion, ie "ixion(fps=30/1.001,height=480,interlaced=true)" will go PAL to NTSC. if false, you'll get bobbed output at twice the "fps" value entered.
this is not at all speed-optimised (i want to masktool the hell out of it eventually, but i wanted to prove the concept first), and it only works with top-field first sources. in my opinion bottom-first should be ditched, and a standard of top-first always should be adopted, as people just get it wrong way too often and it makes things harder for everyone. there's a bunch of ways to reverse field-dominance out there, or some kind soul could modify this script to handle both...
enjoy!
[edit]
btw, you'll need leakkerneldeint to run this...