Mug Funky
18th October 2004, 13:10
hi all.
don't know why i hadn't done this before, but i just combined degrainmedian, remove (dirt and grain) and MVtools and got an interesting denoiser out of it.
there's also dust-style pixel change limiting thanks to YV12lut.
at default settings i got a very large compressibility gain (67.1% of original size, 90.5% the size of regular removedirt) with less potential artefacts.
it runs slow as molasses - about 1 fps for 720x576 source, gets faster if the source is smaller (i suggest resizing before running this). there's room for a speed increase i think, but i can't be bothered with it right now :)
how it works:
- gets forward and backward motion from a slightly blurred source (not sure if the blurring helps)
- runs degrainmedian and removedirt between current frame and motion-compensated and heavily de-blocked neighbors
- compares cleaned and source, and clips changes to the "limit" value (default 6). read dust or degrainmedian docs for more info.
here's the code:
function degrainMC (clip c, int "limit", int "pel", int "mode", int "quant", bool "show")
{
limit = default(limit,6)
pel = default(pel,1)
mode = default(mode,1)
quant = default(quant,12)
show = default(show,false)
maskexpr = "x "+string(limit)+" < 256 "+string(limit)+" x / 256 * ?"
vfw = c.blur(1).mvanalyse(lambda=2000,pel=pel, isb=false)
vbw = c.blur(1).mvanalyse(lambda=2000,pel=pel, isb=true)
comp = (quant > 0)?
\ interleave(c.mvcompensate(vfw).blindpp(quant,cpu=4),c,c.mvcompensate(vbw).blindpp(quant,cpu=4))
\.degrainmedian(mode=mode,limitY=limit,limitUV=limit).removedirt() :
\ interleave(c.mvcompensate(vfw),c,c.mvcompensate(vbw))
\.degrainmedian(mode=mode,limitY=limit,limitUV=limit).removedirt()
clean = comp.selectevery(3,1)
diff = yv12lutxy(c,clean,yexpr="x y - abs",uexpr="x y - abs",vexpr="x y - abs",Y=3,U=3,V=3)
mask = diff.yv12lut(yexpr=maskexpr,uexpr=maskexpr,vexpr=maskexpr,Y=3,U=3,V=3)
show==false? maskedmerge(c,clean,mask) : mask
}
usage:
degrainMC() should do for most things. limit can be tweaked if you see blocks.
the deblocking can smear the image a bit, but also increases compression it can be disabled by setting "quant" to 0. default is 12. image smearing is pretty modest, considering the frame being processed is never deblocked.
hope someone finds a use for this (or uses it as a starting point for another filter). i've tried it out on 1000 frames of an R4 release of Seven - it's very grainy. probably needs more testing than that, but looks alright now.
[edit]
seems to mess the chroma on scenechanges... hmmm.
[edit 2]
false alarm - must be a bug in fdecimate. i wondered why i hadn't seen it earlier.
don't know why i hadn't done this before, but i just combined degrainmedian, remove (dirt and grain) and MVtools and got an interesting denoiser out of it.
there's also dust-style pixel change limiting thanks to YV12lut.
at default settings i got a very large compressibility gain (67.1% of original size, 90.5% the size of regular removedirt) with less potential artefacts.
it runs slow as molasses - about 1 fps for 720x576 source, gets faster if the source is smaller (i suggest resizing before running this). there's room for a speed increase i think, but i can't be bothered with it right now :)
how it works:
- gets forward and backward motion from a slightly blurred source (not sure if the blurring helps)
- runs degrainmedian and removedirt between current frame and motion-compensated and heavily de-blocked neighbors
- compares cleaned and source, and clips changes to the "limit" value (default 6). read dust or degrainmedian docs for more info.
here's the code:
function degrainMC (clip c, int "limit", int "pel", int "mode", int "quant", bool "show")
{
limit = default(limit,6)
pel = default(pel,1)
mode = default(mode,1)
quant = default(quant,12)
show = default(show,false)
maskexpr = "x "+string(limit)+" < 256 "+string(limit)+" x / 256 * ?"
vfw = c.blur(1).mvanalyse(lambda=2000,pel=pel, isb=false)
vbw = c.blur(1).mvanalyse(lambda=2000,pel=pel, isb=true)
comp = (quant > 0)?
\ interleave(c.mvcompensate(vfw).blindpp(quant,cpu=4),c,c.mvcompensate(vbw).blindpp(quant,cpu=4))
\.degrainmedian(mode=mode,limitY=limit,limitUV=limit).removedirt() :
\ interleave(c.mvcompensate(vfw),c,c.mvcompensate(vbw))
\.degrainmedian(mode=mode,limitY=limit,limitUV=limit).removedirt()
clean = comp.selectevery(3,1)
diff = yv12lutxy(c,clean,yexpr="x y - abs",uexpr="x y - abs",vexpr="x y - abs",Y=3,U=3,V=3)
mask = diff.yv12lut(yexpr=maskexpr,uexpr=maskexpr,vexpr=maskexpr,Y=3,U=3,V=3)
show==false? maskedmerge(c,clean,mask) : mask
}
usage:
degrainMC() should do for most things. limit can be tweaked if you see blocks.
the deblocking can smear the image a bit, but also increases compression it can be disabled by setting "quant" to 0. default is 12. image smearing is pretty modest, considering the frame being processed is never deblocked.
hope someone finds a use for this (or uses it as a starting point for another filter). i've tried it out on 1000 frames of an R4 release of Seven - it's very grainy. probably needs more testing than that, but looks alright now.
[edit]
seems to mess the chroma on scenechanges... hmmm.
[edit 2]
false alarm - must be a bug in fdecimate. i wondered why i hadn't seen it earlier.