Log in

View Full Version : new script: AGC (Automatic Gain Control)


Mug Funky
22nd March 2004, 08:23
hey yo, before you point out there's an "autogain" function already...

this script functions in a similar manner to a a VCR's AGC circuit, or in more general terms, a dynamic compressor. the difference here is that it's based on temporalsoften, meaning it has scenechange detection :)

AGC circuits will amplify a too-dark video and reduce a too-bright signal. (this is how Macrovision works - by putting 3-4x white lines in the overscan area, the AGC circuit is fooled into turning the brightness down to stupidly low levels.)

i made this because i have a wide variety of too-dark videos, and the pumping effects of colorYUV(autogain=true) were just too horrible for compressibility and aesthetics, as it works on every frame.

this script will average over several frames (originally i had a lot of scripting for this, until i had a brain freeze and realised temporalsoften(4,255,255,255,2) did exactly what i wanted), then up the gain (in RGB).

this is rather like having an attack time and a release time...

here's the script:


global gl_lum=1

function AGC (clip c, int "mode",float "multiplier", float "gamma", int "radius",int "scenechange", bool "luma")
{
global gl_radius = default(radius,4)
global gl_scenechange = default(scenechange,20)
global gl_multiplier = default(multiplier,.96)
global gl_c = c
global gl_gamma = default(gamma,1)
mode= default(mode, 2)
luma = default(luma,true)

global gl_multiplier = (mode==2)? float(gl_multiplier*2) :
\ float(gl_multiplier)

global gl_method = (mode==1)? "averageluma()" :
\ (mode==2)? "YplaneMax()" : "YplaneMedian()"

gl_c=gl_c.frameevaluate("global gl_lum = gl_multiplier*128/
\ (gl_c.deleteframe(0).reduceby2().reduceby2().
\ temporalsoften(gl_radius,255,255,gl_scenechange,2).
\ levels(0,gl_gamma,255,0,255,coring=false)." + string(gl_method + ")")
\ ,after_frame=false)

(luma==true)? gl_c.scriptclip("coloryuv(gain_y=round(gl_lum * 256)-256)") :
\ gl_c.scriptclip("converttorgb32().RGBadjust(gl_lum,gl_lum,gl_lum,0).converttoyv12()")

}


WARNING: this script is EXTREMELY unstable - i'm new to conditional filtering, so that's bound to be the problem. put this last in your script - any temporal filters after it will crash avisynth (i've been able to run spatial filters after it with varying reliability, so you can experiment... funkydenoise() works)

if anybody can help make this more useful they are very much encouraged to do so :)

usage:

mode - integer defining whether averageluma() is used (1), YplaneMax() (2), or YplaneMedian (3). i wouldn't bother with median, as it is hell on dark videos. probably the most useful one is mode 2.

multiplier - global scale of the output... you may need to lower this for particularly colourful clips, where luma is unexpectedly low and chroma high.

radius - this is attack/release time in frames (the radius param in temporalsoften). default is 4, to prevent small pumping in mode=2, try increase it (but if you get error text decrease it again)

scenechange - best left at default, or if you want to have fading after scenechanges (too make it look like an old tape), raise it to 255.

gamma - this will move the average level around, if need be. useful for videos with dark backround and light foreground - increase the gamma value and the average goes up, meaning less gain is applied. more predictable then tweaking multiplier... agc(gamma=2) will make a video come out lower, agc(gamma=0.75) will make it brighter by a lot.

luma - boolean. default true. this will only add gain to luma, rather than converting to RGB and doing each channel (which is a truer kind of gain, but often meaningless for TV caps, and slower to boot)

have fun people!

[edit]

updated the script so multiplier is doubled for mode = 2

[edit edit]

another slight update. it's now way more stable, and a little faster in certain situations. you can now run filters after it, it seems.

[edit 3]

added some line breaks for Scharfis_Brain, careful not to break the script in the process. :)

[edit 4]

added gamma (well added this before but forgot to document it) and luma-only mode.

jorel
22nd March 2004, 13:57
"this script functions in a similar manney to a a VCR's AGC circuit.."

very cool idea Mug Funky !
:)

i will do some samples and post later.
thanks!

Mug Funky
22nd March 2004, 15:07
ARGH! thanks for spotting the typo...

jorel
22nd March 2004, 16:17
Originally posted by Mug Funky
ARGH! thanks for spotting the typo...

the "typo" wasn't important,
i "copy" the phrase cos i understood the idea that remains cool!


:)

Mug Funky
22nd March 2004, 16:40
updated above code...

added "gamma", which i just found is quite an important parameter. it will wieght the average and mitigate clipping on high ocntrast, dark clips (space action movies :))

default is 1, if you get excessive clipping and oversaturated output, set it to 1.5. this wont apply gamma to the output, but will supply the averaging function with a gamma corrected clip (bringing up the avrage luma)

scharfis_brain
22nd March 2004, 22:02
nice script!

but would you pleeeeeze add some linebreaks into your text above?
I really dislike hor. scrolling....

rfmmars
23rd March 2004, 03:15
mug funky


Hey arn't those auto everything just great on camcorder.....uh, many thanks for your work on this filter.

Have you ever thought of a script to reduce the water fall effect that most VCRs suffer. It's caused by the rotating head assembly.

richard
photorecall.net

Mug Funky
24th March 2004, 15:46
waterfall effect? i've not heard of this one.

is it the horizontal warpage that occurs on pretty much all rental tapes i get (my VCR leaves a little to be desired)?

avisynth currently doesn't lend itself easily to that kind of thing, but if you're really patient you could use a plugin somebody made that shifts single lines. if you're really patient you could derive an equation for the line warping, and write a script that outputs these values into a bunch of eval( "blah" ) lines...

i did that with YV12convolution and a sine squared curve so i could get lowpass filtering at any radius :p

[edit]

added some line breaks. still need to scroll a tiny bit, but all-in-all it helps.

rfmmars
24th March 2004, 16:57
Mug Funkey........waterfall effect, is lets say you have a straight thin vertical line. Because of tape stretch and with the speed of the rotating head varing, each scan line is offset a tiny amount left or right. No longer is the line smooth, but is a little jagged.

On my boardcast decks, you don't see this if the tape was made on this deck, but you can see it quite often with home units, or it shows real bad on a copy of the orignal tape.

Its all about timing, and there are several reference points where a Avisynth script could be written.

Your a great,programer, I not, but i am a NTSC enginee plus I have even design PAL test equipment when SKY satellite service began.

Maybe we could work together on the filter. It would be some what like a TBC with moving each line a tiny bit,expanding the scan line duration or contracting it.

richard
photorecall.net

Si
24th March 2004, 17:53
Its all about timing, and there are several reference points where a Avisynth script could be written.


Could you name a few of them?

This is one of the holy grails of video processing (100% motion detection being the most holy :p ) and I've not heard of anything that can automatically process this distortion to improve it once its been captured :(

regards

Simon

rfmmars
24th March 2004, 18:33
Timing.....The start of each scan line could be referenced to the first horizontal,blanking,sync, or burst pulse of the field. We know that the time for each NTSC scan line is, 63us.

The first horzontal sync pulse's time position, and the pulse itself could be repeted for all the lines in the whole field.

The lenght of the scan line in the uncorrected video then could be compared to the time between the reference pulse time position to the next pulse position for the following scan line.

This works because this is what Zenith used in their Savvy cable decorder.

richard
photorecall.net

Mug Funky
25th March 2004, 05:38
only problem with that is that sync pulses are never captured on any software i've heard of.

i know DV captures more lines than it shows (at least enough to allow macrovision to work when trying to record DV to VHS, although this might be a hack). but getting this vital information into avisynth is a big problem.

i've thought about doing this for sure, but until we can get a definite reference point (ie. a sync pulse or at least something on the side of the picture that can be defined as an edge) there's no foolproof way to do this.

perhaps there's a capture card out there that will do what we want...

(by the way, i'm certainly not a great programmer :))

rfmmars
25th March 2004, 19:59
Let me do somemore thinking on this matter. I do appricate you input on this problem.

richard

Mug Funky
28th March 2004, 18:30
updated above script (well, i will when i'm done typing this bump)

changes (or rather "change"):

- added luma only mode... accessed by "luma=true", true by default. it's now oodles faster as there's no colourspace conversion going on, and seeing as too-dark captures often have too-saturated colours, this is a good compromise in most cases.

Chainmax
29th March 2004, 03:57
I don't understand 100% what does AGC do. Is it comparable to what a Sima SCC can do or is it closer to TBC (like rfmmars said)?

Mug Funky
29th March 2004, 08:06
chainmax: nothing too special.

it just takes an average (or peak) level of the current ~8 frames and applies gain based on that.

it's analogous to coloryuv(autogain=true) except that it doesn't work per frame, but rather over an average of several frames (with scenechange detection of course)

i've called it "AGC" after the similar function of VCRs (automatic gain control)

DarkNite
29th March 2004, 09:32
A bit ago a freind of mine asked me to help him backup some of his more treasured videos that were only available on VHS to DVD-R. While the content of the tapes were great, you're probably all too familiar with the problems inherent to dealing with older VHS tapes.

I'm not sure whether all VCR's are equipped with AGC circuits or not, but apparently the VCR he used was either woefully equipped, completely missing an AGC circuit, or the tape was on it's last play. I don't recall ever seeing so much variance in levels from one frame to another without the cause being that beautiful Macrovision effect.

Well, to make an already long story short(er) I threw this updated function into the mix after a few disappointing ventures into other methods. I have two words for you: very nice!

Luma=true is a really nice addition. It still achieved the same effect as the previous script (to our eyes) while helping out greatly with the speed factor. Considering he's ending his filterchain with IIP and doesn't have room for any more intermediate AVI's that should be a real bonus.

/me returns to burning, shooting, and smashing VHS tapes

Mug Funky
29th March 2004, 12:54
glad to help: :)

i hope it doesn't throw any errors halfway through an encode though... it _should_ be okay if it gets past the first frame without going b0rk.

any script wizards are welcome to make it more stable (it's possibly my system more than anything that is giving me crashes :))

DarkNite
30th March 2004, 08:06
Well, it was fine throughout the 4-5 minute preview we reviewed, and didn't choke during our seeking for the horrid scenes, so... *crosses fingers, knocks on wood, finds an irishman and pays him to do a lucky jig*

First test encode is nearly completed, and no error yet. ;)

Mug Funky
30th March 2004, 08:17
cool. looks like the crashes must be at my end... i only even get them when advancing 1 frame straight after loading, so looks like even here, if it works it continues to work, and if it doesn't you know straight away (bit of a timesaver there).

hmmm... i'm mostly irish. should i do a little jig?

DarkNite
31st March 2004, 01:01
If you were doing a jig, do you have a PayPal account? I'll drop a cool 1,000... pesos. ;)

The first encode completed without a failure. Second has previewed, and began encoding without a failure so I'm assuming the stable trend will continue.

Thanks again, and best of luck on troubleshooting those failures. If I run into any failures on my box at home I'll report back.

Mug Funky
31st March 2004, 15:56
hmm... looks like the crashes i was getting were somehow related to blindPP() (not in ths particular script). probably because i've got _all_ the different versions of mpeg2decX.dll installed :)

sh0dan
12th April 2004, 13:08
Much faster version:
global gl_lum = 1
global gl_c = 0
global filterme = 0

function AGC (clip c, int "mode",float "multiplier", float "gamma", int "radius",int "scenechange", bool "luma")
{
global gl_radius = default(radius,4)
global gl_scenechange = default(scenechange,20)
global gl_multiplier = default(multiplier,.96)
gl_c = c
global gl_gamma = default(gamma,1)
mode= default(mode, 2)
luma = default(luma,true)

global gl_multiplier = (mode==2)? float(gl_multiplier*2) :
\ float(gl_multiplier)

global gl_method = (mode==1)? "averageluma(filterme)" :
\ (mode==2)? "YplaneMax(filterme)" : "YplaneMedian(filterme)"

filterme = gl_c.deleteframe(0).reduceby2().reduceby2().
\ temporalsoften(gl_radius,255,255,gl_scenechange,2).
\ levels(0,gl_gamma,255,0,255,coring=false)

gl_c=gl_c.frameevaluate("global gl_lum = gl_multiplier*128 / (" + string(gl_method + ")")
\ ,after_frame=false)

(luma==true)? gl_c.scriptclip("coloryuv(gain_y=round(gl_lum * 256)-256)") :
\ gl_c.scriptclip("converttorgb32().RGBadjust(gl_lum,gl_lum,gl_lum,0).converttoyv12()")

}
This works realtime on the material I've tested.

Try keeping as many scripts as possible out of ScriptClip/FrameEvaluate. Works very nicely though.

I also moved the global clip definitions outside the function. It somehow causes crash-on-ext if they are defined inside the function (for some reason).

Mug Funky
12th April 2004, 16:17
tanks sh0dan!

i'll bear that in mind. scriptclip/frameevaluate is a bit of a voodoo area to me. my code works but i don't fully understand why it does...

[edit]

works hella fast! w00t!

jorel
23rd April 2004, 20:23
Originally posted by Mug Funky
tanks sh0dan!

i'll bear that in mind. scriptclip/frameevaluate is a bit of a voodoo area to me. my code works but i don't fully understand why it does...

[edit]

works hella fast! w00t!

do you will update the script in the first post?

thanks in advance Mug Funky !
:)

Mug Funky
25th April 2004, 14:58
(holy thread resurrection, mugfunky!)

hmm... i'll update it when i sort out some issues. the RGB mode doesn't appear to work with sh0dan's version, as well as all but the default metric (which isn't an issue with most things, but there's such a wide array of clips out there that i need the other modes often).

jorel
25th April 2004, 20:18
this thread never die my friend!i came here everyday cos my mail notification is not working.

waiting for your news!thanks you.
:)