View Full Version : smoothing script that may be useful
Mug Funky
21st January 2004, 16:29
hi yall.
after reading one of mf's posts (actually a bug report with subtract) i had a bit of an idea to adapt one of my photoshop actions to avisynth.
it's a spatial smoother based around killing high frequencies but preserving those that are significant (edges).
what i'd do (in photoshop) is make a highpassed layer, and a blurred layer at the same radius. the original image can be reconstituted my overlaying the 2 layers. so the clever bit would be to do a kind of "smart blur" on the highpassed layer, so the edges would be unaffected, but the grain would be. this gave pretty nice images, and a fair compressibility gain on JPEGs i saved out.
it hadn't occurred to me that subtract() could do the same thing.
so here's the script:
in=last
blurred=in.bilinearresize(in.width/2,in.height/2).bicubicresize(in.width,in.height,1,0)
edge=subtract(blurred,in).temporalsoften(5,8,8,mode=2,scenechange=16)
subtract(blurred,edge)
it's "kind of" a spatio-temporal filter - it uses a temporal filter to decide whether spatial filtering should be done. this means no banding on camera pans or face movements.
the output looks similar to vaguedenoiser's but a lot faster.
i've yet to do compressability tests, but i like what it does to "dr. strangelove"
lemme know what you think if you try it...
Mug Funky
21st January 2004, 18:43
hmm... i've been doing some more stuff with it and have made a slower and more customisible version. works as a function, defaults give good results on grainy material.
function funkydenoise(clip c, int "radius", int "low", int "high", float "gamma")
{
# set up defaults...
radius=default(radius,3)
low=default(low,0)
high=default(high,240)
gamma=default(gamma,0.125)
radius=radius*2 # keep it all mod2
blurred=c.bilinearresize(2*(c.width/radius),2*(c.height/radius)).bicubicresize(c.width,c.height,1,0)
edge=overlay(subtract(c,blurred),subtract(blurred,c),mode="darken").blur(1).coloryuv(autogain=true).levels(low,gamma,high,0,255)
overlay(c,blurred,mask=edge)
}
just whack that at the start of a script (or in a .avsi file in the plugins folder) and type "funkydenoise()". all arguments are optional.
now there's no temporal component, and it makes use of the new composite modes in "overlay"... so you'll need the latest binary (see sh0dan's sig...)
what happens now is a mask is made from the highpassed layer which controls how much of the original you see and how much of the blurred version.
"radius" controls the blurring (downsizer, basically, like in mipsmooth)
"low" is the black point in the mask (as in levels)
"high" is the white point of the mask
"gamma"...you get the idea.
USAGE:
default:
funkydenoise()
fancy (well, defaults in longhand):
funkydenoise(3,0,240,0.125)
i hope somebody finds this script useful - i like how it's worked for me in photoshop, but this is WAY faster in avisynth.
Mug Funky
6th March 2004, 15:36
here's an update... it's considerably faster, has different defaults (i only tested the previous ones on 1 piece of very noisy film, so they weren't good for much else), and has a VERY light "fast mode" which uses a different method (might be useful for compressibility, and has very little visual effect unless you run it several times)
it also incorporates my bobber and deinterlacer (which have been superseded somewhat, but are still useful)
function FunkyDeInt (clip c, bool "post") {
post = default(post,true)
c3=c.horizontalreduceby2()
c2=subtract(c3.bob(0,.5).selecteven(), c3.bob(0,.5).selectodd()).greyscale()
c2=subtract(c2,c2.deleteframe(0))
c2=overlay(c2,c2.levels(0,1,255,255,0),mode="lighten")
c2=c2.undot().levels(129,1,143,0,255).pointresize(c.width,c.height)
overlay(c, c.tomsmocomp(0,5,0), mask=c2)
(post == true) ? last.blur(0,1).blur(0,-1) : last
}
function FunkyBob(clip c, bool "post") {
post = default(post,true)
c3=c.horizontalreduceby2()
c2=subtract(c3.bob().selecteven(), c3.bob().selectodd()).greyscale()
c2=subtract(c2,c2.deleteframe(0))
c2=overlay(c2,c2.levels(0,1,255,255,0),mode="lighten")
c2=c2.undot().levels(130,1,133,0,255).pointresize(c.width,c.height)
tmcOdd=c.tomsmocomp(0,6,0).sangnom(0)
tmcEven=c.tomsmocomp(1,6,0).sangnom(1)
odd = overlay(c, tmcodd, mask=c2)
even = overlay(c, tmceven, mask=c2)
getparity(c) ? interleave(even,odd) : interleave(odd,even)
(post == true) ? last.blur(0,1).blur(0,-1) : last
}
function FunkyDenoise(clip c, int "radius", int "low", int "high", float "gamma", bool "fast")
{
# set up defaults...
radius=default(radius,3)
low=default(low,127)
gamma=default(gamma,1.5)
high=default(high,140)
fast=default(fast,false)
radius=radius*4 # keep it all mod4
lowpass=c.bilinearresize(4*(c.width/radius),4*(c.height/radius)).bicubicresize(c.width,c.height,1,0)
edge = overlay(lowpass,c,mode="difference").greyscale().levels(low,gamma,high,0,255).ColorYUV(levels="TV->PC")
slowclip=overlay(lowpass,c,mask=edge)
highpass=subtract(lowpass,c).temporalsoften(2,3,3,16,2)
fastclip=subtract(lowpass,highpass)
out = (fast==true)? fastclip:slowclip
return out
}
just put it in an avsi somewhere (i called mine "funkypack.avsi", but that's a bit cheesy for some :))
defaults work for most sources i've tried, but there's room for improvement.
[edit] changed a stoopid luma range bug... now if low < 127 and high < 127 the output is identical to the input. before it seemed to lighten the edges minutely (only visible with subtract(filtered, unfiltered))
Hey Mug,
That Funkydenoiser a very very cool Function (I didn't test the others till right now but that will follow) and its fassssst.
Could you explain more the bool fast=true/false ...
Im just right now teaking the funktion a bit according to very noise captures.
Thanks a lot!
Inc.
Mug Funky
7th March 2004, 08:32
hmm... fast mode?
basically i'm using a technique i got nice results with in photoshop for spatial smoothing.
make a blurred clip, subtract the original, and you end up with a "high-passed" clip, containing only the high frequencies (well, it's not mathematically like this, but a good analogy). in theory the noise will all be in the highpassed clip, and will also be quite low in intensity. so what i then do is create a soft mask for all values near 127 (this will be _most_ of the noise and hopefully not much detail). then i merge the lowpass and highpass back together.
"fast mode" doesn't use a mask - it uses a simple Temporalsoften on the highpass clip with low settings. this makes it all run much much faster, but allows the possibility of temporal smearing if used heaviliy (and when used lightly it produces very little difference)
one thing i've tried with fast mode is using it in a nested manner:
funkydenoise(fast=true, radius=16)
funkydenoise(fast=true, radius=8)
funkydenoise(fast=true, radius=4)
funkydenoise(fast=true, radius=2)
this will give you a lot of motion smearing (but still be kinda fast).
i might put custom values in for the temporal smoother in my next update, but this would increase complexity... right now i'm aiming for something i can use with defaults (i'm kinda lazy with tweaks) and i prefer a simple filter than a complex one with similar results.
Mug Funky
8th March 2004, 10:11
changed the script to make it more intuitive to tweak...
re-mapped the numbers to some more logical values - cut and rolloff
this is similar to lowpass terms in signal theory. you have a cutoff "frequency" and the filter "rolloff" determines how steep the filter is, ie. how much it attenuates above frequencies.
defaults are now:
radius = 4
cut = 0
rolloff = 20
gamma = 1.5
this means that the edge mask is filtered as:
levels(cut+127,gamma,cut+rolloff+127,0,255)
funkydenoise(cut=0,rolloff=0) is completely lossless (it serves to slow down your encoding :))
cut must be between -127 and 128, and is only really useful in positive numbers (but can be used for "soft focus" effects below 0 with rolloff at 0)
useful range of rolloff is ~8 to ~40 depending on noiselevel
i've been playing with this alternate way of setting values and found them more fun to play with, and easier to tweak particularly noisy or particularly clean clips.
here's the updated script (just the funkydenoise bit...)
function FunkyDenoise(clip c, int "radius", int "cut", int "rolloff", float "gamma", bool "fast")
{
# set up defaults...
radius=default(radius,4)
cut=default(cut,0)
gamma=default(gamma,1.5)
rolloff=default(rolloff,20)
fast=default(fast,false)
# remap numbers
low = cut + 127
high = low + rolloff
radius=radius*4 # keep it all mod4
lowpass=c.bilinearresize(4*(c.width/radius),4*(c.height/radius)).bicubicresize(c.width,c.height,1,0)
edge = overlay(lowpass,c,mode="difference").levels(low,gamma,high,0,255).ColorYUV(levels="TV->PC")
slowclip=overlay(lowpass,c,mask=edge)
highpass=subtract(lowpass,c).temporalsoften(2,3,3,16,2)
fastclip=subtract(lowpass,highpass)
out = (fast==true)? fastclip:slowclip
return out
}
vBulletin® v3.8.5, Copyright ©2000-2012, Jelsoft Enterprises Ltd.