Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion.

Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules.

 

Go Back   Doom9's Forum > Capturing and Editing Video > Avisynth Usage

Reply
 
Thread Tools Search this Thread Display Modes
Old 3rd March 2014, 02:25   #1  |  Link
Leo D9
Registered User
 
Join Date: Feb 2013
Posts: 9
Manual White Balance in YUV without converting to RGB

1) Firstly, when adjusting white balance in RGB, my understanding is that the correct way to do this is by simply scaling the values of one or two of the R, G and/or B channel(s) as required. Is that correct?

2) There seem to be many ways of changing Y, U and V, but what is the "correct" method (by which I guess I mean mathematically/colorimetrically correct, not subjective) of manually adjusting white balance in the YUV colorspace? (Or is it necessary/better to convert to RGB, scale the channels and convert back?)

3) Is there a simple way to translate a colour temperature conversion into a change of YUV, and/or change of RGB? (I sometimes work with RGB so an answer for each would be useful.) e.g. If I want to convert the colour temperature from 3200K to 5600K how would I do that in YUV, and how should it be done in RGB?

Many thanks!


PS: 4) Mildly off-topic, but when using ColorYUV(autogain=true) will any values get clipped? The documentation says, "it will scale up the luma (y) values to match the minimum and maximum values." So, if there is one value at 255 and everything else is 200 or less what happens? And if the lowest value in the image is, say, 30 what happens? (ie, does it adjust the offset for setting black as well as pure gain?) Or does it do something like clip 1% of whites and 1% of blacks. Is it purely on a per-frame basis, completely ignoring preceding and subsequent frames? Also, since (unlike in Levels() ) I can't specify a black level (eg 0 or 16) nor a white level (eg 235 or 255), how does it know what the max and min values should be? (Assuming I'm not changing the levels "TV->PC" or "PC->TV".) Thanks.
Leo D9 is offline   Reply With Quote
Old 3rd March 2014, 07:46   #2  |  Link
smok3
brontosaurusrex
 
smok3's Avatar
 
Join Date: Oct 2001
Posts: 2,389
1. Can't be that simple, since what you got is curved nonLinear camera data, so you'd need to uncurve that before changing each curve to fix white balance. (or fix the actual existing curve considering low,mid,high positions)

(resolve lite is free and you'd get the idea how it may actually work)
__________________
certain other member
smok3 is offline   Reply With Quote
Old 3rd March 2014, 12:26   #3  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,380
Regarding ColorYUV(autogain=true), it simply adjusts the gain_y and off_y parameters, on a per-frame basis, to put the darkest pixel in each frame at y=16 and the brightest at y=236 (not 235, for some reason!).
The levels parameter ("TV->PC" or "PC->TV") is ignored in this process.

EDIT: It's a little more complicated if you have existing pixels outside the range [16,236]. What actually happens is it sets gain_y and off_y so that the range [max(yMin, 16), min(yMax, 236)] is mapped to [16,236].
__________________
GScript and GRunT - complex Avisynth scripting made easier

Last edited by Gavino; 3rd March 2014 at 12:45.
Gavino is offline   Reply With Quote
Old 4th March 2014, 06:33   #4  |  Link
Leo D9
Registered User
 
Join Date: Feb 2013
Posts: 9
Ach, I'd forgotten about the gamma curves. So how do people manage/control white balance in AviSynth? What is the standard method? eg if I load a clip and see the white balance is off, how should it be corrected?

@Gavino : So that means if I use autogain on a clip with the range 0-255, then the frames with any pixel above 235 and any pixel below 16 won't be changed at all? So I would have to do Levels(0, 1, 255, 16, 235) before autogain to ensure 0-255 clips are treated the same way as 16-235 clips? I guess that risks banding?

Basically... my problem is that I'm processing and encoding dozens of video clips one by one by using a batch file to generate a temporary AVS file (to add intro, outro, title, watermark, temporal smoothing, etc) that gets encoded by FFMPEG. Some of the clips could be 16-235 and some 0-255 (such as Canon DSLR MOVs).

5.A) Is there any way to automatically identify the luma/chroma range of a clip or normalise the whole clip to a range? (Ideally without needing a plug-in.)

5.B) And when I encode the clip with FFMPEG.exe, does it just assume the range is 16-235 with Rec.709 colour?

(Sorry if that's off-topic, perhaps I should have started a new thread.)

Thanks.

Last edited by Leo D9; 4th March 2014 at 19:06. Reason: Levels() syntax, as noted by Gavino
Leo D9 is offline   Reply With Quote
Old 4th March 2014, 13:21   #5  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,380
Quote:
Originally Posted by Leo D9 View Post
@Gavino : So that means if I use autogain on a clip with the range 0-255, then the frames with any pixel above 235 and any pixel below 16 won't be changed at all?
If a frame has some pixels above 235 AND some below 16, it will not be changed at all. However, if it has some above 235, but the darkest pixel is (for example) 20, then the range [20, 236] will be mapped to [16,236] and the pixels above 236 will be increased in brightness. A similar effect occurs at the other end if there are pixels below 16 but none above 236 (the darkest pixels will get darker).

Quote:
So I would have to do Levels(0, 255, 1, 16, 235) before autogain to ensure 0-255 clips are treated the same way as 16-235 clips? I guess that risks banding?
Yes [you mean Levels(0, 1, 255, 16, 235)], and if you wanted the output to remain 0-255 you would also have to do Levels(16, 1, 235, 0, 255) after.
__________________
GScript and GRunT - complex Avisynth scripting made easier
Gavino is offline   Reply With Quote
Old 5th March 2014, 06:32   #6  |  Link
raffriff42
Retried Guesser
 
raffriff42's Avatar
 
Join Date: Jun 2012
Posts: 1,377
I don't know all the math involved, but I found some interesting things on the Wikipedia page on Color Temperature.

Take a look at this animation: it's the light spectrum of a radiating black body at various temperatures:



I took this image and carefully measured the graph values at red, green and blue (estimated from the rainbow bar at the bottom) and normalized to 0-255:


Adjusted for gamma=1.8:


I also measured the color swatch:

(not shown: red below about 6500k; it's always 255; similarly, blue above about 6500K is always 255)


Note Wikipedia does not attempt to show the high red & blue levels at the extremes; it looks like they convey the impression of reddish or bluish white (given the limits of computer imagery) by decreasing the other channels instead.

I got some transfer functions by curve regression, but I haven't attempted to use them, because (a) I'm not absolutely certain they will be accurate, and (b), there is a simple cheat that is "good enough" for most purposes:

If you view the above Wikipedia animation with a vector scope such as Histogram(mode="color2"), you will notice the color swatch is moving along a pretty straight line on the scope within the range 2000K-20000K. This means a simple call to ColorYUV with the appropriate values of offset_u and offset_v can fake color temp changes pretty well. In fact, the result looks identical to Photoshop's "warm" and "cool" photographic filters...

But that wasn't good enough for me! Simply adding U and V offsets cannot correct white, black and gray balance at the same time. To me, it looks kinda nasty (too much saturation in blacks and whites).

So to do it correctly, one should use RGB mode and adjust gain, offset and gamma on all channels. But we want correction in YUV space! So I propose another cheap trick: I create masks for low, middle and high luminance areas and apply different offsets to each range.

Here is my take at a cheating color correction function; I am calling it CheapColorTemp. Please try this with your own sources and see if it isn't pretty neat. To me luma range selectivity is more important than mathematical correctness. A "calibrated" way to alter apparent color temperature would be nice though, I admit.

Over-adjusted to show the range of the effect.
Code:
##Last=YUV  

## CheapColorTemp demonstration
## flip between original and several corrections
## (view in step mode; not for real time playback)

Interleave(
\ last.Subtitle("original"),
\ CheapColorTemp(0, -10, 0).Subtitle("mid -10"),
\ CheapColorTemp(0, 0, -10).Subtitle("hi -10"),
\ last.Subtitle("original"),
\ CheapColorTemp(0, 0, 10).Subtitle("hi +10"),
\ CheapColorTemp(0, 10, 0).Subtitle("mid +10"))

## scope(s) optional
##   RGBParade http://forum.doom9.org/showthread.php?p=1570968#post1570968
#ConvertToRGB32.HistogramRGBParade ##
#Histogram(mode="levels") 
Histogram(mode="color2")

return Last

#######################################
### emulate color temperature changes in three luma ranges
##
## @ offset_x - arbitrary units; <0 means lower temp (warmer colors)
##     (input range is unlimited, but is normally around -20 to +20; default 0)
##
function CheapColorTemp(clip C, 
\            int offset_lo, int offset_mid, int offset_hi)
{
    Assert(C.IsYUV, "CheapColorTemp: source must be YUV")

    return C.ColorYUVx3(
    \          off_u_lo =offset_lo,  off_v_lo =Round(-0.7*offset_lo),
    \          off_u_mid=offset_mid, off_v_mid=Round(-0.7*offset_mid),
    \          off_u_hi =offset_hi,  off_v_hi =Round(-0.7*offset_hi))
}

#######################################
### apply ColorYUV U & V offsets to three luma ranges
##
## @ off_x   - see ColorYUV
## @ xover_x - aproximate 50% luma blend between ranges
##     ( no reason to mess with this)
## @ showmasks - if true, show original + 3 masks in quad split
##
function ColorYUVx3(clip C,
\           float "off_u_lo", float "off_u_mid", float "off_u_hi",   
\           float "off_v_lo", float "off_v_mid", float "off_v_hi",
\           float "xover_lomid", float "xover_midhi",
\           bool "showmasks")
{
    off_u_lo  = Float(Default(off_u_lo,  0.0))
    off_u_mid = Float(Default(off_u_mid, 0.0))
    off_u_hi  = Float(Default(off_u_hi,  0.0))
    off_v_lo  = Float(Default(off_v_lo,  0.0))
    off_v_mid = Float(Default(off_v_mid, 0.0))
    off_v_hi  = Float(Default(off_v_hi,  0.0))
    xlo = Min(Max(  0, Default(xover_lomid, 102)), 127) * 3.0 / 256
    xhi = Min(Max(128, Default(xover_midhi, 191)), 255) * 3.0 / 256
    showmasks = Default(showmasks, false)

    C_lo  = C.ColorYUV(off_u=off_u_lo,  off_v=off_v_lo)
    C_mid = C.ColorYUV(off_u=off_u_mid, off_v=off_v_mid)
    C_hi  = C.ColorYUV(off_u=off_u_hi,  off_v=off_v_hi)

    ## mt_lutxyz too slow!!

    mask_lo  = C.mt_lut(
    \   yexpr="x -0.01 * "+String(xlo)+" + 256 * ",
    \   u=-128, v=-128)
    
    mask_hi  = C.mt_lut(
    \   yexpr="1 x -0.01 * "+String(xhi)+" + - 256 * ",
    \   u=-128, v=-128)
    
    mask_mid = mt_lutxy(mask_lo, mask_hi, "x  y + -1 * 256 + ", u=-128, v=-128)
    
    return (showmasks)
    \  ? StackVertical(
    \       StackHorizontal(C, mask_lo),
    \       StackHorizontal(mask_mid, mask_hi))
    \       .BilinearResize(C.Width, C.height)
    \       .Subtitle("Low",    align=9)
    \       .Subtitle("\nMid",  align=4, lsp=0)
    \       .Subtitle("\nHigh", align=6, lsp=0)
    \  : C.Overlay(C_lo,  mask=mask_lo)
    \       .Overlay(C_mid, mask=mask_mid)
    \       .Overlay(C_hi,  mask=mask_hi)
}

Last edited by raffriff42; 18th March 2017 at 01:01. Reason: (fixed image links)
raffriff42 is offline   Reply With Quote
Old 7th March 2014, 07:53   #7  |  Link
raffriff42
Retried Guesser
 
raffriff42's Avatar
 
Join Date: Jun 2012
Posts: 1,377
Here's my gamma-adjusted raw data, converted to video, to show the color follows a straight line on a U-V vectorscope. As you can see when viewing this script, there isn't much point to doing more than simply tweaking U and V.
Code:
C = BlankClip(length=1, color=_rgb(226,  77,  12))._sub("2000K")
\ + BlankClip(length=1, color=_rgb(224,  93,  30))._sub("2200K")
\ + BlankClip(length=1, color=_rgb(219, 110,  47))._sub("2500K")
\ + BlankClip(length=1, color=_rgb(216, 120,  60))._sub("2700K")
\ + BlankClip(length=1, color=_rgb(212, 130,  72))._sub("2900K")
\ + BlankClip(length=1, color=_rgb(206, 141,  85))._sub("3200K")
\ + BlankClip(length=1, color=_rgb(198, 148, 100))._sub("3500K")
\ + BlankClip(length=1, color=_rgb(192, 158, 112))._sub("3800K")
\ + BlankClip(length=1, color=_rgb(182, 162, 127))._sub("4200K")
\ + BlankClip(length=1, color=_rgb(176, 167, 141))._sub("4600K")
\ + BlankClip(length=1, color=_rgb(167, 171, 152))._sub("5000K")
\ + BlankClip(length=1, color=_rgb(160, 174, 164))._sub("5500K")
\ + BlankClip(length=1, color=_rgb(152, 176, 175))._sub("6000K")
\ + BlankClip(length=1, color=_rgb(148, 178, 179))._sub("6600K")
\ + BlankClip(length=1, color=_rgb(141, 178, 192))._sub("7200K")
\ + BlankClip(length=1, color=_rgb(136, 178, 201))._sub("7900K")
\ + BlankClip(length=1, color=_rgb(132, 178, 207))._sub("8600K")
\ + BlankClip(length=1, color=_rgb(127, 178, 213))._sub("9400K")
\ + BlankClip(length=1, color=_rgb(124, 178, 217))._sub("10000K")
\ + BlankClip(length=1, color=_rgb(120, 178, 221))._sub("11000K")
\ + BlankClip(length=1, color=_rgb(116, 178, 226))._sub("12000K")
\ + BlankClip(length=1, color=_rgb(112, 178, 228))._sub("13000K")
\ + BlankClip(length=1, color=_rgb(109, 174, 237))._sub("15000K")
\ + BlankClip(length=1, color=_rgb(105, 174, 239))._sub("16000K")
\ + BlankClip(length=1, color=_rgb(101, 174, 242))._sub("18000K")
\ + BlankClip(length=1, color=_rgb(101, 174, 245))._sub("19000K")
\ + BlankClip(length=1, color=_rgb(101, 172, 249))._sub("21000K")
\ + BlankClip(length=1, color=_rgb(100, 172, 252))._sub("23000K")
\ + BlankClip(length=1, color=_rgb(100, 172, 254))._sub("25000K")
\ + BlankClip(length=1, color=_rgb(100, 172, 255))._sub("28000K")

C.ConvertToYV12()
Histogram(mode="color2")
Loop
AssumeFPS(10)
return Last

function _rgb(int R, int G, int B) 
{ 
    return R*65536 + G*256 + B 
}

function _sub(clip C, string s)
{
    return C.Subtitle(s, text_color=$808080, align=5, size=C.Height/16) 
}

__END__

Black Body (Wikipedia)
digitized from graphic image
corrected for gamma=1.8

TEMP      R       G       B
2000      226      77      12
2200      224      93      30
2500      219     110      47
2700      216     120      60
2900      212     130      72
3200      206     141      85
3500      198     148     100
3800      192     158     112
4200      182     162     127
4600      176     167     141
5000      167     171     152
5500      160     174     164
6000      152     176     175
6600      148     178     179
7200      141     178     192
7900      136     178     201
8600      132     178     207
9400      127     178     213
10000     124     178     217
11000     120     178     221
12000     116     178     226
13000     112     178     228
15000     109     174     237
16000     105     174     239
18000     101     174     242
19000     101     174     245
21000     101     172     249
23000     100     172     252
25000     100     172     254
28000     100     172     255

Last edited by raffriff42; 7th March 2014 at 08:08. Reason: _sub
raffriff42 is offline   Reply With Quote
Old 7th March 2014, 18:54   #8  |  Link
Leo D9
Registered User
 
Join Date: Feb 2013
Posts: 9
Thanks raffriff42. I was hoping someone would just "know" the "right" answer/solution, but I see you've gone to a lot of effort to produce something usable from scratch! I'll have to give it a go when I get a moment. I've never used MaskTools but I think I roughly understand what's going on in the code - are you basically leaving the Y channel alone and applying a curve to the U channel and a separate curve to the V channel? Each curve is defined by three numbers. Because of the 50% cross-over this means each curve is essentially made up of 5 straight lines. Correct?

If luma stays pretty much the same as you say this sounds like a good solution for "black body" light sources, but what about green-magenta shift (such as for the green cast produced by fluorescent lights)?

(As the Wikipedia article mentions: ...ineffective with sources such as fluorescent or discharge lamps, whose light varies in colour and may be harder to correct for. Because it is often greenish, a magenta filter may correct it. More sophisticated colorimetry tools can be used...)

How did you come to use gamma 1.8? I followed the link for the animated GIF you used, which is apparently based on sRGB, using the table of RGB values for colour temperature listed here:

http://www.vendian.org/mncharity/dir3/blackbody/

So sRGB would be RGB levels 0-255 using Rec.709 colour primaries. Wikipedia says:

Unlike most other RGB color spaces, the sRGB gamma cannot be expressed as a single numerical value. The overall gamma is approximately 2.2, consisting of a linear (gamma 1.0) section near black, and a non-linear section elsewhere involving a 2.4 exponent and a gamma (slope of log output versus log input) changing from 1.0 through about 2.3.

Also, I wonder what effect matrix Rec.709 vs Rec.601 has on your system.

I was kinda hoping there would be a simple solution that doesn't require plugins. I had thought of doing something similar to your MaskTools code using Levels() multiple times to select lows, mids and highs, scale or adjust them, then re-combine with Layer() (using op="lighten" or op="darken") or possibly Merge(). Very useful to know if/that the luma doesn't need changing.

I wonder if it "makes sense" to use your system rather than converting to RGB and back. Using MaskTools, masks and three Overlay() calls would presumably be slower than YUV-RGB-YUV conversions and channel scaling, and I think green-magenta shift may be easer to correct in RGB. But correct colour temperature adjustment in RGB may be complex too. It's quite nice if the luma channel doesn't need to be tampered with in YUV.

Thanks again.

Last edited by Leo D9; 7th March 2014 at 18:57.
Leo D9 is offline   Reply With Quote
Old 7th March 2014, 21:09   #9  |  Link
raffriff42
Retried Guesser
 
raffriff42's Avatar
 
Join Date: Jun 2012
Posts: 1,377
Hi Leo D9, thanks for your feedback.

Yes, I am leaving the Y channel completely alone, and adding offsets to the U and V channels.

Re: green-magenta shift, you could call ColorYUVx3() directly instead of through CheapColorTemp(), and adjust the offsets as required; I'd suggest adding a vectorscope, eg Histogram(mode="color2"), so you can see what you are doing. Find something in the video that should be white, or black, or gray, and adjust the appropriate offsets to center the color in the vectorscope.

Sorry about the plugin requirement, but I consider Masktools2 ("alpha 48") to be fundamental, as it's used by so many scripts. It's one of a very few plugins I allow to auto load.

re gamma 1.8, it was a judgement call; I happen to agree with the author of
The Monitor calibration and Gamma assessment page
Quote:
My personal preference is to set a system gamma of 1.8, even though I use a PC.
I'll explain why I made this decision, and you can choose to agree or ignore me, as you wish.

Reason 1, and most fundamental, is that a gamma of 2.2 is just too damned dark!
...
I don't know if this method makes sense - it's a hack. Any "real" color corrector would convert to RGB. Avisynth is not really the right tool for color correction - except that it's scriptable and fits into an existing Avisynth workflow. As suggested by smok3, Da Vinci Resolve Lite is an excellent color correction tool.

This method is very subjective and not mathematically correct. That said, I think it looks good and it simple to use, with only 3 parameters to worry about (only two of which are really used - offset_lo should be left alone unless black balancing is needed).

By the way, to do white/black/gray balancing in RGB without plugins, you can do this:
Code:
MergeRGB(
\    ShowRed("Y8")   .Levels(0, 1.0, 255, 0, 255, coring=false),
\    ShowGreen("Y8") .Levels(0, 1.0, 255, 0, 255, coring=false),
\    ShowBlue("Y8")  .Levels(0, 1.0, 255, 0, 255, coring=false))
...it's probably best to find the parameters using a visual tool like Photoshop, then copy the numbers over. Too much work if you are correcting scene-by-scene.

Last edited by raffriff42; 7th March 2014 at 21:50. Reason: vectorscope, code
raffriff42 is offline   Reply With Quote
Old 8th March 2014, 19:54   #10  |  Link
Reel.Deel
Registered User
 
Join Date: Mar 2012
Location: Texas
Posts: 1,084
Hey there Leo D9, thanks for creating this thread, it reminded me of something I had started but had forgotten.

You might want to try WhiteBalance (recently added to the wiki ). The documentation contains some good information regarding white balance.

Another suggestion is AWB (Automatic White Balance); the script is heavily commented with useful information.

Hope this helps.
Reel.Deel is offline   Reply With Quote
Old 10th March 2014, 09:53   #11  |  Link
pandy
Registered User
 
Join Date: Mar 2006
Posts: 1,038
My two cents is - you can do white balance in RGB space, read offsets in YUV and then repeat but only in YUV space - so do measurements in RGB but correction in YUV - should be comparable without conversions RGB<>YUV.
pandy is offline   Reply With Quote
Old 10th March 2014, 18:56   #12  |  Link
Bernardd
Registered User
 
Join Date: Jan 2012
Location: Toulon France
Posts: 181
Hello RaffRiff42

Your white balance observations are impressive.
I agree with you. Your method is very subjective and perhaps not mathematically correct. But you show well that luma range selectivity is more important than mathematical correctness for warm colors.
I have changed your script to use auto white balance function of ColorYUV and to display the different luma range outputs for warm color choice.
I have not your perfect masktools knowledge. So i have keep your script part relative to mask creation and use.

What you think about this fork of your process. Do you know limit of this approach ?

Code:
##Last=YUV  

## From CheapColorTemp demonstration, mod auto white balance version
## stack between original and several corrections
## (view in step mode; not for real time playback)


StackVertical(
\StackHorizontal(last.Subtitle("original"),CheapColorTempAuto(1,0,0).Subtitle("AWB lo")),
\StackHorizontal(last.Subtitle("original"),CheapColorTempAuto(0,1,0).Subtitle("AWB mid")),
\ StackHorizontal(last.Subtitle("original"),CheapColorTempAuto(0,0,1).Subtitle("AWB hi")),
\StackHorizontal(last.Subtitle("original"),last.ColorYuv(autowhite=true).Subtitle("AWB ColorYuv")))


return last

#######################################
### emulate color temperature changes in three luma ranges
##
##
function CheapColorTempAuto(clip C, int lo_auto, int mid_auto, int hi_auto)
{
    Assert(C.IsYUV, "CheapColorTemp: source must be YUV")
 
   lo_auto = Default(lo_auto, 0)
   mid_auto = Default(mid_auto, 0)
    hi_auto = Default(hi_auto, 0)

    return C.ColorYUVxAuto(lo_auto = lo_auto, mid_auto = mid_auto, hi_auto = hi_auto)
}

#######################################
### apply ColorYUV autowhite to three luma ranges
##
## @ xover_x - aproximate 50% luma blend between ranges
##     ( no reason to mess with this)
## @ showmasks - if true, show original + 3 masks in quad split
##
function ColorYUVxAuto(clip C,
\ int "lo_auto",int "mid_auto", int "hi_auto",
\ float "xover_lomid", float "xover_midhi",
\           bool "showmasks")
{
    lo_auto = Default(lo_auto, 0)
   mid_auto = Default(mid_auto, 0)
    hi_auto = Default(hi_auto, 0)
    
    xlo = Min(Max(  0, Default(xover_lomid, 102)), 127) * 3.0 / 256
    xhi = Min(Max(128, Default(xover_midhi, 191)), 255) * 3.0 / 256
    showmasks = Default(showmasks, false)

    (lo_auto == 1) ? C.ColorYUV(autowhite=true) : C
    C_lo_auto  = last
    (mid_auto == 1) ? C.ColorYUV(autowhite=true) : C
    C_mid_auto = last
    (hi_auto == 1) ? C.ColorYUV(autowhite=true) : C
    C_hi_auto  = last

    ## mt_lutxyz too slow!!

    mask_lo  = C.mt_lut(
    \   yexpr="x -0.01 * "+String(xlo)+" + 256 * ",
    \   u=-128, v=-128)
    
    mask_hi  = C.mt_lut(
    \   yexpr="1 x -0.01 * "+String(xhi)+" + - 256 * ",
    \   u=-128, v=-128)
    
    mask_mid = mt_lutxy(mask_lo, mask_hi, "x  y + -1 * 256 + ", u=-128, v=-128)
    
    return (showmasks)
    \  ? StackVertical(
    \       StackHorizontal(C, mask_lo),
    \       StackHorizontal(mask_mid, mask_hi))
    \       .BilinearResize(C.Width, C.height)
    \       .Subtitle("Low",    align=9)
    \       .Subtitle("\nMid",  align=4, lsp=0)
    \       .Subtitle("\nHigh", align=6, lsp=0)
    \  : C.Overlay(C_lo_auto,  mask=mask_lo)
    \       .Overlay(C_mid_auto, mask=mask_mid)
    \       .Overlay(C_hi_auto,  mask=mask_hi)
}
Bernardd is offline   Reply With Quote
Old 10th March 2014, 20:21   #13  |  Link
raffriff42
Retried Guesser
 
raffriff42's Avatar
 
Join Date: Jun 2012
Posts: 1,377
Bernardd, thank you very much for taking the time to thoroughly read my post. I'm so glad you can find some agreement with my thoughts on this.

Re: your fork, it is very welcome as far as I'm concerned. I have to say though: I have never used any "auto" color balance script, as I fear they will try to correct things that don't need correction -- forcing a blue sky to white is one example mentioned in the wiki. I prefer to balance the colors manually for each shot (as I said above, over-simplifying, "Find something in the video that should be white, or black, or gray, and adjust the appropriate offsets to center the color in the vectorscope.")

Of course, everyone's needs are different, and auto mode may be just the thing for certain situations - for example, I suppose it must be very helpful for repairing home movies where the camera operator had no concept of color temperature.

For an extreme illustration of the problems with auto white balance , take this shot from a video game, which is supposed to portray the golden light of early morning on the Côte d'Azur (in your part of the world?)


If corrections like these are to be made (I'm not saying they are necessarily bad), I would prefer to have some kind of manual override:



Last edited by raffriff42; 18th March 2017 at 00:59. Reason: (fixed image links)
raffriff42 is offline   Reply With Quote
Old 23rd March 2014, 18:07   #14  |  Link
Bernardd
Registered User
 
Join Date: Jan 2012
Location: Toulon France
Posts: 181
Hello,

After many tests, i have written this little script to enable automatic Coloryuv strength tune. For best look result and for smart tune action, i have use raffriff 42's luma ranges proposal.

This script is based on AvsPmod user sliders use.

Code:
ori_chroma=last.Info_Chroma().Subtitle("original")
ori_luma=last.Info_Luma().Subtitle("original")

[< separator="Output choice">]
[< separator="          0 = production ">]
[< separator="          1 = Automatic White Balance tune">]
[< separator="          2 = Automatic gain tune">]

choice = [<"choice", 0, 2, 2>]
# -------------------------------------------------  Tones mask ------------------------------------------

LoadPlugin("C:\mt_masktools-25.dll")

xlo = 62 * 3.0 / 256
xhi = 191 * 3.0 / 256
mask_lo  = mt_lut(
    \   yexpr="x -0.01 * "+String(xlo)+" + 256 * ",
    \   u=-128, v=-128)
    
mask_hi  = mt_lut(
    \   yexpr="1 x -0.01 * "+String(xhi)+" + - 256 * ",
    \   u=-128, v=-128)
    
mask_mid = mt_lutxy(mask_lo, mask_hi, "x  y + -1 * 256 + ", u=-128, v=-128)
 
#--------------------------------------------- AWB --------------------------------------
[< separator="Automatic White Balance tune">]

force_AWB_lo = [<"Automatic White Balance strength on shadows tones", 0.0, 1.0, 1.0>]
force_AWB_mid = [<"Automatic White Balance strength on midtones", 0.0, 1.0, 1.0>]
force_AWB_hi = [<"Automatic White Balance strength on hightlights tones", 0.0, 1.0, 1.0>]
awb=ColorYUV(AutoWhite=true)
awb_info=awb.Info_Chroma().Subtitle("simple AWB")
awb_mod=Overlay(awb, mask = mask_lo, opacity=force_AWB_lo, mode="chroma").Overlay(awb, mask = mask_mid, opacity=force_AWB_mid, mode="chroma")
\.Overlay(awb, mask = mask_hi, opacity=force_AWB_hi, mode="chroma")
awb_mod_info=awb_mod.Info_Chroma().Subtitle("tuned AWB")

#--------------------------------------------- Autogain ------------------------------------------
[< separator="Réglage du niveau automatique de gain">]

force_AWB_lo = [<"force du gain automatique tons sombres", 0.0, 1.0, 1.0>]
force_AWB_mid = [<"force du gain automatique tons moyens", 0.0, 1.0, 1.0>]
force_AWB_hi = [<"force du gain automatique tons clairs", 0.0, 1.0, 1.0>]
autogain = awb_mod.ColorYUV(Autogain=true)
autogain_info = autogain.Info_luma().Subtitle("simple autogain")
autogain_mod =awb_mod.Overlay(autogain, mask = mask_lo, opacity=force_AWB_lo, mode="luma").Overlay(autogain, mask = mask_mid, opacity=force_AWB_mid, mode="luma")
\.Overlay(autogain, mask = mask_hi, opacity=force_AWB_hi, mode="luma")
autogain_mod_info = autogain_mod.Info_luma().Subtitle("tuned autogain")

#------------------------------------------- Results

(choice==1) ? StackHorizontal (ori_chroma,awb_info,awb_mod_info).Histogram("levels") :
\((choice==2) ? StackHorizontal (ori_luma,autogain_info,autogain_mod_info)  : autogain_mod)



# ----------------------------------------Function info

function Info_chroma(clip c)
{
c.ScriptClip("""
    acu = AverageChromaU()
    acv = AverageChromaV()    
    Subtitle("Average_Chroma_U = " + String(acu),y=40)
    Subtitle("Average_Chroma_V = " + String(acv),y=60)
    Subtitle("difference_U_V = " + String(acu-acv),y=80)
    Subtitle("moyenne_U_V = " + String((acu+acv)/2),y=100)
""")
return last
}

function Info_luma(clip c)
{
c.ScriptClip("""
    aly = AverageLuma()
    Subtitle("AverageLuma = " + String(aly),y=40)
""")
return last
}
The purpose of this little script is to only amend automatic coloryuv use, not to amend AWB and Autogain functions.
Bernardd is offline   Reply With Quote
Old 26th March 2014, 17:50   #15  |  Link
Bernardd
Registered User
 
Join Date: Jan 2012
Location: Toulon France
Posts: 181
Hello,

I use Avisynth script for old super 8 or 8 mm restoration. So i have sometimes problems with dominant color. Because for me old movies are in accordance with some faults,
I do not search perfect white balance, but i search a pleasant look. So i use coloryuv auto functions, but sometimes the look is no good.

Raffriff42's observation and demonstration on luma range proceeded white balance, give me idea to get more detail actions.

So I have written this function to tune the Coloryuv auto functions, it request Masktools2 plugin load :

Code:
function Auto_ColorYUV_Strenght(clip clip, float "strenght_AWB_lo", float "strenght_AWB_mid", float "strenght_AWB_hi",
                                        \  float "strenght_Autogain_lo",float "strenght_Autogain_mid",float "strenght_Autogain_hi",
                                        \  bool "Show_Help_Display",bool "Show_AWB_or_Autogain_Strenght")
{

Assert(clip.IsYUV, "CheapColorTemp: source must be YUV")

Show_Help_Display = Default(Show_Help_Display, false)  
Show_AWB_or_Autogain_Strenght = Default(Show_AWB_or_Autogain_Strenght, true)   


#--------------------------------------------- Information clip  --------------------------------------------
 
ori=clip.Subtitle("original")
ori_chroma=clip.Info_Chroma().Subtitle("original")
ori_luma=clip.Info_Luma().Subtitle("original")

# -------------------------------------------------   Tones mask ------------------------------------------

xlo = 62 * 3.0 / 256
xhi = 191 * 3.0 / 256
mask_lo  = clip.mt_lut(
    \   yexpr="x -0.01 * "+String(xlo)+" + 256 * ",
    \   u=-128, v=-128)
    
mask_hi  = clip.mt_lut(
    \   yexpr="1 x -0.01 * "+String(xhi)+" + - 256 * ",
    \   u=-128, v=-128)
    
mask_mid = mt_lutxy(mask_lo, mask_hi, "x  y + -1 * 256 + ", u=-128, v=-128)

#--------------------------------------------- AWB --------------------------------------

strenght_AWB_lo = Default(strenght_AWB_lo, 1.0) # Automatic White Balance strength on shadows tones, between 0.0 and 1.0, default 1.0
strenght_AWB_mid = Default(strenght_AWB_mid, 1.0) # Automatic White Balance strength on midtones, between 0.0 and 1.0, default 1.0
strenght_AWB_hi = Default(strenght_AWB_hi, 1.0) # Automatic White Balance strength on hightlights tones, between 0.0 and 1.0, default 1.0

awb=clip.ColorYUV(autoWhite=true)
awb_info=awb.Info_Chroma().Subtitle("default AWB")
awb_mod=clip.Overlay(awb, mask = mask_lo, opacity=strenght_AWB_lo, mode="chroma").Overlay(awb, mask = mask_mid, opacity=strenght_AWB_mid, mode="chroma")
\.Overlay(awb, mask = mask_hi, opacity=strenght_AWB_hi, mode="chroma")
awb_mod_info=awb_mod.Info_Chroma().Subtitle("Tuned AWB")

#--------------------------------------------- Autogain ------------------------------------------

strenght_Autogain_lo = Default(strenght_Autogain_lo, 1.0) # Autogain strength on shadows tones, between 0.0 and 1.0, default 1.0
strenght_Autogain_mid = Default(strenght_Autogain_mid, 1.0) # Autogain strength on midtones, between 0.0 and 1.0, default 1.0
strenght_Autogain_hi = Default(strenght_Autogain_hi, 1.0) # Autogain strength on hightlights tones, between 0.0 and 1.0, default 1.0

autogain = awb_mod.ColorYUV(autogain=true)
autogain_info = autogain.Info_luma().Subtitle("Default Autogain")
autogain_mod =awb_mod.Overlay(autogain, mask = mask_lo, opacity=strenght_Autogain_lo, mode="luma").Overlay(autogain, mask = mask_mid, opacity=strenght_Autogain_mid, mode="luma")
\.Overlay(autogain, mask = mask_hi, opacity=strenght_Autogain_hi, mode="luma")
autogain_mod_info = autogain_mod.Info_luma().Subtitle("Tuned Autogain")


#------------------------------------------- Results

(Show_Help_Display == true) ? ((Show_AWB_or_Autogain_Strenght == true) ? StackHorizontal (ori_chroma,awb_info,awb_mod_info).Histogram("levels") :
\ StackHorizontal (ori_luma,autogain_info,autogain_mod_info).Histogram("levels")) :
\autogain_mod
return last
}

# ---------------------------------------- Info functions

function Info_chroma(clip c)
{
c.ScriptClip("""
    acu = AverageChromaU()
    acv = AverageChromaV()
    Subtitle("correction U = " + String(127-acu),y=20)    
    Subtitle("correction V = " + String(127-acv),y=40)
   
    Subtitle("moyenne_U_V = " + String((acu+acv)/2),y=60)
""")
return last
}

function Info_luma(clip c)
{
c.ScriptClip("""
    aly = AverageLuma()
    Subtitle("AverageLuma = " + String(aly),y=40)
""")
return last
}
For best results, it is good to proceed scene by scene, but sometimes, i have found acceptable strenght values for a 3 mn long video.

Last edited by Bernardd; 27th March 2014 at 09:17.
Bernardd is offline   Reply With Quote
Old 3rd April 2014, 21:45   #16  |  Link
Bernardd
Registered User
 
Join Date: Jan 2012
Location: Toulon France
Posts: 181
Hello raffriff 42

I have written this function based on your luma range script and avisynth overlay internal function opacity tune. It is like a manual RGB problem soluce way in YUV world.
It is possible with it to process manual white balance.
For easy test of this function, in script end, is written a function call script with AvsPmod usersliders use.

Code:
function Other_colors(clip clip, int "limit_lo", int "limit_hi",                                       
                                        \  float "color_red_invert", float "color_green_invert", float "color_blue_invert",
                                        \  float "color_lo_red", float "color_mid_red", float "color_hi_red",
                                        \  float "color_lo_green",float "color_mid_green",float "color_hi_green",
                                        \  float "color_lo_blue",float "color_mid_blue",float "color_hi_blue",
                                        \ float "color_lo_black", float "color_mid_black", float "color_hi_black",
                                        \ float "color_lo_white", float "color_mid_white", float "color_hi_white",
                                        \  float "contrast_lo",float "contrast_mid",float "contrast_hi",
                                        \  bool "show_mask_color")
                                        
{

Assert(clip.IsYUV, "CheapColorTemp: source must be YUV")

show_mask_color = Default(show_mask_color, false)  




#---------------------------------------------  Masks making ----------------------------------------    
 

limit_lo = Default(limit_lo, 62) # seuil bas between in 0 et 190, valeur par default 62
limit_hi = Default(limit_hi, 191) # seuil bas between in 191 et 255, valeur par default 191

xlo_color = limit_lo * 3.0 / 256
xhi_color = limit_hi * 3.0 / 256

mask_lo_color   mt_lut(clip,
    \   yexpr="x -0.01 * "+String(xlo_color)+" + 256 * ",
    \   u=-128, v=-128) 
   
mask_hi_color   mt_lut(clip,
    \   yexpr="1 x -0.01 * "+String(xhi_color)+" + - 256 * ",
    \   u=-128, v=-128) 
    
mask_mid_color = (mask_version == 0) ? mt_lutxy(mask_lo_color, mask_hi_color, "x  y + -1 * 256 + ", u=-128, v=-128)

control_mask = StackHorizontal(mask_lo_color.Subtitle("mask lo"),mask_mid_color.Subtitle("mask mid"),mask_hi_color.Subtitle("mask hi"))

#-------------------------------------------- Add colors tuning


color_red_invert = Default(color_red_invert, 0.0) # percentage between red color and her invert color
color_lo_red = Default(color_lo_red, 0.0) # red add percentage in shadows toness, between in 0.0, 1.0, default 0.0
color_mid_red = Default(color_mid_red, 0.0) # red add percentage in midtones, between in 0.0, 1.0, default 0.0
color_hi_red = Default(color_hi_red, 0.0) # red add percentage in highlights tones, between in 0.0, 1.0, default 0.0

color_green_invert = Default(color_green_invert, 0.0) # percentage between green color and her invert color
color_lo_green = Default(color_lo_green, 0.0) # green add percentage in shadows toness, between in 0.0, 1.0, default 0.0
color_mid_green = Default(color_mid_green, 0.0) # green add percentage in midtones, between in 0.0, 1.0, default 0.0
color_hi_green = Default(color_hi_green, 0.0) # green add percentage in highlights tones, between in 0.0, 1.0, default 0.0

color_blue_invert = Default(color_blue_invert,  0.0) # percentage between blue color and her invert color
color_lo_blue = Default(color_lo_blue, 0.0) # blue add percentage in shadows toness, between in 0.0, 1.0, default 0.0
color_mid_blue = Default(color_mid_blue, 0.0) # blue add percentage in midtones, between in 0.0, 1.0, default 0.0
color_hi_blue = Default(color_hi_blue, 0.0) # blue add percentage in highlights tones, between in 0.0, 1.0, default 0.0

color_red = Overlay(BlankClip(clip , color=$FF0000), BlankClip(clip , color=$FF0000).invert, opacity = color_red_invert, mode = "Chroma")
color_green = Overlay(BlankClip(clip , color=$00FF00), BlankClip(clip , color=$00FF00).invert, opacity = color_green_invert, mode = "Chroma")
color_blue  = Overlay(BlankClip(clip , color=$0000FF), BlankClip(clip , color=$0000FF).invert, opacity = color_blue_invert, mode = "Chroma")

#-------------------------------------------- Luma tunning

color_lo_black = Default(color_lo_black, 0.0) #black add percentage in shadows toness, between in 0.0, 1.0, default 0.0
color_mid_black = Default(color_mid_black, 0.0) # black add percentage in midtones, between in 0.0, 1.0, default 0.0
color_hi_black = Default(color_hi_black, 0.0) # black add percentage in highlights tones, between in 0.0, 1.0, default 0.0

color_lo_white = Default(color_lo_white, 0.0) # white add percentage in shadows toness, between in 0.0, 1.0, default 0.0
color_mid_white = Default(color_mid_white, 0.0) # white add percentage in midtones, between in 0.0, 1.0, default 0.0
color_hi_white = Default(color_hi_white, 0.0) # white add percentage in highlights tones, between in 0.0, 1.0, default 0.0

color_black = BlankClip(clip , color=$000000)
color_white = BlankClip(clip , color=$FFFFFF)

color_sup = clip.Overlay(color_green, mask = mask_lo_color, opacity=color_lo_green, mode="chroma",greymask=true).Overlay(color_green, mask = mask_mid_color, opacity=color_mid_green, mode="chroma",greymask=true)
\.Overlay(color_green, mask = mask_hi_color, opacity=color_hi_green, mode="chroma",greymask=true).
\Overlay(color_red, mask = mask_lo_color, opacity=color_lo_red, mode="chroma",greymask=true).Overlay(color_red, mask = mask_mid_color, opacity=color_mid_red, mode="chroma",greymask=true)
\.Overlay(color_red, mask = mask_hi_color, opacity=color_hi_red, mode="chroma",greymask=true).
\Overlay(color_blue, mask = mask_lo_color, opacity=color_lo_blue, mode="chroma",greymask=true).Overlay(color_blue, mask = mask_mid_color, opacity=color_mid_blue, mode="chroma",greymask=true)
\.Overlay(color_blue, mask = mask_hi_color, opacity=color_hi_blue, mode="chroma",greymask=true).
\Overlay(color_black, mask = mask_lo_color, opacity=color_lo_black, mode="luma",greymask=true).Overlay(color_black, mask = mask_mid_color, opacity=color_mid_black, mode="luma",greymask=true)
\.Overlay(color_black, mask = mask_hi_color, opacity=color_hi_black, mode="luma",greymask=true).
\Overlay(color_white, mask = mask_lo_color, opacity=color_lo_white, mode="luma",greymask=true).Overlay(color_white, mask = mask_mid_color, opacity=color_mid_white, mode="luma",greymask=true)
\.Overlay(color_white, mask = mask_hi_color, opacity=color_hi_white, mode="luma",greymask=true)

# ------------------------------------------ contrast

contrast_lo = Default(contrast_lo, 0.0) # contrast percentage in shadows toness, between in 0.0, 1.0, default 0.0
contrast_mid = Default(contrast_mid, 0.0) # contrast percentage in midtones, between in 0.0, 1.0, default 0.0
contrast_hi = Default(contrast_hi, 0.0) # contrast percentage in highlights tones, between in 0.0, 1.0, default 0.0
color_contr = color_sup.Overlay(color_sup, mask = mask_lo_color, opacity=contrast_lo, mode="add").Overlay(color_sup, mask = mask_mid_color, opacity=contrast_mid, mode="add")
\.Overlay(color_sup, mask = mask_hi_color, opacity=contrast_hi, mode="add")

#------------------------------------------- Results

(show_mask_color == true) ? control_mask : color_contr
return last
}

__END__
# paths to be customised
Source # Your source
LoadPlugin("C:\...........\mt_masktools-25.dll")
Import("C:\..........\Add colors function.avs ") # If you have saved this function script with this file name
[color addition=1]
[< separator="Add color tuning">]
show = [<"Show tones masks (no = 0 et yes = 1)", 0, 1, 0>] 
show_mask_color  = (show == 1) ? true : false

[< separator="Mask tuning">]
limit_lo=[<"limit_lo", 0, 190, 62>]
limit_hi=[<"limit_hi", 191, 255, 191>]

[< separator="Add colors percentage tuning ">]
[< separator="       red addition">]
color_red_invert = [<"percentage between red color and her invert color", 0.0, 1.0, 0.0>]
color_lo_red = [<"red add percentage in shadows tones", 0.0, 1.0, 0.0>]
color_mid_red = [<"red add percentage in midtones", 0.0, 1.0, 0.0>]
color_hi_red = [<"red add percentage in highlights tones", 0.0, 1.0, 0.0>]
[< separator="       green addition">]
color_green_invert = [<"percentage between green color and her invert color", 0.0, 1.0, 0.0>]
color_lo_green = [<"green add percentage in shadows tones", 0.0, 1.0, 0.0>]
color_mid_green = [<"green add percentage in midtones", 0.0, 1.0, 0.0>]
color_hi_green = [<"green add percentage in highlights tones", 0.0, 1.0, 0.0>]
[< separator="       blue addition">]
color_blue_invert = [<"percentage between blue color and her invert color", 0.0, 1.0, 0.0>]
color_lo_blue = [<"blue add percentage in shadows tones", 0.0, 1.0, 0.0>]
color_mid_blue = [<"blue add percentage in midtones", 0.0, 1.0, 0.0>]
color_hi_blue = [<"blue add percentage in highlights tones", 0.0, 1.0, 0.0>]

[< separator="Luma tuning">]
[< separator="More dark">]
color_lo_black = [<"black add percentage in shadows tones", 0.0, 1.0, 0.0>]
color_mid_black = [<"black add percentage in midtones", 0.0, 1.0, 0.0>]
color_hi_black = [<"black add percentage in highlights tones", 0.0, 1.0, 0.0>]
[< separator="More light">]
color_lo_white = [<"white add percentage in shadows tones", 0.0, 1.0, 0.0>]
color_mid_white = [<"white add percentage in midtones", 0.0, 1.0, 0.0>]
color_hi_white = [<"white add percentage in highlights tones", 0.0, 1.0, 0.0>]

[< separator="Contrast tuning">]
contrast_lo = [<"contrast add percentage in shadows tones", 0.0, 1.0, 0.0>]
contrast_mid = [<"contrast add percentage in midtones", 0.0, 1.0, 0.0>]
contrast_hi = [<"contrast add percentage in highlights tones", 0.0, 1.0, 0.0>]

Assert(isclip, "No defined source") # Line to be deleted if you have gived a variable name for the clip

Other_colors(limit_lo = limit_lo, limit_hi = limit_hi,
\color_red_invert = color_red_invert, color_green_invert = color_green_invert, color_blue_invert = color_blue_invert,
\color_lo_red = color_lo_red, color_mid_red = color_mid_red, color_hi_red = color_hi_red,
\color_lo_green = color_lo_green, color_mid_green = color_mid_green, color_hi_green = color_hi_green,
\color_lo_blue = color_lo_blue, color_mid_blue = color_mid_blue, color_hi_blue = color_hi_blue,
\color_lo_black = color_lo_black, color_mid_black = color_mid_black, color_hi_black = color_hi_black,
\color_lo_white = color_lo_white, color_mid_white = color_mid_white, color_hi_white = color_hi_white,
\contrast_lo = contrast_lo, contrast_mid =contrast_mid, contrast_hi = contrast_hi,
\show_mask_color = show_mask_color)

[/color addition]
I think that i should get more accuracy with more luma range zones. But i do not know write masktools formulas for this.
Thus i have put in beginng two variable values for enable little mask making modifications.
What do you think of this trial, is it in accordance with yours observations ?
Thanks
Bernardd is offline   Reply With Quote
Old 4th April 2014, 14:19   #17  |  Link
raffriff42
Retried Guesser
 
raffriff42's Avatar
 
Join Date: Jun 2012
Posts: 1,377
Hello Bernardd, I'm not sure what this script should be doing, as I am not familiar with AvsPmod scripts. I got an error (expected ':') when attempting to preview the script and had to make a change:
Code:
mask_mid_color = /*(mask_version == 0) ? */
\  mt_lutxy(mask_lo_color, mask_hi_color, "x  y + -1 * 256 + ", u=-128, v=-128)
Also, should there be "=" here?
Code:
mask_lo_color /* =  */ mt_lut(clip,
    \   yexpr="x -0.01 * "+String(xlo_color)+" + 256 * ",
    \   u=-128, v=-128) 
   
mask_hi_color /* = */ mt_lut(clip,
    \   yexpr="1 x -0.01 * "+String(xhi_color)+" + - 256 * ",
    \   u=-128, v=-128)
I didn't see any sliders, but again, I'm not too familiar with the program.

As far as customizing the lut equations, maybe this speadsheet will help. It should probably have a term for width at peak gain, but I must leave it for later:

Last edited by raffriff42; 18th March 2017 at 00:53. Reason: (fixed image link)
raffriff42 is offline   Reply With Quote
Old 4th April 2014, 21:39   #18  |  Link
Bernardd
Registered User
 
Join Date: Jan 2012
Location: Toulon France
Posts: 181
Hello RaffRiff42,
I apologize, i have too fast cut trial masks input, thus the script has not been good. You have well find the mistakes.
The good version is below :
Code:
function Other_colors(clip clip, int "limit_lo", int "limit_hi",                                       
                                        \  float "color_red_invert", float "color_green_invert", float "color_blue_invert",
                                        \  float "color_lo_red", float "color_mid_red", float "color_hi_red",
                                        \  float "color_lo_green",float "color_mid_green",float "color_hi_green",
                                        \  float "color_lo_blue",float "color_mid_blue",float "color_hi_blue",
                                        \ float "color_lo_black", float "color_mid_black", float "color_hi_black",
                                        \ float "color_lo_white", float "color_mid_white", float "color_hi_white",
                                        \  float "contrast_lo",float "contrast_mid",float "contrast_hi",
                                        \  bool "show_mask_color")
                                        
{

Assert(clip.IsYUV, "CheapColorTemp: source must be YUV")

show_mask_color = Default(show_mask_color, false)  




#---------------------------------------------  Masks making ----------------------------------------    
 

limit_lo = Default(limit_lo, 62) # seuil bas between in 0 et 190, valeur par default 62
limit_hi = Default(limit_hi, 191) # seuil bas between in 191 et 255, valeur par default 191

xlo_color = limit_lo * 3.0 / 256
xhi_color = limit_hi * 3.0 / 256

mask_lo_color =  mt_lut(clip,
    \   yexpr="x -0.01 * "+String(xlo_color)+" + 256 * ",
    \   u=-128, v=-128) 
   
mask_hi_color =  mt_lut(clip,
    \   yexpr="1 x -0.01 * "+String(xhi_color)+" + - 256 * ",
    \   u=-128, v=-128) 
    
mask_mid_color =  mt_lutxy(mask_lo_color, mask_hi_color, "x  y + -1 * 256 + ", u=-128, v=-128)

control_mask = StackHorizontal(mask_lo_color.Subtitle("mask lo"),mask_mid_color.Subtitle("mask mid"),mask_hi_color.Subtitle("mask hi"))

#-------------------------------------------- Add colors tuning


color_red_invert = Default(color_red_invert, 0.0) # percentage between red color and her invert color
color_lo_red = Default(color_lo_red, 0.0) # red add percentage in shadows toness, between in 0.0, 1.0, default 0.0
color_mid_red = Default(color_mid_red, 0.0) # red add percentage in midtones, between in 0.0, 1.0, default 0.0
color_hi_red = Default(color_hi_red, 0.0) # red add percentage in highlights tones, between in 0.0, 1.0, default 0.0

color_green_invert = Default(color_green_invert, 0.0) # percentage between green color and her invert color
color_lo_green = Default(color_lo_green, 0.0) # green add percentage in shadows toness, between in 0.0, 1.0, default 0.0
color_mid_green = Default(color_mid_green, 0.0) # green add percentage in midtones, between in 0.0, 1.0, default 0.0
color_hi_green = Default(color_hi_green, 0.0) # green add percentage in highlights tones, between in 0.0, 1.0, default 0.0

color_blue_invert = Default(color_blue_invert,  0.0) # percentage between blue color and her invert color
color_lo_blue = Default(color_lo_blue, 0.0) # blue add percentage in shadows toness, between in 0.0, 1.0, default 0.0
color_mid_blue = Default(color_mid_blue, 0.0) # blue add percentage in midtones, between in 0.0, 1.0, default 0.0
color_hi_blue = Default(color_hi_blue, 0.0) # blue add percentage in highlights tones, between in 0.0, 1.0, default 0.0

color_red = Overlay(BlankClip(clip , color=$FF0000), BlankClip(clip , color=$FF0000).invert, opacity = color_red_invert, mode = "Chroma")
color_green = Overlay(BlankClip(clip , color=$00FF00), BlankClip(clip , color=$00FF00).invert, opacity = color_green_invert, mode = "Chroma")
color_blue  = Overlay(BlankClip(clip , color=$0000FF), BlankClip(clip , color=$0000FF).invert, opacity = color_blue_invert, mode = "Chroma")

#-------------------------------------------- Luma tunning

color_lo_black = Default(color_lo_black, 0.0) #black add percentage in shadows toness, between in 0.0, 1.0, default 0.0
color_mid_black = Default(color_mid_black, 0.0) # black add percentage in midtones, between in 0.0, 1.0, default 0.0
color_hi_black = Default(color_hi_black, 0.0) # black add percentage in highlights tones, between in 0.0, 1.0, default 0.0

color_lo_white = Default(color_lo_white, 0.0) # white add percentage in shadows toness, between in 0.0, 1.0, default 0.0
color_mid_white = Default(color_mid_white, 0.0) # white add percentage in midtones, between in 0.0, 1.0, default 0.0
color_hi_white = Default(color_hi_white, 0.0) # white add percentage in highlights tones, between in 0.0, 1.0, default 0.0

color_black = BlankClip(clip , color=$000000)
color_white = BlankClip(clip , color=$FFFFFF)

color_sup = clip.Overlay(color_green, mask = mask_lo_color, opacity=color_lo_green, mode="chroma",greymask=true).Overlay(color_green, mask = mask_mid_color, opacity=color_mid_green, mode="chroma",greymask=true)
\.Overlay(color_green, mask = mask_hi_color, opacity=color_hi_green, mode="chroma",greymask=true).
\Overlay(color_red, mask = mask_lo_color, opacity=color_lo_red, mode="chroma",greymask=true).Overlay(color_red, mask = mask_mid_color, opacity=color_mid_red, mode="chroma",greymask=true)
\.Overlay(color_red, mask = mask_hi_color, opacity=color_hi_red, mode="chroma",greymask=true).
\Overlay(color_blue, mask = mask_lo_color, opacity=color_lo_blue, mode="chroma",greymask=true).Overlay(color_blue, mask = mask_mid_color, opacity=color_mid_blue, mode="chroma",greymask=true)
\.Overlay(color_blue, mask = mask_hi_color, opacity=color_hi_blue, mode="chroma",greymask=true).
\Overlay(color_black, mask = mask_lo_color, opacity=color_lo_black, mode="luma",greymask=true).Overlay(color_black, mask = mask_mid_color, opacity=color_mid_black, mode="luma",greymask=true)
\.Overlay(color_black, mask = mask_hi_color, opacity=color_hi_black, mode="luma",greymask=true).
\Overlay(color_white, mask = mask_lo_color, opacity=color_lo_white, mode="luma",greymask=true).Overlay(color_white, mask = mask_mid_color, opacity=color_mid_white, mode="luma",greymask=true)
\.Overlay(color_white, mask = mask_hi_color, opacity=color_hi_white, mode="luma",greymask=true)

# ------------------------------------------ contrast

contrast_lo = Default(contrast_lo, 0.0) # contrast percentage in shadows toness, between in 0.0, 1.0, default 0.0
contrast_mid = Default(contrast_mid, 0.0) # contrast percentage in midtones, between in 0.0, 1.0, default 0.0
contrast_hi = Default(contrast_hi, 0.0) # contrast percentage in highlights tones, between in 0.0, 1.0, default 0.0
color_contr = color_sup.Overlay(color_sup, mask = mask_lo_color, opacity=contrast_lo, mode="add").Overlay(color_sup, mask = mask_mid_color, opacity=contrast_mid, mode="add")
\.Overlay(color_sup, mask = mask_hi_color, opacity=contrast_hi, mode="add")

#------------------------------------------- Results

(show_mask_color == true) ? control_mask : color_contr
return last
}

__END__
# paths to be customised
Source # Your source
LoadPlugin("C:\...........\mt_masktools-25.dll")
Import("C:\..........\Add colors function.avs ") # If you have saved this function script with this file name
[color addition=1]
[< separator="Add color tuning">]
show = [<"Show tones masks (no = 0 et yes = 1)", 0, 1, 0>] 
show_mask_color  = (show == 1) ? true : false

[< separator="Mask tuning">]
limit_lo=[<"limit_lo", 0, 190, 62>]
limit_hi=[<"limit_hi", 191, 255, 191>]

[< separator="Add colors percentage tuning ">]
[< separator="       red addition">]
color_red_invert = [<"percentage between red color and her invert color", 0.0, 1.0, 0.0>]
color_lo_red = [<"red add percentage in shadows tones", 0.0, 1.0, 0.0>]
color_mid_red = [<"red add percentage in midtones", 0.0, 1.0, 0.0>]
color_hi_red = [<"red add percentage in highlights tones", 0.0, 1.0, 0.0>]
[< separator="       green addition">]
color_green_invert = [<"percentage between green color and her invert color", 0.0, 1.0, 0.0>]
color_lo_green = [<"green add percentage in shadows tones", 0.0, 1.0, 0.0>]
color_mid_green = [<"green add percentage in midtones", 0.0, 1.0, 0.0>]
color_hi_green = [<"green add percentage in highlights tones", 0.0, 1.0, 0.0>]
[< separator="       blue addition">]
color_blue_invert = [<"percentage between blue color and her invert color", 0.0, 1.0, 0.0>]
color_lo_blue = [<"blue add percentage in shadows tones", 0.0, 1.0, 0.0>]
color_mid_blue = [<"blue add percentage in midtones", 0.0, 1.0, 0.0>]
color_hi_blue = [<"blue add percentage in highlights tones", 0.0, 1.0, 0.0>]

[< separator="Luma tuning">]
[< separator="More dark">]
color_lo_black = [<"black add percentage in shadows tones", 0.0, 1.0, 0.0>]
color_mid_black = [<"black add percentage in midtones", 0.0, 1.0, 0.0>]
color_hi_black = [<"black add percentage in highlights tones", 0.0, 1.0, 0.0>]
[< separator="More light">]
color_lo_white = [<"white add percentage in shadows tones", 0.0, 1.0, 0.0>]
color_mid_white = [<"white add percentage in midtones", 0.0, 1.0, 0.0>]
color_hi_white = [<"white add percentage in highlights tones", 0.0, 1.0, 0.0>]

[< separator="Contrast tuning">]
contrast_lo = [<"contrast add percentage in shadows tones", 0.0, 1.0, 0.0>]
contrast_mid = [<"contrast add percentage in midtones", 0.0, 1.0, 0.0>]
contrast_hi = [<"contrast add percentage in highlights tones", 0.0, 1.0, 0.0>]

Assert(isclip, "No defined source") # Line to be deleted if you have gived a variable name for the clip

Other_colors(limit_lo = limit_lo, limit_hi = limit_hi,
\color_red_invert = color_red_invert, color_green_invert = color_green_invert, color_blue_invert = color_blue_invert,
\color_lo_red = color_lo_red, color_mid_red = color_mid_red, color_hi_red = color_hi_red,
\color_lo_green = color_lo_green, color_mid_green = color_mid_green, color_hi_green = color_hi_green,
\color_lo_blue = color_lo_blue, color_mid_blue = color_mid_blue, color_hi_blue = color_hi_blue,
\color_lo_black = color_lo_black, color_mid_black = color_mid_black, color_hi_black = color_hi_black,
\color_lo_white = color_lo_white, color_mid_white = color_mid_white, color_hi_white = color_hi_white,
\contrast_lo = contrast_lo, contrast_mid =contrast_mid, contrast_hi = contrast_hi,
\show_mask_color = show_mask_color)

[/color addition]
The script aim is to overlay red, green, blue or their invert color screens to video and to search good result by tuning the overlay opacity. Whitout AvsPmod UserSliders this script is not fun to use.

Thanks for the curves, i study them.
Bernardd is offline   Reply With Quote
Old 5th April 2014, 01:55   #19  |  Link
raffriff42
Retried Guesser
 
raffriff42's Avatar
 
Join Date: Jun 2012
Posts: 1,377
OK here is a better set of curves, I think.

Here is the new spreadsheet.
The spreadsheet formula is:
Code:
MIN(MAX(0; (1+((WIDTH_2/512)*(256/RAMP_2)))-((ABS(A8-CENTER_2)/256)*(256/RAMP_2))); 1)
It translates to Avisynth with the following code:
Code:
ImageSource("Grayscale_816x72.png", fps=30)
TurnRight
Lanczos4Resize(56, 450)
ConvertToYV12(matrix="PC.709")

a_ctr = 128
a_rmp = 80
a_wid = 60

s1 = ("x * min(max((1+(($w/512)*(256/$r)))-((abs(x-$c)/256)*(256/$r)), 0), 1)")
\     .StrReplace("$c", String(a_ctr))
\     .StrReplace("$r", String(a_rmp))
\     .StrReplace("$w", String(a_wid))
\     .mt_polish

mt_lut(yexpr=s1)
return Last.Histogram

function StrReplace(string base, string findstr, string repstr)
{
    pos = FindStr(base, findstr)
    return (StrLen(findstr)==0) || (pos==0) 
    \   ? base 
    \   : StrReplace( 
    \       LeftStr(base, pos-1) + repstr + 
    \       MidStr(base, pos+StrLen(findstr)), 
    \       findstr, repstr)
}
which gives you (before & after) (image source)

(EDIT looks like there is a gamma effect happening here; fixing it is left as an exercise for the reader)

A final point: I am pretty sure you want the gain of all the curves to add up to unity at all input levels. This was done in my previous script by defining mid range as a difference: mid = input - (low+high).

Last edited by raffriff42; 18th March 2017 at 00:52. Reason: (fixed image links)
raffriff42 is offline   Reply With Quote
Old 5th April 2014, 21:58   #20  |  Link
Bernardd
Registered User
 
Join Date: Jan 2012
Location: Toulon France
Posts: 181
Thanks for this new curves.
Thanks also for example script and for StrReplace function. You are master in knowledges that I have not learnt.
Bernardd is offline   Reply With Quote
Reply

Tags
colour temperature, manual white balance, rgb, white balance, yuv

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 07:29.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2018, vBulletin Solutions Inc.