Log in

View Full Version : Automatic white balance with RGBAdapt plugin


Pages : [1] 2 3

Bernardd
11th March 2017, 12:41
Since 2017, the work is always in progress, thus the last script version is post 61
https://forum.doom9.org/showthread.php?p=1951831#post1951831

StainlessS, Fred,

I open this thread for my automatic white balance script based on the RGBAdapt plugin.

The various plugins necessary for its operation are indicated at the head of the script.
The script can use the AvsPmod user cursors. It is sufficient to uncomment lines 41 to 63.

The script can apply by color channel,
A correction of autogain, the force of this correction is adjustable from 0 to 100%,
A correction of gamma, the force of this correction is adjustable from 0 to 100%,
A bias correction, the force of this correction is adjustable from 0 to 100%,

The correction of gamma is a correction in accordance with the theory of the gray world. Indeed with this theory the bias correction is obtained by solving equation 128 = mean value - correction.
The gamma correction is thus obtained by solving the equation 128 = pow (mean value /255.0,1/correction gamma)

The script can also apply a contrast by channel. The value of this contrast is that of automatic gain after weighting. The application of this contrast is automatic according to a threshold relating to the difference between the greatest max value of the channels and the smallest min value.
This threshold is adjustable. With a value of zero it activates the contrast, with the value of 255 it deactivates the contrast.

Finally, the script adjusts the color temperature. This adjustment can be done automatically or manually.

The script also contains technical parameters, which if necessary need to be adjusted.
These allow you to fix the area of the image to be analyzed in order to extract the data (eliminates the influence of colored borders or a very large colored object in the center of the scene).
A threshold of not taking into account extreme pixels, adjustable from 0 to 100%. This threshold, set by default to 10%, only influences the result of the autogain.

I wanted to make a script giving an automatic white balance without adjustments, but the videos being almost all special cases, it often remains necessary to adjust the process.
To make the settings easier, the script can display a comparison of processes.
The two images at the top correspond to the default treatments without and with contrast.
The middle line shows the original, the result of coloryuv (autowhite), (this is to do better) and the output resulting from the operator settings.
The bottom line shows the result of other combinations, autogain alone, autogain and bias, autogain and gamma.

Finally, novelty of the version broadcast here, a new parameter.
In gray world theory, the average color of an image should be 128, in YUV space, it's good, but not in RGB space, because each channel carries a luma information.
By default, the script calculates the corrections of the gray world with respect to the average of the average values of each channel, calculated after the possible application of the gain. To the experience of some videos, it appeared to me that to allow to adjust from -50 to +50 this average of the average could be interesting.

martin53
12th March 2017, 10:22
Glad you're working on the topic. Maybe you want to read an earlier thread on AWB: Automatic White Balance (AWB) script function(s) (https://forum.doom9.org/showthread.php?p=1632812#post1632812) (from your post, I don't think you are aware of it already, otherwise my apologies)

Bernardd
12th March 2017, 12:08
Hello martin53,
I know your thread. https://forum.doom9.org/showthread.php?p=1672715#post1672715
Happy news, since 2014 i have learned and now your script works fine on my old computer. But i do'nt know what was the problem in past.
My script target is to compensate color aberrations from aged film. Now my improve target is to find a good formula to fix gray value before to apply gamma and bias correction.
Thus i return to study your job.
Thanks.
Bernard

martin53
12th March 2017, 12:44
Back then I had the ideal to automatically detect the white balance bias (the correction step afterwards is not the main challenge, I felt).
Note that StainlessS was so kind to implement the Minkowski P-norm statistics function in his RT_Stats plugin especially for these purposes.

To my so far experiences back then, of the three common theories, White Patch best suited my taste for a wide range of footage (open sea, colorful nature scenery).
But it has a fundamental drawback when used on already recorded footage in contrast to internally in a recording device itself: all camera makes I studied create still fully white bright spots when used indoors with daylight setting.
In other words: everything is tinted in orange, but the bright spots are white, which cheats the White Patch approach.
(Besides of that, just to mention it: a useful AWB controller must have an alternative algorithm for footage where bright spots are completely absent.)
It turned out a dead end to limit the brightest pixels sent to White Patch to e.g. 20 luma increments below full white, because everyday footage can have already colorful objects in this luma range.

Then I followed the idea for a while, that objects (in terms of pixel examination: neighboured pixels with color inside a reasonable range) depict mainly the color of the light source in their comparably brighter areas, while in their comparably darker areas, they mainly depict the color of all surrounding reflections. This did not lead anyone to a formula for the light source color, however, because reflections color itself depends on the light source color...
Maybe the gray world theorem could be used for darker, reflection-dominated regions more than for the brighter regions. So i had to put my growing ever more complex studies aside for the moment.

Recently I was incited to put more thinking into the subject, when I read about homomorphic filtering, which was supposed to separate incident from reflected light, and second I wonder if it could be helpful to calculate the theoretical black body temperature for each pixel, and use the maximum, probably mainly of rather bright (but not fully white! see above) pixels to estimate the light source temperature. This is because I made the observation that blue objects under incandescent light, recorded with daylight white balance, are hopefully not so bright in typical footage that they would cheat this approach.

You are heartily welcome to find 'the' solution :)

Bernardd
12th October 2017, 22:21
Hello,
Here is a new version of the script.

The novelty is the possibility of restricting the extraction of RGB data by not taking into account
the pixels of the tones very dark and very bright. Thing is allowed with the use of a mask with function
RT_RgbChanStats from the powerful RT_Stats plugin.

This novelty combined with the use of contrast makes it possible to correct dominants of strong colors.

Today by default we find:

three display settings
comparison = compare different settings - (false or true)
show_scrutinized = shows the parsed area - (false or true)
show_info = displays extracted and calculated data - (false or true)

a technical adjustment
matrix = choice of the color conversion matrix (Rec 601 = 0 or Rec 709 = 1)

four settings to define the analyzed area
x = ignore pixels to the left - percentage of width - default: 0.00
Y = ignore pixels at the top - percentage of height - default: 0.00
w = ignores pixels to the right - percentage of width - default: 0.00
h = ignores pixels below - percentage of height - default: 0.00

a technical setting of RT_Stats
threshold = percentage of pixelx extreme to ignore - default: 0.10

twelve white balance automation settings
auto_tone_range = Enable tone selection of the pixels to be scanned - (false or true), true
tone_range = manual tone selection, ranges from 0 to 127, default 0
auto_luma_adjust = enable automatic adjustment of output luma - (false or true), default true
luma_adjust = manual adjustment of the luma adjustment - default: 0, varies from -50 to 50
auto_gain = automatic gain gain setting - (false or true), true default
gain_strength = manual gain control - default: 1.0, varies from 0.0 to 1.0
auto_cont = enable automatic contrast force setting - (false or true), true
cont_strength = manual adjustment of contrast strength - default: 1.0, varies from 0.0 to 1.0
auto_rpow = enable automatic rpow force setting - (false or true), default true
rpow_strength = manual rpow force setting - default: 1.0, varies from 0.0 to 1.0
auto_bias = enable automatic bias force setting - (false or true), true false
bias_strength = bias force manual setting - default: 1.0, varies from 0.0 to 1.0

two adjustment of color temperature adjustment
auto_temperature = enable automatic color temperature setting - (false or true) default false
temperature = manually setting the color temperature - default: 0.0, varies from -1.0 to 1.0

The number of these settings can be frightening. But in practice the default settings with all the automation activated
often give an acceptable result (in my opinion). When the result is not satisfactory, the output with the
comparisons makes it possible to identify the optimum adjustment combination.
In fine the setting for the color temperature is perhaps not useful today.
(Google Traduction)

The script in the three following posts

Bernardd
12th October 2017, 22:25
Script part one

######
### RGBAdapt_Awb_Process.avs, RGB32 + YV12 ONLY.
######

/*
AVISource("C:\.............\your video.avi")
LoadPlugin("C:\............\GRunT.dll")
LoadPlugin("C:\............\GScript.dll")
LoadPlugin("C:\............\RGBAdapt.dll")
LoadPlugin("C:\............\RT_Stats26.dll")
*/

# display tunings
comparison = false
show_scrutinized = True
show_info = True

# color space matrix tuning and specify the source rectangle under scrutiny
matrix = "Rec601"
x = 0.1
Y = 0.1
w = 0.1
h = 0.1

#extreme pixels percentage to be ignored when datas extraction
threshold = 0.1

# automatic white balance preset tunings
auto_tone_range = true
tone_range = 0
auto_luma_adjust = true
luma_adjust = 0
auto_gain = true
gain_strength = 1.0
auto_cont = true
cont_strength = 1.0
auto_rpow = true
rpow_strength = 1.0
auto_bias = true
bias_strength = 1.0
auto_temperature = false
temperature = 0.0

# If you use AvsPmod user sliders you can delete comment for following lines

#~ [<separator="display tunings">]
#~ comparison = Select([<"show different settings - (false ou true) default = false = 0", 0, 1, 0>], false , true)
#~ show_scrutinized = Select([<"show scrutinized aera - (false ou true) default = false = 0", 0, 1, 0>], false , true)
#~ show_info = Select([<"show datas - (false ou true) default = false = 0", 0, 1, 0>], false , true)

#~ [<separator="color space matrix tuning">]
#~ matrix = Select([<"color matrix - (Rec 601= 0 ou Rec 709 =1) = default = 0", 0, 1, 0>], "Rec601" , "Rec709")
#~ [<separator=""specify the source rectangle under scrutiny and percentage extreme pixels to ignore">]
#~ x = [<"ignore pixels on left - width percentage - default : 0.00", 0.00, 0.99, 0.09>]
#~ Y= [<"ignore pixels on top - heigth percentage - default : 0.00", 0.00, 0.99, 0.1>]
#~ w = [<"ignore pixels on right - width percentage - default : 0.00", 0.00, 0.99, 0.09>]
#~ h = [<"ignore pixels on bottom - heigth percentage - default : 0.00", 0.00, 0.99, 0.09>]
#~ [<separator=""specify the extreme pixels percentage to be ignored when datas extraction">]
#~ threshold = [<"percentage for extreme pixels to be ignored - default : 0.10", 0.00, 1.00, 0.1>]
#~ [<separator="automatic white balance tunings">]
#~ auto_tone_range = Select([<"automatic scrutinized channel tone area definition - (false ou true) default = true = 0", 0, 1, 1>], false , true)
#~ tone_range = [<"tone pixel range to analyze", 0, 127, 0>]
#~ auto_luma_adjust = Select([<"automatic output luma adjust - (false ou true) default = true = 0", 0, 1, 1>], false , true)
#~ luma_adjust = [<"output luma adjust - default : 0", -50, 50, 0>]
#~ auto_gain = Select([<"automatic gain strength - (false ou true) default = true = 0", 0, 1, 1>], false , true)
#~ gain_strength = [<"gain strength - default : 1.0", 0.0, 1.0, 0.0>]
#~ auto_cont = Select([<"automatic contrast strength - (false ou true) default = true = 0", 0, 1, 1>], false , true)
#~ cont_strength = [<"cont strength - default : 1.0", 0.0, 1.0, 0.0>]
#~ auto_rpow = Select([<"automatic rpow strength - (false ou true) default = true = 0", 0, 1, 1>], false , true)
#~ rpow_strength = [<"rpow strength - default : 1.0", 0.0, 1.0, 0.0>]
#~ auto_bias = Select([<"automatic bias strength - (false ou true) default = true = 0", 0, 1, 1>], false , true)
#~ bias_strength = [<"final bias strength - default : 1.0", 0.0, 1.0, 0.0>]
#~ [<separator="color temperature tunings">]
#~ auto_temperature = Select([<"automatic color temperature - (false ou true) default = true = 1", 0, 1, 0>], false , true)
#~ temperature = [<"manual color temperature - default : 0.0", -1.0, 1.0, 0.0>]


#######
#######
#######

/*
# Without Stacked View capability
a = RGBAdapt_AWB_Process(matrix=matrix,show_scrutinized=show_scrutinized,show_info=show_info,
\ x=x,y=y,w=w,h=h,
\ threshold=threshold,threshold_auto=threshold_auto,
\ gain_strength=gain_strength, luma_adjust = luma_adjust,r pow_strength=rpow_strength, bias_strength=bias_strength,
\ auto_temperature = auto_temperature, temperature = temperature)
*/

# With Stacked View capability

AWB_Func(matrix=matrix,show_scrutinized=show_scrutinized,show_info=show_info,
\ x=x,y=y,w=w,h=h,
\ threshold=threshold, auto_tone_range = auto_tone_range, tone_range= tone_range, auto_luma_adjust= auto_luma_adjust, luma_adjust = luma_adjust,
\ auto_gain = auto_gain, auto_cont = auto_cont, auto_rpow = auto_rpow, auto_bias = auto_bias,
\ gain_strength=gain_strength, cont_strength=cont_strength, rpow_strength=rpow_strength, bias_strength=bias_strength,
\ auto_temperature = auto_temperature, temperature = temperature,
\ Comparison=Comparison)

Return Last

/*
#----------------------------------------------based on RGBADapt plugin --------------------------------------------#
# script author : StainlessS http://forum.doom9.org/showthread.php?t=170642 #
#-------------------------------------------------------------------------------------------------------------------#

#---------------------------------------------- need RT_Stats plugin -----------------------------------------------#
# script author : StainlessS http://forum.doom9.org/showthread.php?t=165479 #
#-------------------------------------------------------------------------------------------------------------------#

#---------------------------------------------- need GRunT plugin --------------------------------------------------#
# plugin author : Gavino http://forum.doom9.org/showthread.php?t=139337 #
#-------------------------------------------------------------------------------------------------------------------#

#---------------------------------------------- need GScript plugin ------------------------------------------------#
# plugin author : Gavino http://forum.doom9.org/showthread.php?t=147846 #
#-------------------------------------------------------------------------------------------------------------------#
*/

Function RGBAdapt_AWB_Process(clip clip,string "matrix",bool "show_scrutinized",bool "show_info",float "x",float "y",float "w",float "h",
\ float "threshold", bool "auto_tone_range", int "tone_range", bool "auto_luma_adjust", int "luma_adjust",
\ bool "auto_gain", bool "auto_cont", bool "auto_rpow", bool "auto_bias",
\ float "gain_strength", float "cont_strength", float "rpow_strength", float "bias_strength",
\ bool "auto_temperature", float "temperature") {

# Clip MUST be YV12 or RGB32. Always returns SAME colorspace as input.
clip
myName="RGBAdapt_Awb_Process: "
Assert(RT_FunctionExist("RGBAdapt"),myName+"RGBAdapt plugin must be loaded, http://forum.doom9.org/showthread.php?t=170642")
Assert(RT_FunctionExist("GScriptClip"),myName+"GRunT plugin must be loaded, http://forum.doom9.org/showthread.php?t=139337")
Assert(RT_FunctionExist("GScript"),myName+"GScript plugin must be loaded, http://forum.doom9.org/showthread.php?t=147846")
Assert(IsYV12(clip) || IsRGB32(clip),RT_String("%sInput video colorspace must be YV12 or RGB32",myName))
matrix = Default(matrix, "Rec601") # Color standard, Rec 601 or Rec 709
Assert(matrix == "Rec601" || matrix == "Rec709",RT_String("%smatrix 'Rec601' or 'Rec709'('%s')",myName,matrix))
show_scrutinized = Default(show_scrutinized, false) # show scrutinized area or not, default false
show_info = Default(show_info, false) # show info or not, default false
x = float(Default(x,0.0)) # width percentage to specify coords source rectangle under scrutiny, the default : x=y=h=w=0.0 full frame
Assert(0.0 <= x <= 0.99,RT_String("%s0.0 <= x <= 0.99(%f)",myName,x))
y = float(Default(y,0.0)) # height percentage to specify coords source rectangle under scrutiny, the default : x=y=h=w=0.0 full frame
Assert(0.0 <= y <= 0.99,RT_String("%s0.0 <= y <= 0.99(%f)",myName,y))
w = float(Default(w,0.0)) # coords specify source rectangle under scrutiny, the default : x=y=h=w=0.0 is full frame
Assert(0.0 <= w <= 0.99,RT_String("%s0.0 <= w <= 0.99(%f)",myName,w))
Assert(0.0 <= (x+w) <= 0.99 ,RT_String("%s0.0 <= (x+w) <= 0.99(%f)",myName,x+w))
h = float(Default(h,0.0)) # coords specify source rectangle under scrutiny , the default : x=y=h=w=0.0 is full frame
Assert(0.0 <= h <= 0.99,RT_String("%s0.0 <= h <= 0.99(%f)",myName,h))
Assert(0.0 <= (y+h) <= 0.99 ,RT_String("%s0.0 <= (y+h) <= 0.99(%f)",myName,y+h))
threshold = Float(Default(threshold, 0.10)) # threshold arg of RT_Stats plugin
Assert(0.0 <= threshold <= 1.0,RT_String("%s0.0 <= threshold <= 1.0(%f)",myName,threshold))
auto_tone_range = Default(auto_tone_range, true) # enable automatic scrutinized channel tone area definition, default true
tone_range = Int(Default(tone_range, 0)) #luma range to select tone pixel to analyze
Assert(0 <= tone_range <= 127,RT_String("%s0 <= tone_range <= 127(%f)",myName,tone_range))
auto_luma_adjust = Default(auto_luma_adjust, true) # enable automatic output luma adjust, default true
luma_adjust = Int(Default(luma_adjust, 0)) # automatic output luma adjust
Assert(-50 <= luma_adjust <= 50,RT_String("%s-50 <= luma_adjust <= 50(%f)",myName,luma_adjust))
auto_gain = Default(auto_gain, true) # enable automatic cont strength, default true
gain_strength = Float(Default(gain_strength, 1.0)) # gain strength
Assert(0.0 <= gain_strength <= 1.0,RT_String("%s0.0 <= gain_strength <= 1.0(%f)",myName,gain_strength))
auto_cont = Default(auto_cont, true) # enable automatic cont strength, default true
cont_strength = Float(Default(cont_strength, 1.0)) # cont strength
Assert(0.0 <= cont_strength <= 1.0,RT_String("%s0.0 <= cont_strength <= 1.0(%f)",myName,cont_strength))
auto_rpow = Default(auto_rpow, true) # enable automatic cont strength, default true
rpow_strength = Float(Default(rpow_strength, 1.0)) #rpow strength
Assert(0.0 <= rpow_strength <= 1.0,RT_String("%s0.0 <= rpow_strength <= 1.0(%f)",myName,rpow_strength))
auto_bias = Default(auto_bias, true) # enable automatic cont strength, default true
bias_strength = Float(Default(bias_strength, 1.0)) #bias strength
Assert(0.0 <= bias_strength <= 1.0,RT_String("%s0.0 <= bias_strength <= 1.0(%f)",myName,bias_strength))
auto_temperature = Default(auto_temperature, true) # enable automatic color temperature factor, default true
temperature = Float(Default(temperature, 0.0)) # manual color temperature factor
Assert(- 1.0 <= temperature <= 1.0,RT_String("%s-1.0 <= temperature <= 1.0(%f)",myName,temperature))

#---------- Specify the source rectangle under scrutiny, x,y,w,h are now type Int

x = int( Width * x)
y = int( Height * y)
w = int(-Width * w)
h = int(-Height * h)

#--------- RGB color space process

RGB32_clip = (!isRGB32(clip)) ? ConvertToRGB32(clip, matrix=matrix) : clip

CWID=72 CHIT=24 #69 21 # display Width and Height in Subtitle characters
MinWid=CWID*10 MinHit=CHIT*20 # RT_Subtitle required width height in pixels (fixed font size is 10x20)
TooSmall=(Width<MinWid || Height<MinHit)

RedStr = (TooSmall) ? "Red values :\n" : "\a2Red values\a- :\n"
GrnStr = (TooSmall) ? "Green values :\n" : "\a4Green values\a- :\n"
BluStr = (TooSmall) ? "Blue values :\n" : "\a1Blue values\a- :\n"

# Use same string at each frame.
Fmt=
\ "\nORI Channels averages average : %7.3f Auto strength :%7.3f" +
\ "\nChannels averages average : %7.3f\n" +
\ "Min max ave diff (for auto contrast tune) : %7.3f\n" +
\ RedStr +
\ "Departure : Average=%7.3f : Min/max=%-3d : Min=%-3d : Max=%-3d\n" +
\ "Finish : Average=%7.3f : Min/max=%-3d : Min=%-3d : Max=%-3d\n" +
\ " R_bias=%7.3f : R_gain =%7.3f : R_cont =%.3f : R_rpow=%.3f\n\n" +
\ GrnStr +
\ "Departure : Average=%7.3f : Min/max=%-3d : Min=%-3d : Max=%-3d\n" +
\ "Finish : Average=%7.3f : Min/max=%-3d : Min=%-3d : Max=%-3d\n" +
\ " G_bias=%7.3f : G_gain =%7.3f : G_cont =%.3f : G_rpow=%.3f\n\n" +
\ BluStr +
\ "Departure : Average=%7.3f : Min/max=%-3d : Min=%-3d : Max=%-3d\n" +
\ "Finish : Average=%7.3f : Min/max=%-3d : Min=%-3d : Max=%-3d\n" +
\ " B_bias=%7.3f : B_gain =%7.3f : B_cont =%.3f : B_rpow=%.3f\n\n" +
\ "Channels averages average : %7.3f \n\nColor temperature mod = %.1f percent of %s (max 6.0 percent)"

Bernardd
12th October 2017, 22:28
Script part two


GSCript("""
# Nested Low level Function, Called per frame via GScriptClip(), RGB32 ONLY
Function RGBAdapt_awb_process_Lo(clip clp,String Fmt,bool show_info,int x,int y,int w,int h,float threshold,
\ bool auto_tone_range, int tone_range, bool auto_luma_adjust, int luma_adjust,
\ bool auto_gain, bool auto_cont, bool auto_rpow, bool auto_bias,
\ float gain_strength,float cont_strength, float rpow_strength, float bias_strength,
\ Bool TooSmall,Int CWid,Int CHit,bool auto_temperature, float temperature) {

clp # Last = Input RGB32 clp clip.

# n = current_frame # n is current_frame, can use in RT_Stats to access frames relative to current. Not currently Used.

#---------- Channels datas extraction and adjustement factors calculation

Last.RT_RgbChanStats(x=x,y=y,w=w,h=h,threshold=threshold,chan=-1,flgs= 1+2+4+16, Prefix="RCS_")

blank_clip = RCS_MinMaxDiff_0 + RCS_MinMaxDiff_1 + RCS_MinMaxDiff_2 # one color clip detection to disable auto white balance

ORI_Ave_0 = RCS_Ave_0 ORI_Ave_1 = RCS_Ave_1 ORI_Ave_2 = RCS_Ave_2

auto_strength = Min((ORI_Ave_0 + ORI_Ave_1 + ORI_Ave_2)/(3.0*128.0),1.0) # automatic strength for all process

if (auto_tone_range) {ref_ori = (ORI_AVE_0+ORI_AVE_1+ORI_AVE_2)/3.0
tone_range = max(round((128.0 - ref_ori)/3.0),0)} # automatic pixel luma range to analyze

Last.RT_RgbChanStats(x=x,y=y,w=w,h=h,threshold=threshold,chan=0,flgs= 1+2+4+16,mask=last.ShowRed("YV12"),MaskMin=tone_range,MaskMax=255 - tone_range)
Last.RT_RgbChanStats(x=x,y=y,w=w,h=h,threshold=threshold,chan=1,flgs= 1+2+4+16,mask=last.ShowGreen("YV12"),MaskMin=tone_range,MaskMax=255 - tone_range)
Last.RT_RgbChanStats(x=x,y=y,w=w,h=h,threshold=threshold,chan=2,flgs= 1+2+4+16,mask=last.ShowBlue("YV12"),MaskMin=tone_range,MaskMax=255 - tone_range)

if (auto_luma_adjust) {luma_adjust = tone_range} # automatic output luma adjust to avoid darkness given by contrast

# Leave RCS_ values as original (avoid repeat function call in Show_info), new variables without RCS_ prefix, avoid div by zero.
MinMaxDiff_0 = Max(RCS_MinMaxDiff_0, 0.00001)
MinMaxDiff_1 = Max(RCS_MinMaxDiff_1, 0.00001)
MinMaxDiff_2 = Max(RCS_MinMaxDiff_2, 0.00001)

#---------- Gain process

if (auto_gain) {gain_strength = auto_strength}

r_gain = 1.0 + (255.0/MinMaxDiff_0 - 1.0) * gain_strength
r_gain_bias = -RCS_Min_0 * r_gain *gain_strength
g_gain = 1.0 + (255.0/MinMaxDiff_1 - 1.0) * gain_strength
g_gain_bias = -RCS_Min_1 * g_gain * gain_strength
b_gain = 1.0 + (255.0/MinMaxDiff_2 - 1.0) * gain_strength
b_gain_bias = -RCS_Min_2 * b_gain * gain_strength

#------ Contrast process

# Cont is dangerous, because it can overshoot light and dark, but it is necessary to help to find good correction for very big
# color cast.

#~ if (auto_cont) {cont_strength = auto_strength}
if (auto_cont) {cont_strength = (ORI_Ave_0 + ORI_Ave_1 + ORI_Ave_2)/(3.0*128.0)
if (cont_strength > 1.0) {cont_strength = cont_strength - 1.0} else {cont_strength = cont_strength}}

r_cont = 1.0 + (r_gain - 1.0) * cont_strength
r_cont_max = RCS_Max_0 * r_gain + r_gain_bias + (r_cont - 1) * (RCS_Max_0 - 128)
r_cont_bias = (255 - r_cont_max) * gain_strength

g_cont = 1.0 + (g_gain - 1.0) * cont_strength
g_cont_max = RCS_Max_1 * g_gain + g_gain_bias + (g_cont - 1) * (RCS_Max_1 - 128)
g_cont_bias = (255 - g_cont_max) * gain_strength

b_cont = 1.0 + (b_gain - 1.0) * cont_strength
b_cont_max = RCS_Max_2 * b_gain + b_gain_bias + (b_cont - 1) * (RCS_Max_2 - 128)
b_cont_bias = (255 - b_cont_max) * gain_strength

r_bias = r_gain_bias +r_cont_bias g_bias = g_gain_bias +g_cont_bias b_bias = b_gain_bias + b_cont_bias

#----gamma args calculation in accordance with gray world theory

# In gray world theory, in YUV range, we increase or decrease average value to ref = 128.0, but in RGB range
# ref = average of channel average values is better.
# With contrast use, average of channel average value after gain process without cont process give a better picture light.

# In gamma process, to incresae or decrease average value, we use gamma args. To find this gamma args, we
# solve this equation ref = pow(average value/255.0,1/gamma args)

ref = (RCS_Ave_0 * r_gain + r_gain_bias + RCS_Ave_1 * g_gain + g_gain_bias + RCS_Ave_2 * b_gain + b_gain_bias)/3.0 + luma_adjust

# Warm temperature = gray mixed with 6% yellow. Cool temperature = gray mixed with 6% blue. (https://en.wikipedia.org/wiki/Color_temperature)
# thus with temperature factor, you can adjust color temperature in manual or automatic mode.

if (auto_temperature) {
temperature = (ref - Min(RCS_Ave_0, RCS_Ave_2))/ref} # else temperature = manual temperature args
#~ add_color = (temperature >= 0) ? "yellow" : "blue" # this variable is only for display

if (auto_rpow) {rpow_strength = auto_strength}

r_rpow = 1 + (log((RCS_Ave_0 * r_gain + r_gain_bias)/255.0)/log(ref * (1 + 0.06 * temperature)/255.0) - 1) * rpow_strength
r_rpow = Min (4.0, Max (r_rpow, 0.1))
g_rpow = 1 + (log((RCS_Ave_1 * g_gain + g_gain_bias)/255.0)/log(ref/255.0) - 1) * rpow_strength
g_rpow = Min (4.0, Max (g_rpow, 0.1))
b_rpow = 1 + (log((RCS_Ave_2 * b_gain + b_gain_bias)/255.0)/log(ref * (1 - 0.06 * temperature)/255.0) - 1) * rpow_strength
b_rpow = Min (4.0, Max (b_rpow, 0.1))

#--------- bias gain cont in RGBadapt args range

r_bias = Min (512.0, Max (r_bias, -512.0)) g_bias = Min (512.0, Max (g_bias, -512.0)) b_bias = Min (512.0, Max (b_bias, -512.0))
r_gain = Min (8.0, Max (r_gain, -8.0)) g_gain = Min (8.0, Max (g_gain, -8.0)) b_gain = Min (8.0, Max (b_gain, -8.0))
r_cont = Min (8.0, Max (r_cont, -8.0)) g_cont = Min (8.0, Max (g_cont, -8.0)) b_cont = Min (8.0, Max (b_cont, -8.0))

#---------- bias corrections in accordance with gray world theory
#----------- bias corrections extraction and calcul
# ssS, Create and measure temp clip

TempC=clp.RGBAdapt(R_bias = r_bias, R_Gain = r_gain, R_Cont = r_cont, R_rpow = r_rpow,
\ G_bias = g_bias, G_Gain = g_gain, G_Cont = g_cont, G_rpow = g_rpow,
\ B_bias = b_bias, B_Gain = b_gain, B_Cont = b_cont, B_rpow = b_rpow)

TempC.RT_RgbChanStats(x=x,y=y,w=w,h=h,threshold=threshold,chan=-1,flgs=16,Prefix="TMP_") ### Use TMP_ prefix HERE

# Ref for bias corrections always calculated with gain output, because is more light than calculated with new extracted channels average values

if (auto_bias) {bias_strength = auto_strength}

dr = (ref * (1 + 0.06 * temperature) - TMP_Ave_0) * bias_strength dg = (ref - TMP_Ave_1) * bias_strength
db = (ref * (1 - 0.06 * temperature) - TMP_Ave_2) * bias_strength

r_bias = (r_gain_bias + r_cont_bias + dr) g_bias = (g_gain_bias + g_cont_bias + dg) b_bias = (b_gain_bias + b_cont_bias + db)
r_bias = Min (512.0, Max (r_bias, -512.0)) g_bias = Min (512.0, Max (g_bias, -512.0)) b_bias = Min (512.0, Max (b_bias, -512.0))

#------------ AWB output with gain cont rpow and bias process
# now change for real

(blank_clip==0)
\ ? clp
\ : clp.RGBAdapt(R_bias=r_bias,R_Gain=r_gain,R_Cont=r_cont,R_rpow=r_rpow,
\ G_bias=g_bias,G_Gain=g_gain,G_Cont=g_cont,G_rpow=g_rpow,
\ B_bias=b_bias,B_Gain=b_gain,B_Cont=b_cont,B_rpow=b_rpow)

if(show_info) {
#--------- final RGB values extraction for display
# Use different 'FIN_' Prefix so as not to destroy original variables

add_color = (temperature >= 0) ? "yellow" : "blue" # this variable is only for display

Last.RT_RgbChanStats(x = x, y = y, w = w, h = h, threshold = threshold, chan = -1, flgs = 1+2+4+8+16,Prefix="FIN_")

S=RT_String(Fmt,
\ (ORI_Ave_0+ORI_Ave_1+ORI_Ave_2)/3.0,auto_strength,
\ (RCS_Ave_0+RCS_Ave_1+RCS_Ave_2)/3.0, Max(RCS_Ave_0,RCS_Ave_1,RCS_Ave_2) - Min(RCS_Ave_0,RCS_Ave_1,RCS_Ave_2),
\
\ RCS_Ave_0, RCS_MinMaxDiff_0, RCS_Min_0, RCS_Max_0,
\ FIN_Ave_0, FIN_MinMaxDiff_0, FIN_Min_0, FIN_Max_0,
\ r_bias, r_gain,r_cont,r_rpow,
\
\ RCS_Ave_1, RCS_MinMaxDiff_1, RCS_Min_1, RCS_Max_1,
\ FIN_Ave_1, FIN_MinMaxDiff_1, FIN_Min_1, FIN_Max_1,
\ g_bias, g_gain,g_cont,g_rpow,
\
\ RCS_Ave_2, RCS_MinMaxDiff_2, RCS_Min_2, RCS_Max_2,
\ FIN_Ave_2, FIN_MinMaxDiff_2, FIN_Min_2, FIN_Max_2,
\ b_bias,b_gain,b_cont,b_rpow,
\
\ (FIN_Ave_0 + FIN_Ave_1 + FIN_Ave_2 )/3, temperature*0.06*100,add_color, Esc=(TooSmall)?0:1)

(TooSmall)
\ ? Last.Subtitle(S,Font="Courier New",lsp=0,text_color=$FFFF00,halo_color=$0,size=height/float(CHIT),
\ Font_width=width/FloaT(CWID))
\ : Last.RT_Subtitle("%s",S)
} # End ShowInfo
Return Last
} # End, RGBAdapt_awb_process_Lo()

# GScriptClip, Calling Low level Function RGBAdapt_awb_process_Lo() at each frame.
# Named ARGS variables at current script level, are imported into GScriptClip script, and passed as args to RGBAdapt_awb_process_Lo().
ARGS="Fmt,show_info,x,y,w,h,threshold, auto_tone_range, tone_range, auto_luma_adjust, luma_adjust," +
" auto_gain, auto_cont, auto_rpow, auto_bias, gain_strength, cont_strength, rpow_strength, bias_strength, TooSmall,CWid,CHit," +
"auto_temperature, temperature"
RGB32_clip.GScriptClip("RGBAdapt_awb_process_Lo(last,"+ARGS+")", local=true, args=ARGS)

# Do border outside of Scriptclip.
if(show_scrutinized) {
Level = 100 # 0 (Off) -> 257 (Full)
MarkColor = $00FF00
#-------- display scrutinized area
scrutinized_green = Last.BlankClip(width = Width-x+w, height = height-y+h, color=MarkColor)
scrutinized_mask = scrutinized_green.Blankclip(color=$0).LetterBox(2,2,2,2,$FFFFFF)
Layer(last,scrutinized_green.Mask(scrutinized_mask),x=x,y=y,level=Level)
} # End show_scrutinized
""")
Return (clip.isYV12) ? ConvertToYV12(last, matrix=matrix) : last # Return original colorspace, YV12 or RGB32
}

Bernardd
12th October 2017, 22:29
Script part three


Function AWB_Func(clip clip, string "matrix",bool "show_scrutinized", bool "show_info", float "x", float "y", float "w", float "h",
\ float "threshold", bool "auto_tone_range", int "tone_range", bool "auto_luma_adjust", int "luma_adjust",
\ bool "auto_gain", bool "auto_cont", bool "auto_rpow", bool "auto_bias",
\ float "gain_strength",float "cont_strength", float "rpow_strength", float "bias_strength",
\ bool "auto_temperature", float "temperature", bool "Comparison") {

# Clip MUST be YV12 or RGB32. Always returns SAME colorspace as input.
Gscript("""
clip
output=clip.RGBAdapt_Awb_Process(matrix=matrix,show_scrutinized=show_scrutinized,show_info=show_info,x=x,y=y,w=w,h=h,threshold=threshold,
\ auto_tone_range = auto_tone_range, tone_range = tone_range, auto_luma_adjust = auto_luma_adjust, luma_adjust=luma_adjust,
\ auto_gain = auto_gain, auto_cont = auto_cont, auto_rpow = auto_rpow, auto_bias = auto_bias,
\ gain_strength=gain_strength, cont_strength=cont_strength, rpow_strength=rpow_strength, bias_strength=bias_strength,
\ auto_temperature = auto_temperature, temperature = temperature)
if (!Default(Comparison,false)) {
output
} else {
# Here, Clip is either RGB32 or YV12.
# Ensure RGB32 for all calls to RGBAdapt_Awb_Process (Only convert input at most once)
RGB_Clip = (Clip.IsYV12) ? clip.ConvertToRGB32(matrix=matrix) : clip
full = RGB_Clip.RGBAdapt_awb_process(matrix=matrix, show_scrutinized=show_scrutinized, show_info=show_info,
\ x=x, y=y, w=w, h=h,auto_gain = false, auto_tone_range = false, tone_range = 0,auto_temperature = false, temperature = 0.0)
without_contrast = RGB_Clip.RGBAdapt_awb_process(matrix=matrix, show_scrutinized=show_scrutinized, show_info=show_info,
\ x=x, y=y, w=w, h=h,auto_cont = false, cont_strength =0.0,auto_temperature = false, temperature = 0.0)
without_rpow = RGB_Clip.RGBAdapt_awb_process(matrix=matrix,show_scrutinized=show_scrutinized, show_info=show_info,
\ x=x,y=y,w=w,h=h,auto_rpow = false, rpow_strength =0.0,auto_temperature = false,temperature = 0.0)
without_bias = RGB_Clip.RGBAdapt_awb_process(matrix=matrix,show_scrutinized=show_scrutinized,show_info=show_info,
\ x=x,y=y,w=w,h=h, auto_bias= false, bias_strength =0.0,auto_temperature = false,temperature = 0.0)
without_gain = RGB_Clip.RGBAdapt_awb_process(matrix=matrix,show_scrutinized=show_scrutinized,show_info=show_info,
\ x=x,y=y,w=w,h=h, auto_gain = false, gain_strength =0.0, temperature = temperature)
only_gain = RGB_Clip.RGBAdapt_awb_process(matrix=matrix,show_scrutinized=show_scrutinized,show_info=show_info,
\ x=x,y=y,w=w,h=h, threshold=0.1,auto_cont = false,cont_strength =0.0,auto_rpow = false, rpow_strength=0.0,
\auto_bias = false, bias_strength=0.0,temperature = temperature)

YV12_Clip = (clip.IsRGB32) ? clip.ConvertToYV12(matrix=matrix) : clip
colorYUV_AWB = YV12_Clip.ColorYUV(autowhite = true)

# Convert clips to original Input ColorSpace.
if(clip.IsRGB32) {
colorYUV_AWB = colorYUV_AWB.ConvertToRGB32(matrix=matrix)
} else {
full = full.ConvertToYV12(matrix=matrix)
without_contrast = without_contrast.ConvertToYV12(matrix=matrix)
without_rpow = without_rpow.ConvertToYV12(matrix=matrix)
without_bias = without_bias.ConvertToYV12(matrix=matrix)
without_gain = without_gain.ConvertToYV12(matrix=matrix)
only_gain = only_gain.ConvertToYV12(matrix=matrix)
}

#~ contrast_label=(cont_strength==0.0) ? "without contrast"
#~ \ : (cont_strength>0.0) ? "with contrast"
#~ \ : "contrast in accordance with threshold"

STK1 = StackHorizontal(
\ without_rpow.AddBorders(0,20,0,0,color=$0).Subtitle("gain contrast and bias process without rpow"),
\ without_bias.AddBorders(0,20,0,0,color=$0).Subtitle("gain contrast and rpow process without bias"),
\ full.AddBorders(0,20,0,0,color=$0).Subtitle("default without color analyzerestriction")
\ )
STK2 = StackHorizontal(
\ clip.AddBorders(0,20,0,0,color=$0).Subtitle("original"),
\ colorYUV_AWB.AddBorders(0,20,0,0,color=$0).Subtitle("As a reminder, classical ColorYUV awb"),
\ output.AddBorders(0,20,0,0,color=$0).Subtitle ("Selected output")
\ )
STK3 = StackHorizontal(
\ only_gain.AddBorders(0,20,0,0,color=$0).Subtitle("only gain "),
\ without_gain.AddBorders(0,20,0,0,color=$0).Subtitle("only rpow and bias without contrast"),
\ without_contrast.AddBorders(0,20,0,0,color=$0).Subtitle("gain rpow and bias process without contrast")
\ )
StackVertical(STK1,STK2,STK3)
} # End, if
""") # End GScript
Return Last # Return Original ColorSpace
}

Sachin
20th November 2017, 03:12
Bernard,
Thank you for this wonderful script, the script posted in first post works simply superb. I wanted to try the new version in the above three posts, it gives me following error

Script error: syntax error
([GScript], line 169, column 0)
(C:\Desktop\RGBAdapt_Awb_Process.avs, line 392)
([GScript], line 7)
(C:\Desktop\RGBAdapt_Awb_Process.avs, line 467)
(C:\Desktop\RGBAdapt_Awb_Process.avs, line 99)

I believe that this is a copy/paste error. It will be very helpful if you can post the whole new version script in a single part avs file so that I can download.

Thank you

StainlessS
20th November 2017, 05:02
Same here, but slight difference in line numbers (due to blank lines probably)


([GScript], line 169, column 0)
(C:\Desktop\RGBAdapt_Awb_Process.avs, line 395)
([GScript], line 7)
(C:\Desktop\RGBAdapt_Awb_Process.avs, line 469)
(C:\Desktop\RGBAdapt_Awb_Process.avs, line 102)


I'm not gonna attempt to find fix, cannot stand unformatted script, and Bernard keeps removing all formatting despite [EDIT: near] zero speed increase benefit.

Bernardd
20th November 2017, 17:42
Hello,
Sachin, StainlessS, i apology.

The error lines are these
ARGS="Fmt,show_info,x,y,w,h,threshold, auto_tone_range, tone_range, auto_luma_adjust, luma_adjust," +
" auto_gain, auto_cont, auto_rpow, auto_bias, gain_strength, cont_strength, rpow_strength, bias_strength, TooSmall,CWid,CHit," +
"auto_temperature, temperature"
They should be this :
ARGS="Fmt,show_info,x,y,w,h,threshold, auto_tone_range, tone_range, auto_luma_adjust, luma_adjust," +
\ " auto_gain, auto_cont, auto_rpow, auto_bias, gain_strength, cont_strength, rpow_strength, bias_strength," +
\ " TooSmall,CWid,CHit,auto_temperature, temperature"

But i suggest to do'nt spend much time to try the last script version, because i propose a new version.

New script more short, more useable.

More short, definitively only four ways for color cast correction.
action with gain,
action with contrast (new formula without color channel ponderation factors),
action with rpow,
action with bias.
This four actions can work together or independantly. Each action have thus a tunable power strength .

If you want, each action power strength can be equal and give a readable white balance. Thus it is more useable,
you have only one common strength to tune. More useable the script have a automatic mode to compute this
common strength. His white balance result is often readable. More useable it is fast to disable the common strength
for one, two or three actions to fine the white balance. At this time, you can also tune the power strength of the
actions of your choice to refine the white balance.

The script have a comparison display mode to help to find the better combination of the four actions.
This mode show nine output of the video.
Top, without contrast action, in automatic common strength mode, you have from rigth to left gain action only,
gain and bias actions, and gain, rpow and bias actions.
Middle, from rigth to left, original input, AutoWhite ColorYUV process, and the tuned script output.
Bottom, from rigth to left, with automatic common strength desable, but with common strength eaqual to 1.0
gain and contrast actions, gain, contrast, and bias actions and gain, contrast, rpow and bias actions.

Comment
The automatic common strength factor is an aproximation. Color cast is problem with color channel average and or
min and max values. Thus common_strength = (channel average average + channel min average + channel
max average))/(128+255). This formula gives often good results with low color cast, but for heavy color cast
the strength of the four actions is to few. In this case you must disable automatic common strength and tune it in
manual mode. You can also experiment the own manual tune of each actions.

and in following posts.

Bernard

Bernardd
20th November 2017, 17:51
script first part

######
### RGBAdapt_Awb_Process.avs, RGB32 + YV12 ONLY.
######

/*
AVISource("C:\.............\your video.avi")
LoadPlugin("C:\............\GRunT.dll")
LoadPlugin("C:\............\GScript.dll")
LoadPlugin("C:\............\RGBAdapt.dll")
LoadPlugin("C:\............\RT_Stats26.dll")
*/

# display tunings
comparison = false
show_scrutinized = true
show_info = true

# color space matrix tuning and specify the source rectangle under scrutiny
matrix = "Rec601"
x = 0.1
Y = 0.1
w = 0.1
h = 0.1

#extreme pixels percentage to be ignored when datas extraction
threshold = 0.1

# automatic white balance preset tunings
auto_strength = true
common_strength = 1.0
common_gain = true
gain_strength = 0.0
common_cont = true
cont_strength = 0.0
common_rpow = true
rpow_strength = 0.0
common_bias = true
bias_strength = 0.0

# If you use AvsPmod user sliders you can delete comment for following lines

#~ [<separator="display tunings">]
#~ comparison = Select([<"show different settings - (false ou true) default = false = 0", 0, 1, 0>], false , true)
#~ show_scrutinized = Select([<"show scrutinized aera - (false ou true) default = false = 0", 0, 1, 0>], false , true)
#~ show_info = Select([<"show datas - (false ou true) default = false = 0", 0, 1, 0>], false , true)

#~ [<separator="color space matrix tuning">]
#~ matrix = Select([<"color matrix - (Rec 601= 0 ou Rec 709 =1) = default = 0", 0, 1, 0>], "Rec601" , "Rec709")
#~ [<separator=""specify the source rectangle under scrutiny and percentage extreme pixels to ignore">]
#~ x = [<"ignore pixels on left - width percentage - default : 0.00", 0.00, 0.99, 0.1>]
#~ Y= [<"ignore pixels on top - heigth percentage - default : 0.00", 0.00, 0.99, 0.1>]
#~ w = [<"ignore pixels on right - width percentage - default : 0.00", 0.00, 0.99, 0.11>]
#~ h = [<"ignore pixels on bottom - heigth percentage - default : 0.00", 0.00, 0.99, 0.1>]
#~ [<separator=""specify the extreme pixels percentage to be ignored when datas extraction">]
#~ threshold = [<"percentage for extreme pixels to be ignored - default : 0.10", 0.00, 1.00, 0.1>]
#~ [<separator="automatic white balance tunings - global process tune">]
#~ auto_strength = Select([<"automatic strength process - (false ou true) default = true = 0", 0, 1, 1>], false , true)
#~ common_strength = [<"---- manual common strength - default : 1.00", 0.00, 2.00, 1.0>]
#~ [<separator="automatic white balance tunings - individual process tune">]
#~ common_gain = Select([<"common gain strength - (false ou true) default = true = 0", 0, 1, 1>], false , true)
#~ gain_strength = [<"---- manual gain strength - default : 0.0", 0.0, 2.0, 0.0>]
#~ common_cont = Select([<"common contrast strength - (false ou true) default = true = 0", 0, 1, 1>], false , true)
#~ cont_strength = [<"---- manual cont strength - default : 0.0", 0.0, 2.0, 0.0>]
#~ common_rpow = Select([<"common rpow strength - (false ou true) default = true = 0", 0, 1, 1>], false , true)
#~ rpow_strength = [<"---- manual rpow strength - default : 0.0", 0.0, 2.0, 0.0>]
#~ common_bias = Select([<"common bias strength - (false ou true) default = true = 0", 0, 1, 1>], false , true)
#~ bias_strength = [<"---- manual bias strength - default : 0.0", 0.0, 2.0, 0.0>]

#######
#######
#######

/*
# Without Stacked View capability
a = RGBAdapt_AWB_Process(matrix=matrix,show_scrutinized=show_scrutinized,show_info=show_info,
\ x=x,y=y,w=w,h=h,
\ threshold=threshold,threshold_auto=threshold_auto,
\ gain_strength=gain_strength, luma_adjust = luma_adjust,r pow_strength=rpow_strength, bias_strength=bias_strength)
*/

# With Stacked View capability

AWB_Func(matrix=matrix,show_scrutinized=show_scrutinized,show_info=show_info,
\ x=x,y=y,w=w,h=h,
\ threshold=threshold, auto_strength = auto_strength, common_strength = common_strength,
\ common_gain = common_gain, common_cont = common_cont, common_rpow = common_rpow, common_bias = common_bias,
\ gain_strength=gain_strength, cont_strength=cont_strength, rpow_strength=rpow_strength, bias_strength=bias_strength,
\ Comparison=Comparison)

/*
#----------------------------------------------based on RGBADapt plugin --------------------------------------------#
# script author : StainlessS http://forum.doom9.org/showthread.php?t=170642 #
#-------------------------------------------------------------------------------------------------------------------#

#---------------------------------------------- need RT_Stats plugin -----------------------------------------------#
# script author : StainlessS http://forum.doom9.org/showthread.php?t=165479 #
#-------------------------------------------------------------------------------------------------------------------#

#---------------------------------------------- need GRunT plugin --------------------------------------------------#
# plugin author : Gavino http://forum.doom9.org/showthread.php?t=139337 #
#-------------------------------------------------------------------------------------------------------------------#

#---------------------------------------------- need GScript plugin ------------------------------------------------#
# plugin author : Gavino http://forum.doom9.org/showthread.php?t=147846 #
#-------------------------------------------------------------------------------------------------------------------#
*/

Function RGBAdapt_AWB_Process(clip clip,string "matrix",bool "show_scrutinized",bool "show_info",float "x",float "y",float "w",float "h",
\ float "threshold", bool "auto_strength", float "common_strength",
\ bool "common_gain", bool "common_cont", bool "common_rpow", bool "common_bias",
\ float "gain_strength", float "cont_strength", float "rpow_strength", float "bias_strength") {

# Clip MUST be YV12 or RGB32. Always returns SAME colorspace as input.
clip
myName="RGBAdapt_Awb_Process: "
Assert(RT_FunctionExist("RGBAdapt"),myName+"RGBAdapt plugin must be loaded, http://forum.doom9.org/showthread.php?t=170642")
Assert(RT_FunctionExist("GScriptClip"),myName+"GRunT plugin must be loaded, http://forum.doom9.org/showthread.php?t=139337")
Assert(RT_FunctionExist("GScript"),myName+"GScript plugin must be loaded, http://forum.doom9.org/showthread.php?t=147846")
Assert(IsYV12(clip) || IsRGB32(clip),RT_String("%sInput video colorspace must be YV12 or RGB32",myName))
matrix = Default(matrix, "Rec601") # Color standard, Rec 601 or Rec 709
Assert(matrix == "Rec601" || matrix == "Rec709",RT_String("%smatrix 'Rec601' or 'Rec709'('%s')",myName,matrix))
show_scrutinized = Default(show_scrutinized, false) # show scrutinized area or not, default false
show_info = Default(show_info, false) # show info or not, default false
x = float(Default(x,0.0)) # width percentage to specify coords source rectangle under scrutiny, the default : x=y=h=w=0.0 full frame
Assert(0.0 <= x <= 0.99,RT_String("%s0.0 <= x <= 0.99(%f)",myName,x))
y = float(Default(y,0.0)) # height percentage to specify coords source rectangle under scrutiny, the default : x=y=h=w=0.0 full frame
Assert(0.0 <= y <= 0.99,RT_String("%s0.0 <= y <= 0.99(%f)",myName,y))
w = float(Default(w,0.0)) # coords specify source rectangle under scrutiny, the default : x=y=h=w=0.0 is full frame
Assert(0.0 <= w <= 0.99,RT_String("%s0.0 <= w <= 0.99(%f)",myName,w))
Assert(0.0 <= (x+w) <= 0.99 ,RT_String("%s0.0 <= (x+w) <= 0.99(%f)",myName,x+w))
h = float(Default(h,0.0)) # coords specify source rectangle under scrutiny , the default : x=y=h=w=0.0 is full frame
Assert(0.0 <= h <= 0.99,RT_String("%s0.0 <= h <= 0.99(%f)",myName,h))
Assert(0.0 <= (y+h) <= 0.99 ,RT_String("%s0.0 <= (y+h) <= 0.99(%f)",myName,y+h))
threshold = Float(Default(threshold, 0.10)) # threshold arg of RT_Stats plugin
Assert(0.0 <= threshold <= 1.0,RT_String("%s0.0 <= threshold <= 1.0(%f)",myName,threshold))
auto_strength = Default(auto_strength, true) # enable automatic cont strength, default true
common_strength = Float(Default(common_strength, 1.0)) # common strength
Assert(0.0 <= common_strength <= 2.0,RT_String("%s0.0 <= common_strength <= 2.0(%f)",myName,common_strength))
common_gain = Default(common_gain, true) # enable common cont strength, default true
gain_strength = Float(Default(gain_strength,0.0)) # manual gain strength
Assert(0.0 <= gain_strength <= 2.0,RT_String("%s0.0 <= gain_strength <= 2.0(%f)",myName,gain_strength))
common_cont = Default(common_cont, true) # enable common cont strength, default true
cont_strength = Float(Default(cont_strength,0.0)) # manual cont strength
Assert(0.0 <= cont_strength <= 2.0,RT_String("%s0.0 <= cont_strength <= 2.0(%f)",myName,cont_strength))
common_rpow = Default(common_rpow, true) # enable common cont strength, default true
rpow_strength = Float(Default(rpow_strength,0.0)) # manual rpow strength
Assert(0.0 <= rpow_strength <= 2.0,RT_String("%s0.0 <= rpow_strength <= 2.0(%f)",myName,rpow_strength))
common_bias = Default(common_bias, true) # enable common cont strength, default true
bias_strength = Float(Default(bias_strength,0.0)) # manual bias strength
Assert(0.0 <= bias_strength <= 2.0,RT_String("%s0.0 <= bias_strength <= 2.0(%f)",myName,bias_strength))

#---------- Specify the source rectangle under scrutiny, x,y,w,h are now type Int

x = int( Width * x)
y = int( Height * y)
w = int(-Width * w)
h = int(-Height * h)

#--------- RGB color space process

RGB32_clip = (!isRGB32(clip)) ? ConvertToRGB32(clip, matrix=matrix) : clip

CWID=72 CHIT=24 #69 21 # display Width and Height in Subtitle characters
MinWid=CWID*10 MinHit=CHIT*20 # RT_Subtitle required width height in pixels (fixed font size is 10x20)
TooSmall=(Width<MinWid || Height<MinHit)

RedStr = (TooSmall) ? "Red values :\n" : "\a2Red values\a- :\n"
GrnStr = (TooSmall) ? "Green values :\n" : "\a4Green values\a- :\n"
BluStr = (TooSmall) ? "Blue values :\n" : "\a1Blue values\a- :\n"

# Use same string at each frame.
Fmt=
\ "\nChannels averages average : %7.3f Common strength :%7.3f\n" +
\ RedStr +
\ "Departure : Average=%7.3f : Min/max=%-3d : Min=%-3d : Max=%-3d\n" +
\ "Finish : Average=%7.3f : Min/max=%-3d : Min=%-3d : Max=%-3d\n" +
\ " R_bias=%7.3f : R_gain =%7.3f : R_cont =%.3f : R_rpow=%.3f\n\n" +
\ GrnStr +
\ "Departure : Average=%7.3f : Min/max=%-3d : Min=%-3d : Max=%-3d\n" +
\ "Finish : Average=%7.3f : Min/max=%-3d : Min=%-3d : Max=%-3d\n" +
\ " G_bias=%7.3f : G_gain =%7.3f : G_cont =%.3f : G_rpow=%.3f\n\n" +
\ BluStr +
\ "Departure : Average=%7.3f : Min/max=%-3d : Min=%-3d : Max=%-3d\n" +
\ "Finish : Average=%7.3f : Min/max=%-3d : Min=%-3d : Max=%-3d\n" +
\ " B_bias=%7.3f : B_gain =%7.3f : B_cont =%.3f : B_rpow=%.3f\n\n" +
\ "Channels averages average : %7.3f "

Bernardd
20th November 2017, 17:52
Script last part


GSCript("""
# Nested Low level Function, Called per frame via GScriptClip(), RGB32 ONLY
Function RGBAdapt_awb_process_Lo(clip clp,String Fmt,bool show_info,int x,int y,int w,int h,
\ float threshold, bool auto_strength, float common_strength,
\ bool common_gain, bool common_cont, bool common_rpow, bool common_bias,
\ float gain_strength, float cont_strength, float rpow_strength, float bias_strength,
\ Bool TooSmall,Int CWid,Int CHit) {

clp # Last = Input RGB32 clp clip.

# n = current_frame # n is current_frame, can use in RT_Stats to access frames relative to current. Not currently Used.

#---------- Channels datas extraction and adjustement factors calculation

Last.RT_RgbChanStats(x=x,y=y,w=w,h=h,threshold=threshold,chan=-1,flgs= 1+2+4+8+16, Prefix="RCS_")

blank_clip = RCS_MinMaxDiff_0 + RCS_MinMaxDiff_1 + RCS_MinMaxDiff_2 # one color clip detection to disable auto white balance

if (auto_strength)
{ave = (RCS_Ave_0+RCS_Ave_1+RCS_Ave_2)/3.0
minmax= (RCS_Max_0+RCS_Max_1+RCS_Max_2+RCS_Min_0+RCS_Min_1+RCS_Min_2)/3.0
common_strength = (ave+minmax)/(128.0+255.0)}
else
{common_strength = common_strength}

# Leave RCS_ values as original (avoid repeat function call in Show_info), new variables without RCS_ prefix, avoid div by zero.
MinMaxDiff_0 = Max(RCS_MinMaxDiff_0, 0.00001)
MinMaxDiff_1 = Max(RCS_MinMaxDiff_1, 0.00001)
MinMaxDiff_2 = Max(RCS_MinMaxDiff_2, 0.00001)

#---------- Gain process

if (common_gain) {gain_strength = common_strength}# else {gain_strength = gain_strength}

r_gain = 1.0 + (255.0/MinMaxDiff_0 - 1.0) * gain_strength
r_gain_bias = -RCS_Min_0 * r_gain *gain_strength
g_gain = 1.0 + (255.0/MinMaxDiff_1 - 1.0) * gain_strength
g_gain_bias = -RCS_Min_1 * g_gain * gain_strength
b_gain = 1.0 + (255.0/MinMaxDiff_2 - 1.0) * gain_strength
b_gain_bias = -RCS_Min_2 * b_gain * gain_strength

#------ Contrast process

# Cont is dangerous, because it can overshoot light and dark, but it is necessary to help to find good correction for very big
# color cast.

if (common_cont) {cont_strength = common_strength}

r_cont = 1.0 + (r_gain - 1.0) * cont_strength
r_cont_max = RCS_Max_0 * r_gain + r_gain_bias + (r_cont - 1) * (RCS_Max_0 - 128)
r_cont_bias = (255 - r_cont_max) * cont_strength

g_cont = 1.0 + (g_gain - 1.0) * cont_strength
g_cont_max = RCS_Max_1 * g_gain + g_gain_bias + (g_cont - 1) * (RCS_Max_1 - 128)
g_cont_bias = (255 - g_cont_max) * cont_strength

b_cont = 1.0 + (b_gain - 1.0) * cont_strength
b_cont_max = RCS_Max_2 * b_gain + b_gain_bias + (b_cont - 1) * (RCS_Max_2 - 128)
b_cont_bias = (255 - b_cont_max) * cont_strength

r_bias = r_gain_bias +r_cont_bias g_bias = g_gain_bias +g_cont_bias b_bias = b_gain_bias + b_cont_bias

#----gamma args calculation in accordance with gray world theory

# In gray world theory, in YUV range, we increase or decrease average value to ref = 128.0, but in RGB range
# ref = average of channel average values is better.
# With contrast use, average of channel average value after gain process without cont process give a better picture light.

# In gamma process, to incresae or decrease average value, we use gamma args. To find this gamma args, we
# solve this equation ref = pow(average value/255.0,1/gamma args)

ref = (RCS_Ave_0 * r_gain + r_gain_bias + RCS_Ave_1 * g_gain + g_gain_bias + RCS_Ave_2 * b_gain + b_gain_bias)/3.0

if (common_rpow) {rpow_strength = common_strength}

r_rpow = 1 + (log((RCS_Ave_0 * r_gain + r_gain_bias)/255.0)/log(ref/255.0) - 1) * rpow_strength
r_rpow = Min (4.0, Max (r_rpow, 0.1))
g_rpow = 1 + (log((RCS_Ave_1 * g_gain + g_gain_bias)/255.0)/log(ref/255.0) - 1) * rpow_strength
g_rpow = Min (4.0, Max (g_rpow, 0.1))
b_rpow = 1 + (log((RCS_Ave_2 * b_gain + b_gain_bias)/255.0)/log(ref/255.0) - 1) * rpow_strength
b_rpow = Min (4.0, Max (b_rpow, 0.1))

#--------- bias gain cont in RGBadapt args range

r_bias = Min (512.0, Max (r_bias, -512.0)) g_bias = Min (512.0, Max (g_bias, -512.0)) b_bias = Min (512.0, Max (b_bias, -512.0))
r_gain = Min (8.0, Max (r_gain, -8.0)) g_gain = Min (8.0, Max (g_gain, -8.0)) b_gain = Min (8.0, Max (b_gain, -8.0))
r_cont = Min (8.0, Max (r_cont, -8.0)) g_cont = Min (8.0, Max (g_cont, -8.0)) b_cont = Min (8.0, Max (b_cont, -8.0))

#---------- bias corrections in accordance with gray world theory
#----------- bias corrections extraction and calcul
# ssS, Create and measure temp clip

TempC=clp.RGBAdapt(R_bias = r_bias, R_Gain = r_gain, R_Cont = r_cont, R_rpow = r_rpow,
\ G_bias = g_bias, G_Gain = g_gain, G_Cont = g_cont, G_rpow = g_rpow,
\ B_bias = b_bias, B_Gain = b_gain, B_Cont = b_cont, B_rpow = b_rpow)

TempC.RT_RgbChanStats(x=x,y=y,w=w,h=h,threshold=threshold,chan=-1,flgs=16,Prefix="TMP_") ### Use TMP_ prefix HERE

# Ref for bias corrections always calculated with gain output, because is more light than calculated with new extracted channels average values

if (common_bias) {bias_strength = common_strength}

dr = (ref - TMP_Ave_0) * bias_strength dg = (ref - TMP_Ave_1) * bias_strength db = (ref - TMP_Ave_2) * bias_strength

r_bias = (r_gain_bias + r_cont_bias + dr) g_bias = (g_gain_bias + g_cont_bias + dg) b_bias = (b_gain_bias + b_cont_bias + db)
r_bias = Min (512.0, Max (r_bias, -512.0)) g_bias = Min (512.0, Max (g_bias, -512.0)) b_bias = Min (512.0, Max (b_bias, -512.0))

#------------ AWB output with gain cont rpow and bias process
# now change for real

(blank_clip==0)
\ ? clp
\ : clp.RGBAdapt(R_bias=r_bias,R_Gain=r_gain,R_Cont=r_cont,R_rpow=r_rpow,
\ G_bias=g_bias,G_Gain=g_gain,G_Cont=g_cont,G_rpow=g_rpow,
\ B_bias=b_bias,B_Gain=b_gain,B_Cont=b_cont,B_rpow=b_rpow)

if(show_info) {
#--------- final RGB values extraction for display
# Use different 'FIN_' Prefix so as not to destroy original variables

Last.RT_RgbChanStats(x = x, y = y, w = w, h = h, threshold = threshold, chan = -1, flgs = 1+2+4+8+16,Prefix="FIN_")

S=RT_String(Fmt,
\ (RCS_Ave_0+RCS_Ave_1+RCS_Ave_2)/3.0,common_strength,
\
\ RCS_Ave_0, RCS_MinMaxDiff_0, RCS_Min_0, RCS_Max_0,
\ FIN_Ave_0, FIN_MinMaxDiff_0, FIN_Min_0, FIN_Max_0,
\ r_bias, r_gain,r_cont,r_rpow,
\
\ RCS_Ave_1, RCS_MinMaxDiff_1, RCS_Min_1, RCS_Max_1,
\ FIN_Ave_1, FIN_MinMaxDiff_1, FIN_Min_1, FIN_Max_1,
\ g_bias, g_gain,g_cont,g_rpow,
\
\ RCS_Ave_2, RCS_MinMaxDiff_2, RCS_Min_2, RCS_Max_2,
\ FIN_Ave_2, FIN_MinMaxDiff_2, FIN_Min_2, FIN_Max_2,
\ b_bias,b_gain,b_cont,b_rpow,
\
\ (FIN_Ave_0 + FIN_Ave_1 + FIN_Ave_2 )/3, Esc=(TooSmall)?0:1)

(TooSmall)
\ ? Last.Subtitle(S,Font="Courier New",lsp=0,text_color=$FFFF00,halo_color=$0,size=height/float(CHIT),
\ Font_width=width/FloaT(CWID))
\ : Last.RT_Subtitle("%s",S)
} # End ShowInfo
Return Last
} # End, RGBAdapt_awb_process_Lo()

# GScriptClip, Calling Low level Function RGBAdapt_awb_process_Lo() at each frame.
# Named ARGS variables at current script level, are imported into GScriptClip script, and passed as args to RGBAdapt_awb_process_Lo().
ARGS="Fmt,show_info,x,y,w,h,threshold,"+
\ " auto_strength, common_strength,"+
\ " common_gain, common_cont, common_rpow, common_bias,"+
\ " gain_strength, cont_strength, rpow_strength, bias_strength,"+
\ " TooSmall,CWid,CHit"

RGB32_clip.GScriptClip("RGBAdapt_awb_process_Lo(last,"+ARGS+")", local=true, args=ARGS)

# Do border outside of Scriptclip.
if(show_scrutinized) {
Level = 100 # 0 (Off) -> 257 (Full)
MarkColor = $00FF00
#-------- display scrutinized area
scrutinized_green = Last.BlankClip(width = Width-x+w, height = height-y+h, color=MarkColor)
scrutinized_mask = scrutinized_green.Blankclip(color=$0).LetterBox(2,2,2,2,$FFFFFF)
Layer(last,scrutinized_green.Mask(scrutinized_mask),x=x,y=y,level=Level)
} # End show_scrutinized
""")
Return (clip.isYV12) ? ConvertToYV12(last, matrix=matrix) : last # Return original colorspace, YV12 or RGB32
}

Function AWB_Func(clip clip, string "matrix",bool "show_scrutinized", bool "show_info", float "x", float "y", float "w", float "h",
\ float "threshold", bool "auto_strength", float "common_strength",
\ bool "common_gain", bool "common_cont", bool "common_rpow", bool "common_bias",
\ float "gain_strength",float "cont_strength", float "rpow_strength", float "bias_strength",
\ bool "Comparison") {

# Clip MUST be YV12 or RGB32. Always returns SAME colorspace as input.
Gscript("""
clip
output=clip.RGBAdapt_Awb_Process(matrix=matrix,show_scrutinized=show_scrutinized,show_info=show_info,x=x,y=y,w=w,h=h,threshold=threshold,
\ auto_strength = auto_strength, common_strength = common_strength,
\ common_gain = common_gain, common_cont = common_cont, common_rpow = common_rpow, common_bias = common_bias,
\ gain_strength=gain_strength, cont_strength=cont_strength, rpow_strength=rpow_strength, bias_strength=bias_strength)
if (!Default(Comparison,false)) {
output
} else {
# Here, Clip is either RGB32 or YV12.
# Ensure RGB32 for all calls to RGBAdapt_Awb_Process (Only convert input at most once)
RGB_Clip = (Clip.IsYV12) ? clip.ConvertToRGB32(matrix=matrix) : clip
only_gain = RGB_Clip.RGBAdapt_awb_process(matrix=matrix,show_scrutinized=show_scrutinized,show_info=show_info,
\ x=x,y=y,w=w,h=h, threshold=threshold, auto_strength = true,common_cont = false,common_rpow = false,
\common_bias = false)
without_cont_rpow = RGB_Clip.RGBAdapt_awb_process(matrix=matrix,show_scrutinized=show_scrutinized,show_info=show_info,
\ x=x,y=y,w=w,h=h,threshold=threshold, auto_strength = true, common_cont = false, common_rpow = false)
without_contrast = RGB_Clip.RGBAdapt_awb_process(matrix=matrix,show_scrutinized=show_scrutinized,show_info=show_info,
\ x=x,y=y,w=w,h=h,threshold=threshold, auto_strength = true,common_cont = false)
only_gain_full = RGB_Clip.RGBAdapt_awb_process(matrix=matrix, show_scrutinized=show_scrutinized, show_info=show_info,
\ x=x, y=y, w=w, h=h,threshold=threshold, auto_strength =false, common_strength = 1.0,
\ common_cont = false,common_rpow = false,common_bias = false)
without_cont_rpow_full = RGB_Clip.RGBAdapt_awb_process(matrix=matrix,show_scrutinized=show_scrutinized,show_info=show_info,
\ x=x,y=y,w=w,h=h,threshold=threshold, auto_strength =false, common_strength = 1.0,
\ common_cont = false, common_rpow = false)
full = RGB_Clip.RGBAdapt_awb_process(matrix=matrix, show_scrutinized=show_scrutinized, show_info=show_info,
\ x=x, y=y, w=w, h=h,threshold=threshold, auto_strength = false, common_strength = 1.0)

YV12_Clip = (clip.IsRGB32) ? clip.ConvertToYV12(matrix=matrix) : clip
colorYUV_AWB = YV12_Clip.ColorYUV(autowhite = true)

# Convert clips to original Input ColorSpace.
if(clip.IsRGB32) {
colorYUV_AWB = colorYUV_AWB.ConvertToRGB32(matrix=matrix)
} else {
only_gain = only_gain.ConvertToYV12(matrix=matrix)
without_cont_rpow = without_cont_rpow.ConvertToYV12(matrix=matrix)
without_contrast = without_contrast.ConvertToYV12(matrix=matrix)
only_gain_full = only_gain_full.ConvertToYV12(matrix=matrix)
without_cont_rpow_full = without_cont_rpow_full.ConvertToYV12(matrix=matrix)
full = full.ConvertToYV12(matrix=matrix)}

#~ contrast_label=(cont_strength==0.0) ? "without contrast"
#~ \ : (cont_strength>0.0) ? "with contrast"
#~ \ : "contrast in accordance with threshold"

STK1 = StackHorizontal(
\ only_gain.AddBorders(0,20,0,0,color=$0).Subtitle("only gain "),
\ without_cont_rpow.AddBorders(0,20,0,0,color=$0).Subtitle("only gain and bias without contrast and rpow"),
\ without_contrast.AddBorders(0,20,0,0,color=$0).Subtitle("gain rpow and bias process without contrast"))
STK2 = StackHorizontal(
\ clip.AddBorders(0,20,0,0,color=$0).Subtitle("original"),
\ colorYUV_AWB.AddBorders(0,20,0,0,color=$0).Subtitle("As a reminder, classical ColorYUV awb"),
\ output.AddBorders(0,20,0,0,color=$0).Subtitle ("Selected output"))
STK3 = StackHorizontal(
\ only_gain_full.AddBorders(0,20,0,0,color=$0).Subtitle("only gain with contrast with fixed strength = 1.0"),
\ without_cont_rpow_full.AddBorders(0,20,0,0,color=$0).Subtitle("only gain and bias without contrast and rpow with fixed strength = 1.0"),
\ full.AddBorders(0,20,0,0,color=$0).Subtitle("default with fixed common strength = 1.0"))
StackVertical(STK1,STK2,STK3)
} # End, if
""") # End GScript
Return Last # Return Original ColorSpace
}

Sachin
20th November 2017, 18:14
Bernard
Thank you very much

Bernardd
29th January 2018, 21:15
New script version.

Five ways for color cast correction.
action with gain,
action with contrast,
action with rpow,
acion with spow,
action with bias.
This five actions can work together or independantly. Each action have thus a tunable power strength.

In default mode, the script use gain, contrast, rpow and bias process. It compute a strength weighting
factor for each actions. This mode give often readable results for many videos with a little color cast.
The operator can refine the result with manual mode of each action (to desable contrast can be a good idea).

With big color cast, the operator can desable the automatic strength weighting factor mode to use the
whole correction of each process, it also enable spow process.

The script have always a comparison display mode to help to find the better combination of the five actions.
This mode show nine output of the video.
Top, without contrast action, in automatic strength weighting factor strength mode, you have from rigth
to left gain action only, gain and bias actions, followed by gain, rpow and bias actions.
Middle, from rigth to left, original input, AutoWhite ColorYUV process, and the tuned script output.
Bottom, from rigth to left, with strength weighting factor equal to 1.0,
gain action only, gain and bias actions, followed by gain, contrast, rpow and bias actions.

Comment
If you use AvsPmod, you can uncomment lines 45 to 72 to have UserSliders facility.
They are now two automatic strength weigthing factors. One for gain and contrast process : (channel min average + channel
max average)/255 and one for gamma and bias process channel average average/128.

The script in attachments

Bernard

ABDO
4th February 2018, 13:02
the best Automatic white balance i have ever use,thanks @Bernardd.

Bernardd
16th February 2018, 17:31
New script version with automatic white balance improved in hight light.

Six ways for color cast correction.
action with gain,
action with contrast,
action with bias rpow mix,
action with spow,
action with final bias.
This six actions can work together or independantly. Each action have thus a tunable power strength.

In default mode, the script use gain, contrast, bias rpow mix, spow and final bias process.
It compute a strength weighting factor for each actions. This mode give often readable results for many videos.

The operator can refine the result with manual mode of each action. In first action i suggest to desable the contrast.
After you can use the comparison display mode, which help to find the better combination of the six actions.

Comment
If you use AvsPmod, you can uncomment lines 46 to 77 to have UserSliders facility.

The script here
and here https://www.dropbox.com/s/qft9f4fzrptsxzj/RGBAdapt_Awb_Process%20v%202018%20fev.avs?dl=0

Bernard

Bernardd
2nd March 2018, 11:46
Hello,
New script version which improve process.

First in past i have used a tip to control strength of gain, contrast and gamma process. Thus when i tuned strength to 0.0
gain, contrast and gamma values were 1.0 (neutral). When i tuned strength to 1.0, gain, contrast and gamma values were the
computed values from RGB channels datas. For example the formula for gain was :
gain = 1.0 + (255.0/MinMaxDiff_0 - 1.0) * gain_strength
In manual mode this tip is not a problem, the operator choose the good gain_strength value. But in past, in automatic mode,
i calculated a gain_strength value based on RGB channels datas to decrease, to ponderate the process strength and in this case
the formula is not accurate 1.0 + (255.0/MinMaxDiff_0 - 1.0) * gain_strength is not (255.0/MinMaxDiff_0) * gain_strength, when
gain_strength >0.0 and < 1.0.

Now i used this formula gain = (255.0/MinMaxDiff_0) * (ponderate_factor + gain_strength)
gain_strength is manual adujst arg in range from -1.0 to 1.0 with default 0.0

With the last formulas i have some problem of luma. Thus i was obliged to base the bias calcul on average of RGB channels
averages after gain to recover readable something. With accurate formulas, no luma problem. Thus all process use the RGB
channels values of original clip.

Thus the new script is for color cast correction with five and half process.
action with gain,
action with contrast,
action with one bias and rpow mix,
action with spow,
and the half,only if contrast is enable, action with one final bias to recover luma. (Contrast increase color saturation but
also decrease luma.)

This actions can work together or independantly.

The operator can enable or desable gain, contrast, rpow and spow process with boolean switchs.
He can also adjust the computed strength of gain and contraste with theire strength args.
Bias and Gamma (rpow and spow) process are auto mixed in default mode. The operator can desable this automatic process with
a boolean switch. In this case the operator can tune the bias gamma mix percentage with one arg.
In manual mix mode percentage = 0.0 traduce only gamma process, 1.0 only bias.
For inflexion point of Spow curve, the script compute one automatic spmid by RGB channels, but the operator can adjust these
spmid with a spmid strength arg.

One arg stay always manual. "pord" equal false (default) rpow corrections are computed before spow corrections, true inverse

Gain bias formulas are classic formulas. Gamma formula is a mathematical application of grey world theory. Nota, gain and contrast
are having the same formula, rpow and spow have the same formula.

Automatic ponderation factor for gain and contrast, automatic bias gamma mixed percentage and spmid have formulas choosed after
many personnal tests.

This formulas are choosed for big colors casts like lena or tahiti clip, but i think they give readable output for low colors
casts. But for big colors casts with washed colors, the spmid formula is not the best. In this case i suggest first to decrease the
spmid strength and after to try to adjust bias gamma mix in manual mode.

Below some samples

Lena with default mode and comparaison display and RgbAdapt graffer to show curves.

https://www.dropbox.com/s/cizhhta89kz3cgy/Lena%20comparaison.jpg?dl=0

https://www.dropbox.com/s/4f1t8qb4gwd06om/Lena%20Graffer.jpg?dl=0

Tahiti clip with default mode. On this sample we can see problem with contrast. Contrast is necessary to recover color, but we
loose some details in the dark. At the end, red is a little magenta. A little hue with Tweak function can solve this look.
https://youtu.be/y4LSb0pcTsU

Disneyland park. on left half original, on right half default without contrast and on right without contrast but with
decreased spmid strength to 0.6. I do'nt suggest that default without contrast and 0.6 spmid is the good combination, but it is
very fast to find.
https://youtu.be/x6oVh5PmTGk

Comment
If you use AvsPmod, you can uncomment lines 43 to 70 to have UserSliders facility.

The script in attachment
and here https://www.dropbox.com/s/j02xhirllh4fudn/RGBAdapt_Awb_Process%20v%202018%20mar.avs?dl=0

Bernardd
30th June 2018, 23:07
Hello
New script version. Better luma process.
It is a manual white balance, you must tune the args.

The script args are :

comparison = boolean arg to show differents settings output
show_scrutinized = boolean arg to show the scrutinized aera
show_info = boolean arg to show extracted and comptuted datas

matrix = "Rec601" or "Rec709" to choice the color conversion matrix
x = float arg to specify the left of scrutinized aera
Y = float arg to specify the top of scrutinized aera
w = float arg to specify the right of scrutinized aera
h = float arg to specify the bottom of scrutinized aera

threshold = float arg to specify extreme pixels percentage to be ignored when datas extraction

gain_strength = float arg to enable gain process and increase his strength
cont_strength = float arg to enable contrast process and increase his strength
cont_adapt = float arg to adapt contrast bias
bias_gamma = boolean arg to enable bias and gamma white balance process
bias_strength = float arg to enable bias process and increase his strength
gamma_strength = float arg to enable gamma process and increase his strength
cont_adapt2 = is the same arg as cont_adapt, but its vlaue is used when bias and gamma white balance is enable
spow = boolean arg to enable spow process
pord = boolean arg to secify order of rpow and spow process
spmid_strength = float arg to adapt spimd
temperature = float arg to increase or decrease color temperature

The script calculate for each color channel,
- the classic autogain with a gain bias to keep the value between 0 to 255
- the contrast, with gain formula and a cont bias to aviod a visual bad offset
- a bias to keep the luma value after gain and or contrast application
- in accordance with the grey world theory a bias to get the same value of color channel average
- in accordance with the grey world theory a rpow float number
- a spow float number with the rpow formula
- a spmid number to specify inflexion point of the s curve

Cont_adapt, cont_adapt2, bias_gamma, pord and temperature are not computed. They are operator choices.

The operator can modify, adjust the computed results by increasing or decreasing gain, contrast, bias and gamma strengths and cont adapt.
The operator can choice the combination of process. Gain, contrast, bias and gamma strengths desable process when their values are null.

Nota : For gain and contrast strengths = 0.0, gain and contrast factors = 1.0 and gain bias and contrast bias = 0.0.
But, for gain and contrast strengths = 0.1, gain and contrast factors are near to 1.0, but gain and contrast bias are not null. For sample, if
the min value of one color channel is 100, the bias for gain is -100.

The perform of this script is the contrast bias use. The operateur can tune cont_adapt2 (or cont_adapt if only gain and contrasts process are
selected) to get the best contrast bias.
For some videos, it is possible to get a readable white balance with only gain and contrast process.
For other video, you must use classical bias and gamma process. The arg tunes are manual

With the boolean arg bias_gamma, you can make a fast comparison between gain and contrast result and result of combination of gain, contrast, bias and gamma .

The default args give a readable output with "lena" color cast sample picture. But it can be better. First decrease or increase cont-adapat2.

The script have always a comparison display mode to help to find the better combination of actions.
This mode show nine output of the video.
Top, from left to right, gain action only, gain and bias actions, followed by gain, rpow and bias actions.
Middle, from left to right, original input, AutoWhite ColorYUV process, and the tuned script output.
Bottom, from left to right, default modes without gain, and without cont, default modes without gain and default modes all process.

Comment
If you use AvsPmod, you can uncomment lines 45 to 76 to have UserSliders facility.

The script here in attachment
and here https://www.dropbox.com/s/lhvwqufa8hu1rgm/RGBAdapt_Awb_Process%20v%202018%20juil.avs?dl=0


Bernard

Bernardd
17th September 2018, 15:44
Hello,

The script with two automatic modes and one manual.
The first automatic mode use only gain and contrast process, sometimes for white balance it is enough.
The second automatic mode use gain, contrast, bias and gamma process. In this mode you can adjust gamma S curves process action to refine the white balance.
In manual mode you tune separately each process actions.

The script args are :
1- for display tunings
- comparison , default = false, to compare different process selection outputs :
-------------------Top, from left to right, full gain an contrast action,full contrast action, followed by automatic gain and contrast actions.
-------------------Middle, from left to right, original input, AutoWhite ColorYUV process, and the tuned script output.
-------------------Bottom, from left to right, automatic mode without rpow, automatic modes without spow and automatic mode all process.
- show_scrutinized, default = false, to select the area scrutinized by RT_Stat plugin for data extraction
- show_info, default = false, to see extracted datas and process args tune

- matrix, defaut = "Rec601", to give the video color space matrix
- x, default = 0.1, to specify the source rectangle under scrutiny by RT_Stat plugin for data extraction
- Y, default = 0.1, see RT_STAT doc
- w, default = 0.1
- h, default = 0.1

- threshold, default = 0.1, to specify extreme pixels percentage to be ignored when datas extraction (see RT_STAT doc)

2- automatic white balance preset tunings

- mode, default = "auto", in this case all process are used in automatic, if "gain_&_cont" only gain and contrast are used in automatic,
if "manual" you tune separately each process
- rpow, default = true, only efficiency in mode "auto", you can enable or desable the rpow process,
- spow, default = true, only efficiency in mode "auto", you can enable or desable the rpow process,
- spow_adjust, default = 0.0, float from -1.0 to 1.0, only efficiency in mode "auto", you can adjust the automatic computed spow strength to refine spow process. If value = 0.0 no computed spow strength have not change.

3- manual white balance tunings
- gain_strength, default = 0.5, float from 0.0 to 1.0, to tune gain process strength. If value = 0.0 no gain process use.
- cont_strength, default = 0.5, float from 0.0 to 1.0, to tune contrast process strength. If value = 0.0 no conttrast process use.
- g_c_bias_adapt, default = 0.5, float from 0.0 to 1.0, to adjust the automatic bias computed when gain and or contrast are applied.
If value = 0.0 computed gain and cont bias = 0.0.
- bias_strength, default = 0.5, float from 0.0 to 1.0, to tune bias process strength. This bias is a computed bias in accordance with grey world theory for color balance. If value = 0.0 no bias process use.
- rpow_strength, default = 0.5, float from 0.0 to 1.0, to tune rpow process strength. This computed rpow is the application of the grey world theory for color balance to gamma space. Explanation in script comment. If value = 0.0 no rpow process use.
- spow_strength, default = 1.5, float from 0.0 to 2.0, to tune spow process strength. Like rpow proces but with S curve.
If value = 1.0 no spow process use.

4- spow process's specifics tunes in automatic or manual mode, if spow process is enable
- pord, default = false, priority for rpow or spow process, see RGBAdapt doc.
- spmid_strength, default = 1.0, float from 0.0 to 1.0, you can adjust the automatic computed spmid strength to refine spow process


In this script, gain formula and grey world bias formula are classical. The other formulas are empirical, i have searched formulas to mix maximal,
minimal and average values of each RGB channel RGB to :
- do not use too much the autogain process and
- get best results with almong videos clips plubished on this forum like
here https://forum.doom9.org/showpost.php?p=1800097&postcount=83
or found on WDW plublication https://forum.doom9.org/showpost.php?p=1716590&postcount=924

The problem of this method is to found a good mix of datas to get always the good S curve correction. In fact, the Max, Min and average values of RGB channels are not enough to describe a color channel histogram with two or more pic values. Thus i have jut found one formula for gentle videos.
A manual adjust of Spow correction is often necessary. You can make it by tuning spow_adjust and or spmid args.

Each video is specific, each scene is specific, a tip is to look at the comparison display output of the script to find the best combination of process.
Often, if the automatic mode without spow seem to be the best, you have interest before to desable spow, to tune spow_adjust and or spmid tune. With this display you can find some scene like below, which have a good result with only manual contrast use (result with full gain and contrast seem better, but you have no reserve for add autogain and more saturation).

https://www.dropbox.com/s/omvsv5aj7uhykn8/RGBAdapt_Awb_Process%20v%202018%20sept000082.jpg?dl=0

Comment
If you use AvsPmod, you can uncomment lines 49 to 81 to have UserSliders facility.

The script here in attachment
and here https://www.dropbox.com/s/kxwctnxg5qx187o/RGBAdapt_Awb_Process%20v%202018%20sept.avs?dl=0

Bernard

Bernardd
21st September 2018, 17:34
Hello,
I want help about Gscript use.
In my script in the previous post, i try to make a iteration with the "spow_adjust" arg.
Thus i have change my script in avsi and i have this little script to make iteration.


Import("F:\...........\RGBAdapt_Awb_Process v 2018 sept.avsi")

x = int( Width * 0.1)
y = int( Height * 0.1)
w = int(-Width * 0.1)
h = int(-Height * 0.1)
ConvertToRGB()
GScriptClip(last,"""
ConvertToRGB()
RT_RgbChanStats(x = x, y = y, w = w, h = h, threshold = 0.1, chan = -1, flgs = 16,Prefix="ORI_")
GScript("
cond = 0.8
spow_adjust = -1.0
while (cond < 0.9 && cond > 1.1)
{
OUT=last.RGBAdapt_AWB_Process(show_info = false, Spow_adjust = spow_adjust)
out.RT_RgbChanStats(x = x, y = y, w = w, h = h, threshold = 0.1, chan = -1, flgs = 16,Prefix=FIN_)
cond =(FIN_Ave_0 + FIN_Ave_1 + FIN_Ave_2)/(ORI_Ave_0 + ORI_Ave_1 + ORI_Ave_2)
if (cond > 0.9 && cond <1.1) {u = spow_adjust} else { spow_adjust = spow_adjust + 0.1 }
return u
}
")
return last.RGBAdapt_AWB_Process(show_info = true, Spow_adjust = u)
""", local=true, args="x,y,w,h")


But, i cannot get the data "u". i get an error message : I don't know what "u" means.
I do not see the way to get the result of the statement of the while.

Thanks for futur explanation.

Bernard

StainlessS
21st September 2018, 18:24
I really dont have a clue what you are trying to achieve.

while (cond < 0.9 && cond > 1.1) { # executes ONCE, as start with cond=0.8, and exit unconditionally
OUT=last.RGBAdapt_AWB_Process(show_info = false, Spow_adjust = spow_adjust)
out.RT_RgbChanStats(x = x, y = y, w = w, h = h, threshold = 0.1, chan = -1, flgs = 16,Prefix=FIN_)
cond =(FIN_Ave_0 + FIN_Ave_1 + FIN_Ave_2)/(ORI_Ave_0 + ORI_Ave_1 + ORI_Ave_2)
# u not assigned in else statement, ie I dont know what u means on next line.
if (cond > 0.9 && cond <1.1) {u = spow_adjust} else { spow_adjust = spow_adjust + 0.1 }
return u # Exit loop unconditionally ("I dont know what u means", not assigned in Else above)
}


EDIT: And by the way, "<" is not inverse of ">", what about "<=". (or vice versa)

EDIT: Float iteration something like

spow_start= -10 # -1 * 10.0
spow_end = 20 # 2 * 10.0

for(spow_int=spow_start,spow_end) {
spow_float = spow_int / 10.0
...
if(whatever) {
...
} Else {
spow_int = spow_end # exit iterations early
}
}

Bernardd
21st September 2018, 23:18
Thanks for your fast answer.
I haved found my script need often to tune spow_tune args to refine the AWB. To tune this args first way is to choice the best picture, but perhaps a second way should be to tune this arg to have the channel average average of input video equal the channel average average of output video.
Thus i try to do automatic this second way with intention to study his efficiency.

I have use your tip in the second part of your post and write this script, which seem run.

x = int( Width * x)
y = int( Height * y)
w = int(-Width * w)
h = int(-Height * h)
ConvertToRGB()
GScriptClip(last,"""
RT_RgbChanStats(x = x, y = y, w = w, h = h, threshold = 0.1, chan = -1, flgs = 16,Prefix="ORI_")
GScript("
for ( adjust = -1 , 1 , 1 ) {
spow_adjust = adjust/10.0
OUT=last.RGBAdapt_AWB_Process(show_info = false, Spow_adjust = spow_adjust)
out.RT_RgbChanStats(x = x, y = y, w = w, h = h, threshold = 0.1, chan = -1, flgs = 16)
OUT2=last.RGBAdapt_AWB_Process(show_info = true, Spow_adjust = spow_adjust)
cond =(RCS_Ave_0 + RCS_Ave_1 + RCS_Ave_2)/(ORI_Ave_0 + ORI_Ave_1 + ORI_Ave_2)
if ((cond > 0.9) && (cond <1.1)) {adjust = 10} else { }
return out2
}
")
""", local=true, args="x,y,w,h")


Thanks
Bernard

`Orum
4th December 2018, 14:58
I've been looking for AWB for AviSynth, and stumbled across this. Two quick questions:

This appears to require GScript, which AFAIK was never ported to 64-bit as some of it was incorporated into AVISynth+. Any chance we could see a version of this that works with 64-bit AviSynth+?
Does this do a per-frame AWB? I have some footage that was already using some automatic AWB within the camera, and thus it fluctuates wildly (and usually incorrectly) over the course of the video. I'm hoping to get something that will both stabilize the white balance as well as correct it.

Thanks!

StainlessS
6th December 2018, 14:16
Orum,
I'm doing (well done) x64 version of RgbAdapt, maybe post today.
Can just delete any GScript(""" ... """) from script and it should work ok. (Will also need RT_Stats v2.00.Beta11 x64)

Am also looking at possibility of GScript x64 dll (probably x64 only, as can just add GScript x86 dll to avs+) which just calls avs+ Eval, dont now if I can get it to work ok.
Current situation of having to edit each existing script for use with avs+ x64 is a little intolerable.
[EDIT: Same type of thing for GImport, and GEval]

EDIT: GScript has some assembler to catch exceptions, maybe reason was never ported. (Maybe also reason I may not get it to work ok).

EDIT:
Also comment out this line.

# Assert(RT_FunctionExist("GScript"),myName+"GScript plugin must be loaded, http://forum.doom9.org/showthread.php?t=147846")

Works ok as suggested above. I'll post x64 RgbAdapt now.

EDIT: Also need x64 Grunt for GScriptClip.

Bernardd
6th December 2018, 14:43
Hello,

This new script version has one target : a better automatic white balance than ColorYUV(autowhite=true).

Thus the script have one display args to show the assesment :

- comparison , default = false, to compare ColorYUV(autowhite=true) output with three other outputs :
------- Top, from left to right, original input, like AutoWhite ColorYUV process.
------- Bottom, from left to right, automatic mode with whole process, tuned script output.

The script automatic mode is not full optimized, often the spmid strength need to be tuned,
Thus the script have one second display args to verify spmid strength influency :

- influency , default = false, to compare different process selection outputs :
------- Top, from left to right, original input, automatic mode with whole process, but with spmid strength = 0.5.
------- Bottom, from left to right, automatic mode with whole process, but with spmid strength = 1.5, tuned script output.

The script have two other display args :

- show_scrutinized, default = false, to display the scrutinized area by RT_Stat plugin for data extraction.
- show_info, default = false, to see extracted datas and process args tunes.

The script have the following args to tune the white balance process :

- matrix, defaut = "Rec601", to give the video color space matrix
- x, default = 0.1, to specify the source rectangle under scrutiny by RT_Stat plugin for data extraction
- Y, default = 0.1, see RT_STAT doc
- w, default = 0.1
- h, default = 0.1

- threshold, default = 0.1, to specify extreme pixels percentage to be ignored when datas extraction (see RT_STAT doc)


- auto, default = true, in this case process are used in automatic (automatic mode), if false process are used in manual,

In automatic mode, whith these args, you can choice auto process combination
- gain, default = true, gain process enable
- cont, default = true, cont process enable
- g_c_bias, default = true, gain and contrast bias process enable
- bias, default = true, bias process enable
- rpow, default = true, rpow process enable
- spow, default = true, spow process enable

In manual mode, whith these args, you can built the process combination and tune strength of each process
- gain_strength, default = 0.5, float from 0.0 to 1.0, to tune gain process strength.
If value = 0.0 no gain process use.
- cont_strength, default = 0.5, float from 0.0 to 1.0, to tune contrast process strength.
If value = 0.0 no contrast process use.
- g_c_bias_adapt, default = 0.5, float from 0.0 to 1.0, to adjust the automatic bias computed when gain and or contrast are applied.
If value = 0.0 computed gain and cont bias = 0.0.
- bias_strength, default = 0.5, float from 0.0 to 1.0, to tune bias process strength.
This bias is a computed bias in accordance with grey world theory for color balance. If value = 0.0 no bias process use.
- rpow_strength, default = 0.5, float from 0.0 to 1.0, to tune rpow process strength.
This computed rpow is the application of the grey world theory for color balance to gamma space. Explanation in script comment.
If value = 0.0 no rpow process use.
- spow_strength, default = 1.5, float from 0.0 to 2.0, to tune spow process strength. Like rpow proces but with S curve.
If value = 1.0 no spow process use.

In auto or manual mode, two spow process's specifics tunes, if spow process is enable
- pord, default = false, priority for rpow or spow process, see RGBAdapt doc.
- spmid_strength, default = 1.0, float from 0.0 to 1.0, you can adjust the automatic computed spmid strength to refine spow process


In this script, gain formula and grey world bias formula are classical. The other formulas are empirical, i have searched formulas
to mix maximal, minimal and average values of each RGB channel RGB to :
- do not use too much the autogain process and
- get best results with almong videos clips plubished on this forum

The problem of this method is to found a good mix of datas to get always the good S curve correction. In fact, the Max, Min and
average values of RGB channels are not enough to describe a color channel histogram with two or more pic values. Thus i have
found one formula for gentle videos. For the other videos, a manual adjust of Spmid correction is often necessary.
Look the spmid strength influency display.

Each video is specific, each scene is specific, the script is not a universal solution, some time one following correction like
ColorYUV(off_u = - 5, off_v = 5) or adjust with tweak function can be good.

Comment
If you use AvsPmod, you can uncomment lines 52 to 85 to have UserSliders facility.

The script here in attachment
and here https://www.dropbox.com/s/9hzgf3v697omyjm/RGBAdapt_Awb_Process%20v%202018%20dec.avs?dl=0

Bernard

Bernardd
6th December 2018, 14:46
'Orum
item one : Stainless have give you answer for RGBAdapt.dll.
But before, to try to port the script to 64 bits, i am trying to find best formulas for automatic process.
Thus the last release is 32 bits.

item two : The script does a per-frame AWB.
In auto, with only bias enable, you have AWB with ColorYUV(autowhite = true) look.
In this case, the channel datas after ColorYUV output and Script output are not exactly same, perhaps its done by
colorsapace conversions. But in this case, if coloryuv give a bad result because a big colored object overshoot the
white balance, you can use the script and modify the scrutinized aera to ignore the object.

The script use gain and cont based on Max and Min values, if your video fluctuates wildly, perhaps try to increase
thresehold (RT_Stats args for data extraction), to ignore extreme pixels.

I suggests you try the last script version.

Bernard

StainlessS
6th December 2018, 15:19
Only tested new script with 1 clip (JohnMeyer Parade clip, all defaults) but works great (tested both x86 and x64[after suggested edits for GScript] no problem).
Nice job Bernardd, thanks. https://www.cosgan.de/images/smilie/froehlich/g015.gif

StainlessS
29th December 2018, 23:55
Here mod for Avs+ or GScript required (should work ok in x86 or x64 with suitable plugins).

Post 1 of 2
RGBAdapt_Awb_Process.avs

Function RGBAdapt_AWB_Process(clip clip,string "matrix",bool "show_scrutinized",bool "show_info",float "x",float "y",float "w",
\ float "h", float "threshold", bool "auto", bool "gain", bool "cont", bool "g_c_bias",
\ bool "bias", bool "rpow", bool "spow",
\ float "gain_strength", float "cont_strength", float "g_c_bias_adapt",
\ float "bias_strength", float "rpow_strength", float "spow_strength",
\ float "spmid_strength", bool "pord") {
# Clip MuST be YV12 or RGB32. Always returns SAME colorspace as input.
clip
myName="RGBAdapt_Awb_Process: "
IsAvsPlus=(FindStr(UCase(versionString),"AVISYNTH+")!=0) HasGScript=RT_FunctionExist("GScript")
Assert(IsAvsPlus || HasGScript,"AWB_Func: Must have either Avs+ or Gscript")
Assert(RT_FunctionExist("RGBAdapt"),myName+"RGBAdapt plugin must be loaded, http://forum.doom9.org/showthread.php?t=170642")
Assert(RT_FunctionExist("GScriptClip"),myName+"GRunT plugin must be loaded, http://forum.doom9.org/showthread.php?t=139337")
Assert(IsYV12(clip) || IsRGB32(clip),RT_String("%sInput video colorspace must be YV12 or RGB32",myName))
matrix = Default(matrix, "Rec601") # Color standard, Rec 601 or Rec 709
Assert(matrix == "Rec601" || matrix == "Rec709",RT_String("%smatrix 'Rec601' or 'Rec709'('%s')",myName,matrix))
show_scrutinized = Default(show_scrutinized, false) # show scrutinized area or not, default false
show_info = Default(show_info, false) # show info or not, default false
x = float(Default(x,0.1)) # width percentage to specify coords source rectangle under scrutiny, the default : x=y=h=w=0.0 full frame
Assert(0.0 <= x <= 0.99,RT_String("%s0.0 <= x <= 0.99(%f)",myName,x))
y = float(Default(y,0.1)) # height percentage to specify coords source rectangle under scrutiny, the default : x=y=h=w=0.0 full frame
Assert(0.0 <= y <= 0.99,RT_String("%s0.0 <= y <= 0.99(%f)",myName,y))
w = float(Default(w,0.1)) # coords specify source rectangle under scrutiny, the default : x=y=h=w=0.0 is full frame
Assert(0.0 <= w <= 0.99,RT_String("%s0.0 <= w <= 0.99(%f)",myName,w))
Assert(0.0 <= (x+w) <= 0.99 ,RT_String("%s0.0 <= (x+w) <= 0.99(%f)",myName,x+w))
h = float(Default(h,0.1)) # coords specify source rectangle under scrutiny , the default : x=y=h=w=0.0 is full frame
Assert(0.0 <= h <= 0.99,RT_String("%s0.0 <= h <= 0.99(%f)",myName,h))
Assert(0.0 <= (y+h) <= 0.99 ,RT_String("%s0.0 <= (y+h) <= 0.99(%f)",myName,y+h))
threshold = Float(Default(threshold, 0.10)) # threshold arg of RT_Stats plugin
Assert(0.0 <= threshold <= 1.0,RT_String("%s0.0 <= threshold <= 1.0(%f)",myName,threshold))
auto = Default(auto, true) # enable automatic process, default true
gain = Default(gain, true) # enable gain process, default true
cont = Default(cont, true) # enable cont process, default true
g_c_bias = Default(g_c_bias, true) # enable g_c_bias process, default true
bias = Default(bias, true) # enable bias process, default true
rpow = Default(rpow, true) # enable rpow process, default true
spow = Default(spow, true) # enable spow process, default true
gain_strength = Float(Default(gain_strength,0.5)) # gain strength for manual mode
Assert(0.0 <= gain_strength <= 1.0,RT_String("%s0.0 <= gain_strength <= 1.0(%f)",myName,gain_strength))
cont_strength = Float(Default(cont_strength,0.5)) # cont strength for manual mode
Assert(0.0 <= cont_strength <= 1.0,RT_String("%s0.0 <= cont_strength <= 1.0(%f)",myName,cont_strength))
g_c_bias_adapt = Float(Default(g_c_bias_adapt,0.5)) # gain and cont bias adapt for manual mode
Assert(0.0 <= g_c_bias_adapt <= 1.0,RT_String("%s0.0 <= g_c_bias_adapt <= 1.0(%f)",myName,g_c_bias_adapt))
bias_strength = Float(Default(bias_strength,0.5)) # manual bias strength
Assert(0.0 <= bias_strength <= 1.0,RT_String("%s0.0 <= bias_strength <= 1.0(%f)",myName,bias_strength))
rpow_strength = Float(Default(rpow_strength,0.5)) # manual rpow strength
Assert(0.0 <= rpow_strength <= 1.0,RT_String("%s0.0 <= rpow_strength <= 1.0(%f)",myName,rpow_strength))
spow_strength = Float(Default(spow_strength,0.5)) # manual spow strength
Assert(-1.0 <= spow_strength <= 1.0,RT_String("%s-1.0 <= spow_strength <= 1.0(%f)",myName,spow_strength))
spmid_strength = Default(spmid_strength, 1.0)
Assert(0.0 <= spmid_strength <= 2.0,RT_String("%s0.0 <= spmid_strength <= 2.0(%f)",myName,spmid_strength))
pord = Default(pord, false) # first rpow or spow process

#---------- Specify the source rectangle under scrutiny, x,y,w,h are now type Int

x = int( Width * x)
y = int( Height * y)
w = int(-Width * w)
h = int(-Height * h)

#--------- RGB color space process

RGB32_clip = (!isRGB32(clip)) ? ConvertToRGB32(clip, matrix=matrix) : clip

CWID=88 CHIT=24 #69 21 # display Width and Height in Subtitle characters
MinWid=CWID*10 MinHit=CHIT*20 # RT_Subtitle required width height in pixels (fixed font size is 10x20)
TooSmall=(Width<MinWid || Height<MinHit)

RedStr = (TooSmall) ? "Red values :\n" : "\a2Red values\a- :\n"
GrnStr = (TooSmall) ? "Green values :\n" : "\a4Green values\a- :\n"
BluStr = (TooSmall) ? "Blue values :\n" : "\a1Blue values\a- :\n"

# use same string at each frame.
Fmt=
\ "gain strength : %3.3f cont strength : %3.3f g & c bias adapt : %3.3f \n" +
\ "bias strength : %3.3f rpow strength : %3.3f spow strength : %3.3f \n" +
\ "Channels averages average : %3.3f \n" +
\ RedStr +
\ " Departure : Average=%7.3f : Min/max=%-3d : Min=%-3d : Max=%-3d \n" +
\ " R_bias=%7.3f : R_gain =%7.3f : R_cont =%7.3f \n" +
\ " R_rpow=%7.3f : R_spow =%7.3f : R_spmid =%7.3f \n" +
\ " Finish : Average=%7.3f : Min/max=%-3d : Min=%-3d : Max=%-3d\n\n" +
\ GrnStr +
\ " Departure : Average=%7.3f : Min/max=%-3d : Min=%-3d : Max=%-3d \n" +
\ " G_bias=%7.3f : G_gain =%7.3f : G_cont =%7.3f \n" +
\ " G_rpow=%7.3f : G_spow =%7.3f : G_spmid =%7.3f \n" +
\ " Finish : Average=%7.3f : Min/max=%-3d : Min=%-3d : Max=%-3d\n\n" +
\ BluStr +
\ " Departure : Average=%7.3f : Min/max=%-3d : Min=%-3d : Max=%-3d \n" +
\ " B_bias=%7.3f : B_gain =%7.3f : B_cont =%7.3f \n" +
\ " B_rpow=%7.3f : B_spow =%7.3f : B_spmid =%7.3f \n" +
\ " Finish : Average=%7.3f : Min/max=%-3d : Min=%-3d : Max=%-3d\n\n" +
\ "Channels averages average : %7.3f"

GS="""
# Nested Low level Function, Called per frame via GScriptClip(), RGB32 ONLY
Function RGBAdapt_awb_process_Lo(clip clp,String Fmt,bool show_info,int x,int y,int w,int h, float threshold,
\ bool auto, bool gain, bool cont, bool g_c_bias, bool bias, bool rpow, bool spow,
\ float gain_strength, float cont_strength, float g_c_bias_adapt,
\ float bias_strength, float rpow_strength, float spow_strength, float spmid_strength, bool pord,
\ Bool TooSmall,Int CWid,Int CHit) {

clp # Last = Input RGB32 clp clip.

# n = current_frame # n is current_frame, can use in RT_Stats to access frames relative to current. Not currently used.

#---------- Channels datas extraction

Last.RT_RgbChanStats(x=x,y=y,w=w,h=h,threshold=threshold,p = 16,chan=-1,flgs= 1+2+4+16, Prefix="RCS_")

blank_clip = RCS_MinMaxDiff_0 + RCS_MinMaxDiff_1 + RCS_MinMaxDiff_2 # one color clip detection to disable auto white balance

# Leave RCS_ values as original (avoid repeat function call in Show_info), new variables without RCS_ prefix, avoid div by zero.
MinMaxDiff_0 = Max(RCS_MinMaxDiff_0, 0.00001)
MinMaxDiff_1 = Max(RCS_MinMaxDiff_1, 0.00001)
MinMaxDiff_2 = Max(RCS_MinMaxDiff_2, 0.00001)

ref = (RCS_Ave_0 + RCS_Ave_1 + RCS_Ave_2)/3.0
#~ maxmin = (RCS_Max_0 + RCS_Min_0 + RCS_Max_1 + RCS_Min_1 + RCS_Max_2 + RCS_Min_2)/3.0
#~ min = (RCS_Min_0 + RCS_Min_1 + RCS_Min_2)/3.0

#---------- Factors calculation for automatic mode

if (auto) {
if (gain) {
gain_strength = float(Max(RCS_Min_0,RCS_Min_1,RCS_Min_2)) \
/ Max(RCS_Max_0 + RCS_Min_0,RCS_Max_1 + RCS_Min_1,RCS_Max_2 + RCS_Min_2)
} else {gain_strength = 0.0}
if (cont) { cont_strength = Max(RCS_Min_0,RCS_Min_1,RCS_Min_2) / Max(RCS_Ave_0, RCS_Ave_1, RCS_Ave_2) }
else { cont_strength = 0.0 }
if (g_c_bias) {
g_c_bias_adapt = Pow(float(Max(RCS_Min_0,RCS_Min_1,RCS_Min_2))\
/ Max(RCS_Max_0 + RCS_Min_0,RCS_Max_1 + RCS_Min_1,RCS_Max_2 + RCS_Min_2)\
+ Max(RCS_Min_0,RCS_Min_1,RCS_Min_2)\
/ Max(RCS_Ave_0, RCS_Ave_1, RCS_Ave_2), 2)\
* \
Pow(Max(RCS_Ave_0, RCS_Ave_1, RCS_Ave_2)\
/ Max(RCS_Max_0 + RCS_Min_0,RCS_Max_1 + RCS_Min_1,RCS_Max_2 + RCS_Min_2), 2)
} else { g_c_bias_adapt = 0.0 }
bias_strength = Min(RCS_Ave_0, RCS_Ave_1, RCS_Ave_2) / Max(RCS_Ave_0, RCS_Ave_1, RCS_Ave_2)
# increase bias process if no gamma process use and inverse
if (rpow) {
if (bias) { rpow_strength = 1.0 - bias_strength}
else { rpow_strength = 1.0 bias_strength = 0.0}
} else {
if (bias) { bias_strength = 1.0 rpow_strength = 0.0 }
else { bias_strength = 0.0 rpow_strength = 0.0 }
}
if (spow) {spow_strength = Pow(Min(RCS_Ave_0, RCS_Ave_1, RCS_Ave_2) / Max(RCS_Ave_0, RCS_Ave_1, RCS_Ave_2),2)}
else {spow_strength = 0.0}
} else { } # factors are operator args

#---------- Gain process (only gain increase)

r_gain = 1.0 - (1.0 - 255.0/MinMaxDiff_0) * gain_strength
g_gain = 1.0 - (1.0 - 255.0/MinMaxDiff_1) * gain_strength
b_gain = 1.0 - (1.0 - 255.0/MinMaxDiff_2) * gain_strength

r_gain_bias = - RCS_Min_0 * r_gain * g_c_bias_adapt
g_gain_bias = - RCS_Min_1 * g_gain * g_c_bias_adapt
b_gain_bias = - RCS_Min_2 * b_gain * g_c_bias_adapt

#------ Contrast process (only contrast increase)

r_cont = 1.0 - (1.0 - 255.0/MinMaxDiff_0) * cont_strength
g_cont = 1.0 - (1.0 - 255.0/MinMaxDiff_1) * cont_strength
b_cont = 1.0 - (1.0 - 255.0/MinMaxDiff_2) * cont_strength

#------ Contrast bias calculation to aviod bad offset

r_cont_max = RCS_Max_0 * r_gain + (r_cont - 1.0) * (RCS_Max_0 - 128.0)
g_cont_max = RCS_Max_1 * g_gain + (g_cont - 1.0) * (RCS_Max_1 - 128.0)
b_cont_max = RCS_Max_2 * b_gain + (b_cont - 1.0) * (RCS_Max_2 - 128.0)

r_cont_min = RCS_Min_0 * r_gain + (r_cont - 1.0) * (RCS_Min_0 - 128.0)
g_cont_min = RCS_Min_1 * g_gain + (g_cont - 1.0) * (RCS_Min_1 - 128.0)
b_cont_min = RCS_Min_2 * b_gain + (b_cont - 1.0) * (RCS_Min_2 - 128.0)

r_cont_bias = - (r_cont_max + r_cont_min) * g_c_bias_adapt
g_cont_bias = - (g_cont_max + g_cont_min) * g_c_bias_adapt
b_cont_bias = - (b_cont_max + b_cont_min) * g_c_bias_adapt

#----- Gain and contrast bias calculation to avoid luma decrease

gain_cont_ref = (RCS_Ave_0 * r_gain + r_gain_bias + (r_cont - 1.0) * (RCS_Ave_0 - 128.0) + r_cont_bias \
+ RCS_Ave_1 * g_gain + g_gain_bias + (g_cont - 1.0) * (RCS_Ave_1 - 128.0) + g_cont_bias \
+ RCS_Ave_2 * b_gain + b_gain_bias + (b_cont - 1.0) * (RCS_Ave_2 - 128.0) + b_cont_bias)/3.0

luma_corr = ref - gain_cont_ref

r_bias = r_gain_bias + r_cont_bias + luma_corr
g_bias = g_gain_bias + g_cont_bias + luma_corr
b_bias = b_gain_bias + b_cont_bias + luma_corr

#----bias and gamma args calculation in accordance with gray world theory

# In gray world theory, in YuV range, we increase or decrease average value to ref = 128.0, but in RGB range
# ref = average of channel average values is better.

# First : classic bias correction before gamma process

r_bias_offset = (ref - RCS_Ave_0) * bias_strength
g_bias_offset = (ref - RCS_Ave_1) * bias_strength
b_bias_offset = (ref - RCS_Ave_2) * bias_strength
r_bias = r_bias + r_bias_offset g_bias = g_bias + g_bias_offset b_bias = b_bias + b_bias_offset

# Second : gamma bias correction applied on the selected bias
# In gamma process, to incresae or decrease average value, we use gamma args. To find this gamma args, we
# solve this equation ref/255 = pow(average value/255, 1/gamma args)

r_rpow = log((RCS_Ave_0 + (ref - RCS_Ave_0) * (1.0 - rpow_strength))/255.0)/log(ref/255.0)
g_rpow = log((RCS_Ave_1 + (ref - RCS_Ave_1) * (1.0 - rpow_strength))/255.0)/log(ref/255.0)
b_rpow = log((RCS_Ave_2 + (ref - RCS_Ave_2) * (1.0 - rpow_strength))/255.0)/log(ref/255.0)

r_spow = 1.0/(log((RCS_Ave_0 + (ref - RCS_Ave_0) * (1.0 - spow_strength))/255.0)/log(ref/255.0))
g_spow = 1.0/(log((RCS_Ave_1 + (ref - RCS_Ave_1) * (1.0 - spow_strength))/255.0)/log(ref/255.0))
b_spow = 1.0/(log((RCS_Ave_2 + (ref - RCS_Ave_2) * (1.0 - spow_strength))/255.0)/log(ref/255.0))

r_spmid = 1.0 - Pow((RCS_Ave_0/(RCS_Max_0 + RCS_Min_0)), 2) * spmid_strength
g_spmid = 1.0 - Pow((RCS_Ave_1/(RCS_Max_1 + RCS_Min_1)), 2) * spmid_strength
b_spmid = 1.0 - Pow((RCS_Ave_2/(RCS_Max_2 + RCS_Min_2)), 2) * spmid_strength

#--------- bias, gain, cont, rpow, spow and spmid in RGBadapt args range

r_bias = Min (512.0, Max (r_bias, -512.0)) g_bias = Min (512.0, Max (g_bias, -512.0)) b_bias = Min (512.0, Max (b_bias, -512.0))
r_gain = Min (8.0, Max (r_gain, -8.0)) g_gain = Min (8.0, Max (g_gain, -8.0)) b_gain = Min (8.0, Max (b_gain, -8.0))
r_cont = Min (8.0, Max (r_cont, -8.0)) g_cont = Min (8.0, Max (g_cont, -8.0)) b_cont = Min (8.0, Max (b_cont, -8.0))
r_rpow = Min (4.0, Max (r_rpow, 0.1)) g_rpow = Min (4.0, Max (g_rpow, 0.1)) b_rpow = Min (4.0, Max (b_rpow, 0.1))
r_spow = Min (4.0, Max (r_spow, 0.1)) g_spow = Min (4.0, Max (g_spow, 0.1)) b_spow = Min (4.0, Max (b_spow, 0.1))
r_spmid = Min (0.99, Max (r_spmid, 0.1)) g_spmid = Min (0.99, Max (g_spmid, 0.1)) b_spmid = Min (0.99, Max (b_spmid, 0.1))

#------------ AWB output

StainlessS
29th December 2018, 23:57
Post 2 of 2
RGBAdapt_Awb_Process.avs part 2 (copy/paste)


(blank_clip==0)
\ ? clp
\ : clp.RGBAdapt(R_bias=r_bias,R_Gain=r_gain,R_Cont=r_cont,R_rpow=r_rpow, R_spow = r_spow, R_spmid = r_spmid, R_pord = pord,
\ G_bias=g_bias,G_Gain=g_gain,G_Cont=g_cont,G_rpow=g_rpow, G_spow = g_spow, G_spmid = g_spmid, G_pord = pord,
\ B_bias=b_bias,B_Gain=b_gain,B_Cont=b_cont,B_rpow=b_rpow, B_spow = b_spow, B_spmid = b_spmid, B_pord = pord)

if(show_info) {
#--------- final RGB values extraction for display
# use different 'FIN_' Prefix so as not to destroy original variables
Last.RT_RgbChanStats(x = x, y = y, w = w, h = h, threshold = threshold, p =16,chan = -1, flgs = 1+2+4+16,Prefix="FIN_")
# calculation of rpow strength data, this data is only for display
if (!auto) {rpow_strength = rpow_strength}
else { if (rpow) {rpow_strength = 1.0 - bias_strength} else {rpow_strength = 0.0}}
S=RT_String(Fmt,
\ gain_strength,cont_strength,g_c_bias_adapt,bias_strength, rpow_strength,spow_strength,ref,
\
\ RCS_Ave_0, RCS_MinMaxDiff_0, RCS_Min_0, RCS_Max_0,
\ r_bias, r_gain, r_cont,
\ r_rpow, r_spow, r_spmid,
\ FIN_Ave_0, FIN_MinMaxDiff_0, FIN_Min_0, FIN_Max_0,
\
\ RCS_Ave_1, RCS_MinMaxDiff_1, RCS_Min_1, RCS_Max_1,
\ g_bias, g_gain,g_cont,
\ g_rpow,g_spow, g_spmid,
\ FIN_Ave_1, FIN_MinMaxDiff_1, FIN_Min_1, FIN_Max_1,
\
\ RCS_Ave_2, RCS_MinMaxDiff_2, RCS_Min_2, RCS_Max_2,
\ b_bias,b_gain,b_cont,
\ b_rpow,b_spow, b_spmid,
\ FIN_Ave_2, FIN_MinMaxDiff_2, FIN_Min_2, FIN_Max_2,
\
\ (FIN_Ave_0 + FIN_Ave_1 + FIN_Ave_2 )/3,Esc=(TooSmall)?0:1)
(TooSmall)
\ ? Last.Subtitle(S,Font="Courier New",lsp=0,text_color=$FFFF00,halo_color=$0,size=height/float(CHIT),
\ Font_width=width/FloaT(CWID))
\ : Last.RT_Subtitle("%s",S)
} # End ShowInfo
Return Last
} # End, RGBAdapt_awb_process_Lo()

# GScriptClip, Calling Low level Function RGBAdapt_awb_process_Lo() at each frame.
# Named ARGS variables at current script level, are imported into GScriptClip script, and passed as args to RGBAdapt_awb_process_Lo().
ARGS="Fmt,show_info,x,y,w,h,threshold," +
\ " auto, gain, cont, g_c_bias, bias, rpow, spow, gain_strength, cont_strength, g_c_bias_adapt, " +
\ " bias_strength, rpow_strength, spow_strength, spmid_strength, pord," +
\ " TooSmall,CWid,CHit"

RGB32_clip.GScriptClip("RGBAdapt_awb_process_Lo(last,"+ARGS+")", local=true, args=ARGS)
""" # End GS
HasGScript ? GScript(GS) : Eval(GS,"GS_EVAL") # Use GSCript if installed (loaded plugs override builtin)
# Do border outside of Scriptclip.
if(show_scrutinized) {
Level = 100 # 0 (Off) -> 257 (Full)
MarkColor = $00FF00
#-------- display scrutinized area
scrutinized_green = Last.BlankClip(width = Width-x+w, height = height-y+h, color=MarkColor)
scrutinized_mask = scrutinized_green.Blankclip(color=$0).LetterBox(2,2,2,2,$FFFFFF)
Layer(last,scrutinized_green.Mask(scrutinized_mask),x=x,y=y,level=Level)
} # End show_scrutinized

Return (clip.isYV12) ? ConvertToYV12(last, matrix=matrix) : last # Return original colorspace, YV12 or RGB32
}




Function AWB_Func(clip clip, string "matrix",bool "show_scrutinized", bool "show_info", float "x", float "y", float "w", float "h",
\ float "threshold", bool "auto", bool "gain", bool "cont", bool "g_c_bias", bool "bias", bool "rpow", bool "spow",
\ float "gain_strength", float "cont_strength", float "g_c_bias_adapt",
\ float "bias_strength" ,
\ float "rpow_strength", float "spow_strength", float "spmid_strength", bool "pord", bool "comparison", bool "influency") {
# Clip MuST be YV12 or RGB32. Always returns SAME colorspace as input.
clip
IsAvsPlus=(FindStr(UCase(versionString),"AVISYNTH+")!=0) HasGScript=RT_FunctionExist("GScript")
Assert(IsAvsPlus || HasGScript,"AWB_Func: Must have either Avs+ or Gscript")
output=clip.RGBAdapt_Awb_Process(matrix=matrix,show_scrutinized=show_scrutinized,show_info=show_info,x=x,y=y,w=w,h=h,
\ threshold=threshold, auto = auto, gain = gain, cont = cont, g_c_bias = g_c_bias,
\ bias = bias, rpow = rpow, spow = spow,
\ gain_strength = gain_strength, cont_strength = cont_strength, g_c_bias_adapt = g_c_bias_adapt,
\ bias_strength = bias_strength,
\ rpow_strength = rpow_strength, spow_strength = spow_strength, spmid_strength = spmid_strength, pord = pord)
GS="""
if (!Default(comparison,false) && !Default(influency,false)) {
output
} else if (Default(comparison,false) && !Default(influency,false)) {
only_bias = Clip.RGBAdapt_awb_process(matrix=matrix,show_scrutinized=show_scrutinized,show_info=show_info, x=x,y=y,w=w,h=h,
\ threshold=threshold,gain = false, cont = false, g_c_bias = false, bias = true, rpow = false, spow = false)
full_auto = Clip.RGBAdapt_awb_process(matrix=matrix,show_scrutinized=show_scrutinized,show_info=show_info, x=x,y=y,w=w,h=h,
\ threshold=threshold)
STK1 = StackHorizontal(
\ clip.AddBorders(0,20,0,0,color=$0).Subtitle("Original"),
\ only_bias.AddBorders(0,20,0,0,color=$0).Subtitle("Only bias correction. As a reminder, like classical ColorYuV AWB"))
STK2 = StackHorizontal(
\ full_auto.AddBorders(0,20,0,0,color=$0).Subtitle("Full auto with spmid = 1.0 and pord = false"),
\ output.AddBorders(0,20,0,0,color=$0).Subtitle("Selected output"))
StackVertical(STK1,STK2)
} else {
full_auto_0_5 = Clip.RGBAdapt_awb_process(matrix=matrix,show_scrutinized=show_scrutinized,show_info=false, x=x,y=y,w=w,h=h,
\ threshold=threshold, spmid_strength = 0.5)
full_auto_1_5 = Clip.RGBAdapt_awb_process(matrix=matrix,show_scrutinized=show_scrutinized,show_info=false, x=x,y=y,w=w,h=h,
\ threshold=threshold, spmid_strength = 1.5)
STK11 = StackHorizontal(
\ clip.AddBorders(0,20,0,0,color=$0).Subtitle("Original"),
\ full_auto_0_5.AddBorders(0,20,0,0,color=$0).Subtitle("Full auto with spmid = 0.5"))
STK22 = StackHorizontal(
\ full_auto_1_5.AddBorders(0,20,0,0,color=$0).Subtitle("Full auto with spmid = 1.5"),
\ output.AddBorders(0,20,0,0,color=$0).Subtitle("Selected output with spmid = " + LeftStr(String(spmid_strength),3)))
StackVertical(STK11,STK22)
} # End, if
""" # End GS
HasGScript ? GScript(GS) : Eval(GS,"GS_EVAL") # Use GSCript if installed (loaded plugs override builtin)
Return Last # Return Original ColorSpace
}


Client

#import ("RGBAdapt_Awb_Process.avs")

Avisource(".\Parade.avi")
######
### RGBAdapt_Awb_Process.avs, RGB32 + YV12 ONLY.
######

/*
AVISource("C:\.............\your video.avi")
LoadPlugin("C:\............\GRunT.dll")
LoadPlugin("C:\............\GScript.dll")
LoadPlugin("C:\............\RGBAdapt.dll")
LoadPlugin("C:\............\RT_Stats26.dll")
*/

# display tunings
comparison = true
influency = false
show_scrutinized = false
show_info = false

# color space matrix tuning and specify the source rectangle under scrutiny
matrix = "Rec601"
x = 0.1
Y = 0.1
w = 0.1
h = 0.1

#extreme pixels percentage to be ignored when datas extraction
threshold = 0.1

# automatic white balance preset tunings
auto = true
# auto mode combination choice
gain = true
cont = true
g_c_bias = true
bias = true
rpow = true
spow = true
# manual combination and tune">]
gain_strength = 0.5
cont_strength = 0.5
g_c_bias_adapt = 0.5
bias_strength = 0.5
rpow_strength = 0.5
spow_strength = 0.5
# for auto or manual mode spow process adjust
pord = false
spmid_strength = 1.0

# If you use AvsPmod user sliders you can delete comment for following lines

#~
#~ comparison = Select(0, false , true)
#~ influency = Select(0, false , true)
#~ show_scrutinized = Select(0, false , true)
#~ show_info = Select(0, false , true)

#~
#~ matrix = Select(0, "Rec601" , "Rec709")
#~
#~ x = 0.1
#~ y= 0.1
#~ w = 0.1
#~ h = 0.1
#~
#~ threshold = 0.1
#~
#~ auto = Select(0, false , true)
#~
#~ gain = Select(1, false , true)
#~ cont = Select(1, false , true)
#~ g_c_bias = Select(1, false , true)
#~ bias = Select(1, false , true)
#~ rpow = Select(1, false , true)
#~ spow = Select(1, false , true)
#~
#~ gain_strength = 0.5
#~ cont_strength = 0.5
#~ g_c_bias_adapt = 0.5
#~ bias_strength = 0.5
#~ rpow_strength = 0.5
#~ spow_strength = 0.5
#~
#~ pord = Select(0, false , true)
#~ spmid_strength = 1.0

#######
#######
#######


AWB_Func(matrix=matrix,show_scrutinized=show_scrutinized,show_info=show_info,x=x,y=y,w=w,h=h,threshold=threshold,
\ auto = auto, gain = gain, cont = cont, g_c_bias = g_c_bias, bias = bias, rpow = rpow, spow = spow,
\ gain_strength = gain_strength, cont_strength = cont_strength, g_c_bias_adapt = g_c_bias_adapt,
\ bias_strength = bias_strength,
\ rpow_strength = rpow_strength, spow_strength = spow_strength, spmid_strength = spmid_strength, pord = pord,
\ comparison = comparison, influency = influency)

Return Last



EDIT: x64 bit Avs+, (No GScript, dont exist for x64)
https://i.postimg.cc/jn2Hw7F5/RGBAdapt-Awb-Process-v-2018-dec.jpg (https://postimg.cc/jn2Hw7F5)

fenomeno83
13th January 2019, 12:11
Hi Bernardd.
Thanks for your work! Your script works very well!
In my opinion should be create a dll to a easier integration in external applications. Like hdragc or autolevels avisynth plugins.
Thanks!

Bernardd
18th January 2019, 11:39
Hello,

First, this new version is in accordance with StainlessS's nice and smart redaction to have compatibility with
Avisynth x32 and Avisynth+ x64 and the suitable plugins.

Second, this new version is like the previous but with a possible new manual refine action in finish.

This script has one target : a better automatic white balance than ColorYUV(autowhite=true).

Thus the script have one display args to show the assesment :

- comparison , default = false, to compare ColorYUV(autowhite=true) output with three other outputs :
------- Top, from left to right, original input, like AutoWhite ColorYUV process.
------- Bottom, from left to right, automatic mode with whole process, tuned script output.

The script automatic mode is not full optimized, often the spmid strength need to be tuned,
Thus the script have one second display args to verify spmid strength influency :

- influency , default = false, to compare different process selection outputs :
------- Top, from left to right, original input, automatic mode with whole process, but with spmid strength = 0.5.
------- Bottom, from left to right, automatic mode with whole process, but with spmid strength = 1.5, tuned script output.

In finish, you can refine the output look. Thus you can applied offset to two color channels without change the third. It is
like color temperature when you increase red, decrease blue and non change green. But here, you can choice the invariant color
channel. This refine is manual, thus the script have one third display args to verify offset influency :

- show_offset , default = false, to compare different manual offset applied to two color channels without change the third.
------- Top, from left to right, invariant red channel with offset applied on the other channels, invariant green channel with
offset applied on the other channels.
------- Bottom, from left to right, invariant blue channel with offset applied on the other channels, tuned script output.
- offset_2, default = 5, to increase or decrease the offset in comparison display

The script have two other display args :

- show_scrutinized, default = false, to display the scrutinized area by RT_Stat plugin for data extraction.
- show_info, default = false, to see extracted datas and process args tunes.

The script have the following args to tune the white balance process :

- matrix, defaut = "Rec601", to give the video color space matrix
- x, default = 0.1, to specify the source rectangle under scrutiny by RT_Stat plugin for data extraction
- Y, default = 0.1, see RT_STAT doc
- w, default = 0.1
- h, default = 0.1

- threshold, default = 0.1, to specify extreme pixels percentage to be ignored when datas extraction (see RT_STAT doc)

- auto, default = true, in this case process are used in automatic (automatic mode), if false process are used in manual,

In automatic mode, whith these args, you can choice auto process combination
- gain, default = true, gain process enable
- cont, default = true, cont process enable
- g_c_bias, default = true, gain and contrast bias process enable
- bias, default = true, bias process enable
- rpow, default = true, rpow process enable
- spow, default = true, spow process enable

In manual mode, whith these args, you can built the process combination and tune strength of each process
- gain_strength, default = 0.5, float from 0.0 to 1.0, to tune gain process strength.
If value = 0.0 no gain process use.
- cont_strength, default = 0.5, float from 0.0 to 1.0, to tune contrast process strength.
If value = 0.0 no contrast process use.
- g_c_bias_adapt, default = 0.5, float from 0.0 to 1.0, to adjust the automatic bias computed when gain and or contrast are applied.
If value = 0.0 computed gain and cont bias = 0.0.
- bias_strength, default = 0.5, float from 0.0 to 1.0, to tune bias process strength.
This bias is a computed bias in accordance with grey world theory for color balance. If value = 0.0 no bias process use.
- rpow_strength, default = 0.5, float from 0.0 to 1.0, to tune rpow process strength.
This computed rpow is the application of the grey world theory for color balance to gamma space. Explanation in script comment.
If value = 0.0 no rpow process use.
- spow_strength, default = 1.5, float from 0.0 to 2.0, to tune spow process strength. Like rpow proces but with S curve.
If value = 1.0 no spow process use.

In auto or manual mode, two spow process's specifics tunes, if spow process is enable
- pord, default = false, priority for rpow or spow process, see RGBAdapt doc.
- spmid_strength, default = 1.0, float from 0.0 to 1.0, you can adjust the automatic computed spmid strength to refine spow process

In auto or manual mode, you can refine color look with offset on only two channels and no change on the third.
- invariant_channel, default = "green", , to select one invariant color channel.
- offset, default = 0, to tune offset applied to the other color channels.

In this script, gain formula and grey world bias formula are classical. The other formulas are empirical, i have searched formulas
to mix maximal, minimal and average values of each RGB channel RGB to :
- do not use too much the autogain process and
- get best results with most videos clips plubished on this forum

The problem of this method is to found a good mix of datas to get always the good S curve correction. In fact, the Max, Min and
average values of RGB channels are not enough to describe a color channel histogram with two or more pic values. Thus i have
found one formula for gentle videos. For the other videos, a manual adjust of Spmid correction is often necessary.
Look the spmid strength influency display.

Each video is specific, each scene is specific, the script is not a universal solution. Some time, before use one following correction
like ColorYUV(off_u = - 5, off_v = 5) or adjust with tweak, try to apply offset. The following picture show the offset inflency on
the automatic white balance on "Lena".
https://www.dropbox.com/s/svqvsd3zus8mmyt/lena%20offset%20comparison.jpg?dl=0

Comment
In this version, the function lines are in script beginning, the client lines are at end
If you use AvsPmod, you can uncomment lines 473 to 511 to have UserSliders facility.

The script here in attachment
and here https://www.dropbox.com/s/ct8v68o09tjj3u4/RGBAdapt%20Awb%20Process%20for%20x32%20or%20x64%20v%20jan%202019.avs?dl=0

@Fenomeno83
Thanks for your comments, on the previous version.
Sorry, i have not the knowledges to transform this script in dll.

Bernard

Zetti
18th January 2019, 16:26
Can the default settings be enabled with RGBAdapt_Awb_Process()

Or should it be more specific??

Bernardd
18th January 2019, 19:46
I do not understand exactly your problem. But i can add this information.

The script have two functions :
AWB_Func(), which call the secund function and add only three comparison displays opportunity
RGBAdapt_AWB_Process(), which is the script for AWB with technical settings like "scrutinized aera", "color matrix", and process combination to produce AWB (gain and contrast, and bias or whole by sample).

In fact, one script with one line like AWB_Func(), give the same output that one script with one line RGBAdapt_AWB_Process(). This output is the AWB with whole process and their default settings.

Zetti
18th January 2019, 22:37
I have no problems until now.

I have only very basic Avisynth knowledge.

And i want to learn how the script works, so one step at a time.

Now i getting this error:
https://i.imgsafe.org/24/2463c32ad6.png

That is my script:
LoadPlugin("C:\MeGUI\tools\dgindexnv\DGDecodeNV.dll")
Import("C:\Program Files (x86)\AviSynth+\plugins+\RGBAdapt Awb Process for x32 or x64 v jan 2019.avs")
DGSource("C:\Temp\Anth.dgi",fieldop=0, deinterlace=1)
RGBAdapt_AWB_Process()

I using Avisynth+ x86

StainlessS
18th January 2019, 22:57
Remove this part from the script [EDIT the RGBAdapt Awb Process for x32 or x64 v jan 2019.avs script]
or it will not run from Plugins directory properley [EDIT: Will also be problem for Import too] (maybe put in your client script)


######
### RGBAdapt Awb Process.avs, RGB32 + YV12 ONLY.
######

/*
AVISource("C:\.............\your video.avi")
LoadPlugin("C:\............\GRunT.dll")
LoadPlugin("C:\............\GScript.dll") # no need for Avisynth+ x64
LoadPlugin("C:\............\RGBAdapt.dll")
LoadPlugin("C:\............\RT_Stats26.dll")
*/

# display tunings
comparison = true
influency = false
show_offset = false
offset_2 = 5
show_scrutinized = false
show_info = false

# color space matrix tuning and specify the source rectangle under scrutiny
matrix = "Rec601"
x = 0.1
Y = 0.1
w = 0.1
h = 0.1

#extreme pixels percentage to be ignored when datas extraction
threshold = 0.1

# automatic white balance preset tunings
auto = true
# auto mode combination choice
gain = true
cont = true
g_c_bias = true
bias = true
rpow = true
spow = true
# manual combination and tune">]
gain_strength = 0.5
cont_strength = 0.5
g_c_bias_adapt = 0.5
bias_strength = 0.5
rpow_strength = 0.5
spow_strength = 0.5
# for auto or manual mode spow process adjust
pord = false
spmid_strength = 1.0
#for auto or manual mode refine with offset on only two channels
invariant_channel = "green"
offset = 0

# If you use AvsPmod user sliders you can delete comment for following lines

#~
#~ comparison = Select(0, false , true)
#~ influency = Select(0, false , true)
#~ show_offset = Select(0, false , true)
#~ offset_2 = 5
#~ show_scrutinized = Select(0, false , true)
#~ show_info = Select(0, false , true)

#~
#~ matrix = Select(0, "Rec601" , "Rec709")
#~
#~ x = 0.1
#~ y= 0.1
#~ w = 0.1
#~ h = 0.1
#~
#~ threshold = 0.1
#~
#~ auto = Select(1, false , true)
#~
#~ gain = Select(1, false , true)
#~ cont = Select(1, false , true)
#~ g_c_bias = Select(1, false , true)
#~ bias = Select(1, false , true)
#~ rpow = Select(1, false , true)
#~ spow = Select(1, false , true)
#~
#~ gain_strength = 0.5
#~ cont_strength = 0.5
#~ g_c_bias_adapt = 0.5
#~ bias_strength = 0.5
#~ rpow_strength = 0.5
#~ spow_strength = 0.5
#~
#~ pord = Select(0, false , true)
#~ spmid_strength = 1.0
#~
#~ invariant_channel = Select(1, "red" , "green", "blue")
#~ offset = 0


#######
#######
#######


AWB_Func(matrix=matrix,show_scrutinized=show_scrutinized,show_info=show_info,x=x,y=y,w=w,h=h,threshold=threshold,
\ auto = auto, gain = gain, cont = cont, g_c_bias = g_c_bias, bias = bias, rpow = rpow, spow = spow,
\ gain_strength = gain_strength, cont_strength = cont_strength, g_c_bias_adapt = g_c_bias_adapt,
\ bias_strength = bias_strength,
\ rpow_strength = rpow_strength, spow_strength = spow_strength, spmid_strength = spmid_strength, pord = pord,
\ invariant_channel = invariant_channel, offset = offset,
\ comparison = comparison, influency = influency, show_offset = show_offset, offset_2 = offset_2)

Return Last

The above is client script.

(for myself,) I would also remove the AvsPMod rubbish at the end (the commented out stuff).

I separated the functions and client script in my modified version for this very reason.

EDIT: Alternatively, you could comment out ALL of the client code in the original script (that way you have a copy of original client script).

EDIT: Any AvsPMod stuff should be in client script only, never in Function script, if it is to work correctly from Plugins or Import().

EDIT: If you rename the function script in Plugins, to an *.avsi it will autoload and you will not have to import
(cant remember off hand if avs+ also autoloads avs scripts in plugins).

EDIT:
Avisynth open Failure.
Script error: Invalid arguments to function ;AWB_Func'
Above because the client part of the AWB script that you import, calls the function without any clip.

Bernardd
19th January 2019, 09:49
In accordance with StainlessS's recommendation, the script in two parts, function and client
here in attachment and here :
https://www.dropbox.com/s/dvo2c8zvwufh33v/RGBAdapt%20Awb%20Process%20for%20x32%20or%20x64%20v%20jan%202019%20function.avs?dl=0
https://www.dropbox.com/s/4xdn0yd3wpj0qxt/RGBAdapt%20Awb%20Process%20for%20x32%20or%20x64%20v%20jan%202019%20client.avs?dl=0

Zetti
19th January 2019, 14:38
Thanks you both StainlessS and Bernardd

Now have i something i can try.

fenomeno83
19th January 2019, 15:20
@Fenomeno83
Thanks for your comments, on the previous version.
Sorry, i have not the knowledges to transform this script in dll.

Bernard

Maybe StainlessS could do it ;)

Bernardd
19th January 2019, 17:50
I can not answer for StainlessS, but i think we must not go to fast.

First, in automatic mode this script is based on process strength factors, which are the same for each color channel inside one process (gain, cont, bias or gamma).
I do not know yet, if tuned strength factor for each color channel inside one process should be better.

Second, the automatic mode give a AWB output. If this result need refine, the solution is one like my last add (offset function) or is to display one RGBAdapt cmd line with args of AWB process and with enable user adjust for each args. Now, i do not know.

Danette
23rd January 2019, 20:52
How long does it generally take for the forum admins to approve attachments?

StainlessS
23rd January 2019, 21:57
How long does it generally take for the forum admins to approve attachments?

I heard tell that whilst waiting, one guy died and ended up desiccated.

Danette
24th January 2019, 02:11
I heard tell that whilst waiting, one guy died and ended up desiccated.

Bernardd: please remain hydrated!!

Bernardd
25th January 2019, 11:50
Hello,

First, this new version always is in accordance with Stainlesss nice and smart redaction to have compatibility with Avisynth x32 and Avisynth+ x64 and the suitable plugins.

Secondly, this version have the same engine than the previous (except for spmid calculation, which is more simple), but operator dialogue is changed. You have now a RGBAdapt function with a AWB mode, which can be refined with original RGBAdapt args.

Third the script do a half automatic white balance, in finish you must control and often adjust pord and spmid.

This script has one target : a better automatic white balance than ColorYUV(autowhite=true).

Thus the script have one display args to show the assesment :

- comparison , default = false, to compare ColorYUV(autowhite=true) output with three other outputs :
------- Top, from left to right, original input, like AutoWhite ColorYUV process.
------- Bottom, from left to right, automatic mode with whole process, tuned script output.

The script automatic mode is not full optimized, often the channel spmid need to be tuned.
For this process, the datas like color channel average, max and min datas are not enougth to descrive the color channel curve, thus not enougth to choice inflexion point of S curve.
Thus the script have one secund display args to verify spmid influency :

- influency , default = false, to compare different process selection outputs :
------- Top, from left to right, original input, automatic mode with whole process, but with spmid = 0.25 for the three channels.
------- Bottom, from left to right, automatic mode with whole process, but with spmid = 0.75 for the three channel, tuned script output.
This display do not show the best solution for spmid, it give you by comparison a way to find the best tune.

The script have two other display args :

- show_scrutinized, default = false, to display the scrutinized area by RT_Stat plugin for data extraction.
- show_info, default = false, to see extracted datas and process args tunes.

The script have the following args to tune the white balance process :

- matrix, defaut = "Rec601", to give the video color space matrix
- x, default = 0.1, to specify the source rectangle under scrutiny by RT_Stat plugin for data extraction
- Y, default = 0.1, see RT_STAT doc
- w, default = 0.1
- h, default = 0.1

- threshold, default = 0.1, to specify extreme pixels percentage to be ignored when datas extraction (see RT_STAT doc)

With this following args, you can choice automatic process combination :
- gain, default = true, gain process enable
- cont, default = true, cont process enable
- bias, default = true, bias process enable
- rpow, default = true, rpow process enable
- spow, default = true, spow process enable

Finally, the script have also the RGBAdapt's args, for bias, gain, cont, rpow, spow, spmid and pord. See RGBAdapt documentation.

Note :
If you have only selected bias, you get like ColorYUV(autowhite = true) ouput. If you tune one RGBAdapt channel bias arg, you change this white balance.

In fact, the script produce a automatic white balance, that you can refine by tunning RGBAdapt args. If all automatic process are desabled, you have only manual RGBAdapt function.

Fast tips :
Run script with default args,
Look influency display to verify if spmid is good, if no, tune channel spmid. After return comparison diplay or output display.
If necessary, now, you can improve the white balance by tunning RGBAdapt args, like channel gain (little change like 0.1 or 0.2) or like bias and rpow together. If you decrease a channel bias you decrease channel inflency in light aera, if you increase the same channel rpow, you increase channel inflency in dark aera.

To refine, you can try to tune all RGBAdapt args, but do not forget, if automatic process is enable, your changes on suitable RGBAdapt args must be little.
Thus the AvsPmod user slider ranges for RGBAdapt args are more little than in the RGBAdapt documentation.

Comment :
The script have always two functions :
AWB_Func(), which call the second function and add only two comparison displays opportunity, in default mode this comparison display are desabled.
RGBAdapt_AWB_Process(), which is the script for AWB with technical settings like "scrutinized aera", "color matrix", and process combination to produce AWB (gain and contrast, and bias or whole).

Thus, one script with one line like AWB_Func(), give the same output that one script with one line RGBAdapt_AWB_Process(). This output is the AWB with whole process and their default settings.

The script release file content two avs files, one for the functions, the secund for the client.
The script need to load this plugins in accordance with avisynth version :
- GRunT author Gavino http://forum.doom9.org/showthread.php?t=139337 and the posts 35 and 39 for x64 versions by Yesmanitsbearman.
- GScript author Gavino http://forum.doom9.org/showthread.php?t=147846, x32 only, no need with Avisynth +
- RGBAdapt author Stainless http://forum.doom9.org/showthread.php?t=170642
- RT_Stats author Stainless https://forum.doom9.org/showthread.php?p=1584313#post1584313

If you use AvsPmod, you can uncomment lines 67 to 115 to have UserSliders facility.

The script here in attachment
and here https://www.dropbox.com/s/95q3uhvo5ijz67p/RGBAdapt%20Awb%20Process%20x32%20x64%20jan%202019.7z?dl=0

I think this version is a candidat release, i have no idea to improve it, to make it more automatic.

Bernard

PS : DropBox link for thirsty people

Danette
31st January 2019, 21:21
I agree with others: this is a noticeable improvement over the earlier versions - even using defaults. Flesh tones are better and colors and whites are warmer. Better than the likes of ColorYUV and, in many situations, WhiteBalance.

Congratulations, Bernard, on turning StainlessS good work into what appears to be a simple one-size-fits-all white balance capability.

Of course, a dll would eliminate all the lines needed in the script, but I can appreciate that such coding is more than you want to get involved in.

manono
1st February 2019, 07:29
How long does it generally take for the forum admins to approve attachments?
Although I visit this forum regularly, I hadn't read this thread as I work almost entirely with black and white material and it didn't interest me. But I had a look, saw your question, and approved all pending attachments. On behalf of us lazy mods, I apologize.

To answer your question, anywhere from immediately to never.

Danette
1st February 2019, 15:10
Although I visit this forum regularly, I hadn't read this thread as I work almost entirely with black and white material and it didn't interest me. But I had a look, saw your question, and approved all pending attachments. On behalf of us lazy mods, I apologize.

To answer your question, anywhere from immediately to never.

Thanks. I'll complain when they start paying you to do this.

StainlessS
1st February 2019, 21:06
A bit OT.
Report your own post, say "approve plz" and it'll get approved. I don't think the 200k thing is a real limit.

Unfortunately vBulletin in all of its wisdom notifies mods of reports but does NOT notify us of pending approvals, so the only option is to wade into threads on the off chance someone might have attached something. There's the mod panel, but it's... lousy, at best. I check on this thread twice a week, but it's so active I miss a lot. Now that we all work way more than full time, the rules page really needs a Rule #0: Report your own post for prompt service.

https://forum.doom9.org/showthread.php?p=1837290#post1837290

The REPORT icon is the little red triangle under your avatar [ideally on post containing the attachment, or add which post you refer to].

EDIT:
Thanks. I'll complain when they start paying you to do this.
I'll complain a lot more often, when they start paying me to do that.

Bernardd
16th February 2019, 16:55
Hi StainlessS

I think export the RGBAdapt args computed by my script in a text file and i would load this data in RGBAdapt_graffer. But i have not the knowledge to modify RGBAdapt_graffer for this use. Thus, please, i ask you, if you wish insert for me, datas import function in the graffer soft.

Bernard

StainlessS
16th February 2019, 22:41
What format would input take ?

Will probably take a least a couple of days for me to get time.