View Full Version : Clone of Gimp's Color Balance?
mikeytown2
10th July 2008, 00:27
Does AviSynth have anything like this?
http://img73.imageshack.us/img73/8854/colorbalanceyt2.png
Screenshot from Gimp 2.4.6
Gavino
10th July 2008, 00:53
How about some combination of RGBAdjust (http://avisynth.org/mediawiki/RGBAdjust) with AvsP's sliders?
mikeytown2
10th July 2008, 01:33
By it's self RGBAdjust can't do it.
At a minimum it would need 9 adjustments: shadows, midtones and highlights; all use 3 sliders. ChannelMixer is not the answer, gimp has this as well under colors -> components -> channel mixer. Color Balance is quite useful, I think thats why its at the top of the menu in gimp.
In order to replicate this you would split up the clip into shadows midtones and highlights; then you need to have an adjuster that goes from cyan to red, magenta to green, and yellow to blue; which happens to be the inverse of each, so it looks like it's playing with the hue for each channel in the shadows, midtones and highlights range.
Mug Funky
10th July 2008, 03:45
i'd love to see something similar to a "3 point colour corrector".
as in, 3 colour wheels (lift, gamma, gain) with colour directions that correspond to a vectorscope (ie red up top, slightly to the left, green down the bottom left, blue on the right and down a bit). you could accomplish in a single click-drag what would otherwise take 3 click-drags and several adjustments.
this'd be one for avs GUI :)
of course, then we'd need to split it up into shots and grade each one separately...
[edit]
the top half of this pic is what i had in mind:
http://images.digitalmedianet.com/2002/09_sep/features/cw_fcp_vs_xdv_shootout/fcp_ccsmall.jpg
of course, masktools' RGB_lut can do this quite well - you just need to get it into avsp sliders in a clever way.
rfmmars
10th July 2008, 04:25
By it's self RGBAdjust can't do it.
At a minimum it would need 9 adjustments: shadows, midtones and highlights; all use 3 sliders. ChannelMixer is not the answer, gimp has this as well under colors -> components -> channel mixer. Color Balance is quite useful, I think thats why its at the top of the menu in gimp.
In order to replicate this you would split up the clip into shadows midtones and highlights; then you need to have an adjuster that goes from cyan to red, magenta to green, and yellow to blue; which happens to be the inverse of each, so it looks like it's playing with the hue for each channel in the shadows, midtones and highlights range.
RGB-eq 2.1 has up to 17 slider per funtion not three, plus spreadsheet funtions for lum and color mix, indeed it will do it.
Richard
mikeytown2
10th July 2008, 07:51
Function BadColorBalance(clip c, float "R", float "G", float "B")
{
R = Default(R,0.0)
G = Default(G,0.0)
B = Default(B,0.0)
red = BlankClip(c,color=$FF0000)
green = BlankClip(c,color=$00FF00)
blue = BlankClip(c,color=$0000FF)
Black = BlankClip(c,color=$000000)
R1 = Overlay(Black,red,mask=c.ShowRed()).ConvertToYUY2().Tweak(hue=R)
G1 = Overlay(Black,green,mask=c.ShowGreen()).ConvertToYUY2().Tweak(hue=G)
B1 = Overlay(Black,blue,mask=c.ShowBlue()).ConvertToYUY2().Tweak(hue=B)
Overlay(c,R1,opacity=0.6)
Overlay(last,G1,opacity=0.35)
Overlay(last,B1,opacity=0.3)
Overlay(last,c,mode="luma").ConvertToYUY2().Tweak(0,2).ConvertToRGB()
}
BadColorBalance([<"Cyan-Red", -180.0, 180.0, 0.0>],[<"Magenta-Green", -180.0, 180.0, 0.0>],[<"Yellow-Blue", -180.0, 180.0, 0.0>])
Here's a 3 slider for avsp, look at the name; this is more of a yes it's possible then usable function.
I'll be looking into RGB_lut. EDIT did u mean mt_lut ?
Is there a link for RGB-eq?
tin3tin
10th July 2008, 08:16
http://members.chello.at/nagiller/vdub/filter.jpg
Gradation for Vdub (http://members.chello.at/nagiller/vdub/index.html).
It can also work in YUV colorspace(and many others).
mikeytown2
10th July 2008, 21:52
Take 2
BadColorBalance([<"LOW Cyan-Red", -45.0, 45.0, 0.0>],[<"LOW Magenta-Green", -45.0, 45.0, 0.0>],[<"LOW Yellow-Blue", -45.0, 45.0, 0.0>], \
[<"MID Cyan-Red", -45.0, 45.0, 0.0>],[<"MID Magenta-Green", -45.0, 45.0, 0.0>],[<"MID Yellow-Blue", -45.0, 45.0, 0.0>], \
[<"HI Cyan-Red", -45.0, 45.0, 0.0>],[<"HI Magenta-Green", -45.0, 45.0, 0.0>],[<"HI Yellow-Blue", -45.0, 45.0, 0.0>])
Function BadColorBalance(clip c, float "RL", float "GL", float "BL", float "RM", float "GM", float "BM", float "RH", float "GH", float "BH")
{
RL = Default(RL,0.0)
GL = Default(GL,0.0)
BL = Default(BL,0.0)
RM = Default(RM,0.0)
GM = Default(GM,0.0)
BM = Default(BM,0.0)
RH = Default(RH,0.0)
GH = Default(GH,0.0)
BH = Default(BH,0.0)
c=c.ConvertToRGB32()
red = BlankClip(c,color=$FF0000)
green = BlankClip(c,color=$00FF00)
blue = BlankClip(c,color=$0000FF)
Black = BlankClip(c,color=$000000)
White = BlankClip(c,color=$FFFFFF)
Low = 85
Mid = 170
RLow = Overlay(Black,red.ConvertToYUY2().Tweak(hue=RL),mask=c.ShowRed().Levels(0,1,Low,0,Low)).ResetMask()
GLow = Overlay(Black,green.ConvertToYUY2().Tweak(hue=GL),mask=c.ShowGreen().Levels(0,1,Low,0,Low)).ResetMask()
BLow = Overlay(Black,blue.ConvertToYUY2().Tweak(hue=BL),mask=c.ShowBlue().Levels(0,1,Low,0,Low)).ResetMask()
RMed = Overlay(Black,red,mask=c.ShowRed().Levels(Low,1,Mid,Low,Mid)).ResetMask().ColorKeyMask($550000,1)
RMed = Layer(White,RMed).ConvertToYUY2().Tweak(hue=RM).ConvertToRGB32().ColorKeyMask($CCCCCC,100)
GMed = Overlay(Black,green,mask=c.ShowGreen().Levels(Low,1,Mid,Low,Mid)).ResetMask().ColorKeyMask($005600,1)
GMed = Layer(White,GMed).ConvertToYUY2().Tweak(hue=GM).ConvertToRGB32().ColorKeyMask($CCCCCC,100)
BMed = Overlay(Black,blue,mask=c.ShowBlue().Levels(Low,1,Mid,Low,Mid)).ResetMask().ColorKeyMask($000054,1)
BMed = Layer(White,BMed).ConvertToYUY2().Tweak(hue=BM).ConvertToRGB32().ColorKeyMask($CCCCCC,100)
RHi = Overlay(Black,red,mask=c.ShowRed().Levels(Mid,1,255,Mid,255)).ResetMask().ColorKeyMask($A80000,1)
RHi = Layer(black,RHi).ConvertToYUY2().Tweak(hue=RH).ConvertToRGB32().ColorKeyMask($333333,100)
GHi = Overlay(Black,green,mask=c.ShowGreen().Levels(Mid,1,255,Mid,255)).ResetMask().ColorKeyMask($00AB00,1)
GHi = Layer(black,GHi).ConvertToYUY2().Tweak(hue=GH).ConvertToRGB32().ColorKeyMask($333333,100)
BHi = Overlay(Black,blue,mask=c.ShowBlue().Levels(Mid,1,255,Mid,255)).ResetMask().ColorKeyMask($0000A9,1)
BHi = Layer(black,BHi).ConvertToYUY2().Tweak(hue=BH).ConvertToRGB32().ColorKeyMask($333333,100)
R2 = Layer(RLow,RMed).Layer(RHi)
G2 = Layer(GLow,GMed).Layer(GHi)
B2 = Layer(BLow,BMed).Layer(BHi)
Layer(R2,G2,level=128).Layer(B2,level=85).ConvertToYUY2().Tweak(0,3)
Overlay(last,c,mode="chroma",opacity=0.25)
Overlay(last,c,mode="luma",opacity=1).ConvertToRGB32()
}
It's not perfect, but it kinda gets the job done for now. Not sure what job it is, but it does it! I might go take a peek at GIMP's CVS (http://www.gimp.org/source/howtos/stable-cvs-get.html) and go from there. For the AvsP sliders I caped them at 45, but it can go to 180.
sidewinder711
10th July 2008, 22:16
@mickeytown2
Here (http://fdump.narod.ru/) is the link for RGBeq. Keep up your good work... looks promising! :)
mikeytown2
20th August 2008, 23:19
Finally got around to downloading Gimp's source (ftp://ftp.gimp.org/pub/gimp/stable/). Looked around at online header files (http://www.goof.com/pcg/marc/pdb/gimp_color_balance.html). Found some interesting discussions (http://lists.xcf.berkeley.edu/lists/gimp-developer/2005-December/015065.html). Even found different code online (http://www.koders.com/c/fid7AD5221618D94E3FFCC339E3477E06C89F9DE320.aspx?s=mdef%3ainsert) of the function. All of this to say I got no idea where to go from here. I've never gotten my hands dirty with coding color functions before, so any help would be appreciated!
Gavino
21st August 2008, 00:49
Where to go maybe depends a bit on what is your ultimate goal. Is it to produce an Avisynth plugin, or to emulate the functionality in the script language?
One thing that isn't clear to me is what the parameters in the Gimp's dialog actually mean in terms of raw RGB values. The documentation doesn't really make this clear. Perhaps rooting around in the code you could shed some light on this, and come up with an outline specification. (Or maybe you've already reached that point, at least in your head.)
mikeytown2
21st August 2008, 18:26
Ultimate goal is a plugin. There are a bunch of loops and that would be a pain to script; it also appears to go pixel by pixel. Here is the code out of 2.4.6. It doesn't have the GUI code like the online one did.
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <glib-object.h>
#include "libgimpcolor/gimpcolor.h"
#include "libgimpmath/gimpmath.h"
#include "base-types.h"
#include "color-balance.h"
#include "pixel-region.h"
/* local function prototypes */
static void color_balance_transfer_init (void);
/* private variables */
static gboolean transfer_initialized = FALSE;
/* for lightening */
static gdouble highlights_add[256] = { 0 };
static gdouble midtones_add[256] = { 0 };
static gdouble shadows_add[256] = { 0 };
/* for darkening */
static gdouble highlights_sub[256] = { 0 };
static gdouble midtones_sub[256] = { 0 };
static gdouble shadows_sub[256] = { 0 };
/* public functions */
void
color_balance_init (ColorBalance *cb)
{
GimpTransferMode range;
g_return_if_fail (cb != NULL);
for (range = GIMP_SHADOWS; range <= GIMP_HIGHLIGHTS; range++)
color_balance_range_reset (cb, range);
cb->preserve_luminosity = TRUE;
}
void
color_balance_range_reset (ColorBalance *cb,
GimpTransferMode range)
{
g_return_if_fail (cb != NULL);
cb->cyan_red[range] = 0.0;
cb->magenta_green[range] = 0.0;
cb->yellow_blue[range] = 0.0;
}
void
color_balance_create_lookup_tables (ColorBalance *cb)
{
gdouble *cyan_red_transfer[3];
gdouble *magenta_green_transfer[3];
gdouble *yellow_blue_transfer[3];
gint i;
gint32 r_n, g_n, b_n;
g_return_if_fail (cb != NULL);
if (! transfer_initialized)
{
color_balance_transfer_init ();
transfer_initialized = TRUE;
}
/* Set the transfer arrays (for speed) */
cyan_red_transfer[GIMP_SHADOWS] =
(cb->cyan_red[GIMP_SHADOWS] > 0) ? shadows_add : shadows_sub;
cyan_red_transfer[GIMP_MIDTONES] =
(cb->cyan_red[GIMP_MIDTONES] > 0) ? midtones_add : midtones_sub;
cyan_red_transfer[GIMP_HIGHLIGHTS] =
(cb->cyan_red[GIMP_HIGHLIGHTS] > 0) ? highlights_add : highlights_sub;
magenta_green_transfer[GIMP_SHADOWS] =
(cb->magenta_green[GIMP_SHADOWS] > 0) ? shadows_add : shadows_sub;
magenta_green_transfer[GIMP_MIDTONES] =
(cb->magenta_green[GIMP_MIDTONES] > 0) ? midtones_add : midtones_sub;
magenta_green_transfer[GIMP_HIGHLIGHTS] =
(cb->magenta_green[GIMP_HIGHLIGHTS] > 0) ? highlights_add : highlights_sub;
yellow_blue_transfer[GIMP_SHADOWS] =
(cb->yellow_blue[GIMP_SHADOWS] > 0) ? shadows_add : shadows_sub;
yellow_blue_transfer[GIMP_MIDTONES] =
(cb->yellow_blue[GIMP_MIDTONES] > 0) ? midtones_add : midtones_sub;
yellow_blue_transfer[GIMP_HIGHLIGHTS] =
(cb->yellow_blue[GIMP_HIGHLIGHTS] > 0) ? highlights_add : highlights_sub;
for (i = 0; i < 256; i++)
{
r_n = i;
g_n = i;
b_n = i;
r_n += cb->cyan_red[GIMP_SHADOWS] * cyan_red_transfer[GIMP_SHADOWS][r_n];
r_n = CLAMP0255 (r_n);
r_n += cb->cyan_red[GIMP_MIDTONES] * cyan_red_transfer[GIMP_MIDTONES][r_n];
r_n = CLAMP0255 (r_n);
r_n += cb->cyan_red[GIMP_HIGHLIGHTS] * cyan_red_transfer[GIMP_HIGHLIGHTS][r_n];
r_n = CLAMP0255 (r_n);
g_n += cb->magenta_green[GIMP_SHADOWS] * magenta_green_transfer[GIMP_SHADOWS][g_n];
g_n = CLAMP0255 (g_n);
g_n += cb->magenta_green[GIMP_MIDTONES] * magenta_green_transfer[GIMP_MIDTONES][g_n];
g_n = CLAMP0255 (g_n);
g_n += cb->magenta_green[GIMP_HIGHLIGHTS] * magenta_green_transfer[GIMP_HIGHLIGHTS][g_n];
g_n = CLAMP0255 (g_n);
b_n += cb->yellow_blue[GIMP_SHADOWS] * yellow_blue_transfer[GIMP_SHADOWS][b_n];
b_n = CLAMP0255 (b_n);
b_n += cb->yellow_blue[GIMP_MIDTONES] * yellow_blue_transfer[GIMP_MIDTONES][b_n];
b_n = CLAMP0255 (b_n);
b_n += cb->yellow_blue[GIMP_HIGHLIGHTS] * yellow_blue_transfer[GIMP_HIGHLIGHTS][b_n];
b_n = CLAMP0255 (b_n);
cb->r_lookup[i] = r_n;
cb->g_lookup[i] = g_n;
cb->b_lookup[i] = b_n;
}
}
void
color_balance (ColorBalance *cb,
PixelRegion *srcPR,
PixelRegion *destPR)
{
const guchar *src, *s;
guchar *dest, *d;
gboolean alpha;
gint r, g, b;
gint r_n, g_n, b_n;
gint w, h;
h = srcPR->h;
src = srcPR->data;
dest = destPR->data;
alpha = (srcPR->bytes == 4) ? TRUE : FALSE;
while (h--)
{
w = srcPR->w;
s = src;
d = dest;
while (w--)
{
r = s[RED_PIX];
g = s[GREEN_PIX];
b = s[BLUE_PIX];
r_n = cb->r_lookup[r];
g_n = cb->g_lookup[g];
b_n = cb->b_lookup[b];
if (cb->preserve_luminosity)
{
gimp_rgb_to_hsl_int (&r_n, &g_n, &b_n);
b_n = gimp_rgb_to_l_int (r, g, b);
gimp_hsl_to_rgb_int (&r_n, &g_n, &b_n);
}
d[RED_PIX] = r_n;
d[GREEN_PIX] = g_n;
d[BLUE_PIX] = b_n;
if (alpha)
d[ALPHA_PIX] = s[ALPHA_PIX];
s += srcPR->bytes;
d += destPR->bytes;
}
src += srcPR->rowstride;
dest += destPR->rowstride;
}
}
/* private functions */
static void
color_balance_transfer_init (void)
{
gint i;
for (i = 0; i < 256; i++)
{
gdouble low = (1.075 - 1 / ((gdouble) i / 16.0 + 1));
gdouble mid = 0.667 * (1 - SQR (((gdouble) i - 127.0) / 127.0));
shadows_add[i] = low;
shadows_sub[255 - i] = low;
midtones_add[i] = mid;
midtones_sub[i] = mid;
highlights_add[255 - i] = low;
highlights_sub[i] = low;
}
}
Header File
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __COLOR_BALANCE_H__
#define __COLOR_BALANCE_H__
struct _ColorBalance
{
gboolean preserve_luminosity;
gdouble cyan_red[3];
gdouble magenta_green[3];
gdouble yellow_blue[3];
guchar r_lookup[256];
guchar g_lookup[256];
guchar b_lookup[256];
};
void color_balance_init (ColorBalance *cb);
void color_balance_range_reset (ColorBalance *cb,
GimpTransferMode range);
void color_balance_create_lookup_tables (ColorBalance *cb);
void color_balance (ColorBalance *cb,
PixelRegion *srcPR,
PixelRegion *destPR);
#endif /* __COLOR_BALANCE_H__ */
The flow of this is color_balance_create_lookup_tables() pre-calculates all 2304 values (3*3*256; SMH*RGB*levels), then for each pixel color_balance() looks up that adjusted RGB value. I'll worry about preserve_luminosity later. What it's pre-calculating is a mystery to me right now, other then it's multiplying the slider value (-100 to 100) by the value out of color_balance_transfer_init() low,mid for that i value.
So this is the black box of the code
gdouble low = (1.075 - 1 / ((gdouble) i / 16.0 + 1));
gdouble mid = 0.667 * (1 - SQR (((gdouble) i - 127.0) / 127.0));
EDIT1:
Going to look at cinepaint (http://www.cinepaint.org/) for a 16bit version of this
Found it online here
http://www.sfr-fresh.com/unix/misc/cinepaint-0.22-1.tar.gz:a/cinepaint-0.22-1/app/depth/color_balance.c
EDIT2:
Multi threading this shouldn't be that hard (last time I wrote MT code was 3 years ago...), have it split off in these 2 loops:
color_balance() --> while (h--)
color_balance_transfer_init --> for (i = 0; i < 256; i++)
Game plan is to get Gimp code working, then multi thread it, then get 16bit working.
Gavino
22nd August 2008, 00:49
Multi threading this shouldn't be that hard (last time I wrote MT code was 3 years ago...), have it split off in these 2 loops:
color_balance() --> while (h--)
color_balance_transfer_init --> for (i = 0; i < 256; i++)
In Avisynth plugin terms, color_balance() more or less corresponds to GetFrame(), whereas the init stuff (setting up lookup tables, etc) would be done in your constructor, so I don't think there is scope for multi-threading these.
A quick look at the code (although I haven't absorbed the details yet) suggests it should not be overly slow anyway.
IanB
22nd August 2008, 04:08
Here is a sample script for doing a 3x3 matrix correction of a RGB clip.... # RGB clip
# Red mixing ratios
Rr=1.0
Rg=0.0
Rb=0.0
# Green mixing ratios
Gr=0.0
Gg=1.0
Gb=0.0
# Blue mixing ratios
Br=0.0
Bg=0.0
Bb=1.0
Ri=ShowRed("YV12")
Gi=ShowGreen("YV12")
Bi=ShowBlue("YV12")
Z=BlankClip(Ri)
(Rg+Rb != 0) ? MergeLuma(Gi, Bi, Ratio(Rg, Rb)) : Z
MergeLuma(Ri, Ratio(Rg+Rb, Rr))
(Rr+Rg+Rb != 1) ? Tweak(Cont=Rr+Rg+Rb, coring=False) : Last
Ro=Last
(Gr+Gb != 0) ? MergeLuma(Ri, Bi, Ratio(Gr, Gb)) : Z
MergeLuma(Gi, Ratio(Gr+Gb, Gg))
(Gr+Gg+Gb != 1) ? Tweak(Cont=Gr+Gg+Gb, coring=False) : Last
Go=Last
(Br+Bg != 0) ? MergeLuma(Ri, Gi, Ratio(Br, Bg)) : Z
MergeLuma(Bi, Ratio(Br+Bg, Bb))
(Rr+Rg+Rb != 1) ? Tweak(Cont=Br+Bg+Bb, coring=False) : Last
Bo=Last
MergeRGB(Ro, Go, Bo)
Function Ratio(Float A, Float B) {
Return (A+B == 0) ? 0.5 : B/(A+B)
}It can easily be adapted to adjust any of the component channels in any way required. e.g. apply 1.2 gamma and 35 offset to the red component of the green mix....
Rg=Levels(0, 1.2, 220, 35, 255, Coring=False)
(Gr+Gb != 0) ? MergeLuma(Rg, Bi, Ratio(Gr, Gb)) : Z
...
Gavino
22nd August 2008, 11:42
@mikeytown2: another observation on your possible ways forward:
Ultimate goal is a plugin. There are a bunch of loops and that would be a pain to script; it also appears to go pixel by pixel.
The alternative to a plugin would not be to directly rewrite the code as a script - that would be both painful and misguided.
Instead, the idea would be to figure out what the code was doing at the image level (eg adding x% to the red level over a certain threshold, or whatever), and replicate that in terms of available Avisynth filters. That's what I meant by an outline specification.
IanB's script has shown that just about anything can be achieved - but first you have to know what you want the output to be in terms of the input.
Gavino
26th August 2008, 17:05
@mikeytown2
I've found time to put together a prototype plugin based on the Gimp source you posted. It's basically a straight transcription, amended to fit the Avisynth plugin interface.
I'm quite content for you to take this forward in any way you like. If you need any help, feel free to ask.
The interface is currently as follows:
ColorBalance(clip,
float "rs", float "gs", float "bs", # shadows
float "rm", float "gm", float "bm", # midtones
float "rh", float "gh", float "bh", # highlights
bool "keep_luma")
The float parameters correspond to the Gimp sliders for (red, green, blue)x(shadows, midtones, highlights), nominal range -100.0 to +100.0 (though this is not currently checked), defaults 0.0;
keep_luma corresponds to Gimp's 'preserve luminosity' - this functionality is not yet implemented, so the parameter should be set to false (the default).
I am calling it a prototype, but the basic color balancing is fully functional - only keep_luma is not implemented.
Here it is (source + working dll):
mikeytown2
27th August 2008, 06:55
@Gavino
You beat me to it! Got simple sample compiled in MS VC++ 2005 (http://avisynth.org/mediawiki/Filter_SDK/Compiling_instructions#How_to_compile_existant_.28old_MS_VC_6.0.29_plugin_with_MS_VC.2B.2B_2005) and was about to start porting the code.
I'm still waiting for your zip file to be approved, would you mind putting it up on a one-click file hosting site?
Gavino
27th August 2008, 08:58
OK - here's the link: http://rapidshare.com/files/140458312/ColorBalance.zip.html
IanB
27th August 2008, 09:26
@Gavino,
Hint: Do not put tests inside inner loops, put the test outside the loop and clone the code with a very simple inner loop....
for (w = 0; w < src_width; w+=nBytes) {
if (nBytes == 4) // RGB32
a = *(srcp + w+3);
r = *(srcp + w+2);
...
if (nBytes == 4) // RGB32
*(dstp + w+3) = a;
*(dstp + w + 2) = r_n;
...
}
...
if (nBytes == 4) { // RGB32
...
for (w = 0; w < src_width; w+=4) {
a = *(srcp + w+3);
r = *(srcp + w+2);
...
*(dstp + w+3) = a;
*(dstp + w+2) = r_n;
...
}
...
} else {
...
for (w = 0; w < src_width; w+=nBytes) {
r = *(srcp + w+2);
...
*(dstp + w + 2) = r_n;
...
}
...
}
...
Gavino
27th August 2008, 10:00
Do not put tests inside inner loops, put the test outside the loop and clone the code with a very simple inner loop.
Yes, I guess you're right from a performance (or even a 'control flow elegance') point of view, though in general I prefer not to repeat code as it makes it harder to change.
Here your change is worth doing, and there are clearly other optimisations possible (eg eliminate the repeated addition of w in the pointer arithmetic).
mikeytown2
27th August 2008, 11:13
Now I remember why I didn't like non scripting languages... constructors!
I think Gimp's Preserve Luminosity is broken, or at least it's suffering from rounding errors. did a quick compare with this image from wikipedia (http://en.wikipedia.org/wiki/Sunset)
http://img440.imageshack.us/img440/7429/wikipediamiamisunset200ke5.th.jpg (http://img440.imageshack.us/my.php?image=wikipediamiamisunset200ke5.jpg)
GIMP - Shadows
-54, -16, 17
Preserve Luminosity checked
http://img360.imageshack.us/img360/2189/wikipediamiamisunset200rh2.th.jpg (http://img360.imageshack.us/my.php?image=wikipediamiamisunset200rh2.jpg)
Plugin
ImageReader("wikipediamiamisunset200ke5.jpg",0,0,pixel_type="RGB32")
a=last.ConvertToYUY2()
ColorBalance([<"LOW Cyan-Red", -100.0, 100.0, -54.9>],[<"LOW Magenta-Green", -100.0, 100.0, -16.6>],[<"LOW Yellow-Blue", -100.0, 100.0, 17.4>], \
[<"MID Cyan-Red", -100.0, 100.0, 0.0>],[<"MID Magenta-Green", -100.0, 100.0, 0.0>],[<"MID Yellow-Blue", -100.0, 100.0, 0.0>], \
[<"HI Cyan-Red", -100.0, 100.0, 0.0>],[<"HI Magenta-Green", -100.0, 100.0, 0.0>],[<"HI Yellow-Blue", -100.0, 100.0, 0.0>])
ConvertToYUY2()
MergeLuma(a)
http://img514.imageshack.us/img514/4608/wikipediamiamisunset200us3.th.jpg (http://img514.imageshack.us/my.php?image=wikipediamiamisunset200us3.jpg)
Both give this when not Preserving Luminosity
http://img261.imageshack.us/img261/1391/wikipediamiamisunset200rg3.th.jpg (http://img261.imageshack.us/my.php?image=wikipediamiamisunset200rg3.jpg)
Edit:
Using Midtones in gimp doesn't give awful results with Preserve Luminosity Checked.
Interesting... http://www.larryjordan.biz/articles/lj_color.html. sounds like ColorYUV() (http://avisynth.org/mediawiki/ColorYUV), but with a nice looking GUI. Thanks Gavino for pointing this out in your 2nd post and to Mug Funky for pointing to a nice GUI. Looks like http://avisynth.org/mediawiki/Histogram#Color2_mode would be useful
Edit 2: CinePaint with same settings as Gimp
http://img185.imageshack.us/img185/5939/wikipediamiamisunset200wg3.th.jpg (http://img185.imageshack.us/my.php?image=wikipediamiamisunset200wg3.jpg)
Looks like 16bit helps a little bit, but not a lot
IanB
27th August 2008, 13:57
...and clone the code with a very simple inner loop.... though in general I prefer not to repeat code as it makes it harder to change.Yes, repeating code of any substance can be problematic. But the thing here is the inner loop code should be as trivial as you can possibly make it, sufficiently trivial that cloning it is also trivial.
If there needs to be a meaty block of code repeated in several places and performance is an issue then you can use the inline compiler directive. Appropriate use of the alias operator, "&", with the formal arguments to the routine can help bend the compiler to your will. ;)
Gavino
27th August 2008, 23:24
Now I remember why I didn't like non scripting languages... constructors!
Don't be put off - the stuff in the constructor is basically the things that need only be done once per filter instance, rather than on every frame. That's not an issue with Gimp as it only has one 'frame' to process.
A further optimisation (this time shared with Gimp) is that some lookup tables are independent of the filter parameters and so are created just once as static and shared by all instances.
I think Gimp's Preserve Luminosity is broken, or at least it's suffering from rounding errors.
...Using Midtones in gimp doesn't give awful results with Preserve Luminosity Checked.
Could it be that Gimp is using PC-range in its RGB<->YUV conversions? I think this would show bigger differences at the extremes of the range and less on midtones, consistent with what you saw.
mikeytown2
27th August 2008, 23:33
0.2 Changes
Added in Preserve Luminosity and set it default true
Compiled in MS VC++ 2005 with 0 warnings
http://rapidshare.com/files/140643630/ColorBalance_0.2.zip.html
Next step is to create a GimpSupportFunctions Class, do simple code optimizations, then go 16 bit/double with a rounding function at the end. This is fast, so MT doesn't appeal to me right now.
gimpcolorspace 2.5.3 gimp_rgb_to_hsl_int, gimp_rgb_to_l_int, gimp_hsl_to_rgb_int, gimp_hsl_value_int
http://www.sfr-fresh.com/unix/misc/gimp-2.5.3.tar.gz:a/gimp-2.5.3/libgimpcolor/gimpcolorspace.c
http://www.sfr-fresh.com/unix/misc/gimp-2.5.3.tar.gz:a/gimp-2.5.3/libgimpcolor/gimpcolorspace.h
CinePaint equivalent rgb_to_hls, hls_to_rgb, hls_value
http://www.sfr-fresh.com/unix/misc/cinepaint-0.22-1.tar.gz:a/cinepaint-0.22-1/app/depth/paint_funcs_area.c
Doesn't look 16bit
mikeytown2
28th August 2008, 02:08
0.21 Changes
Code cleanup, should be slightly faster
Added AvsP sliders Example to zip
http://rapidshare.com/files/140669354/ColorBalance_0.21.zip.html
Preserve Luminosity Eats CPU
mikeytown2
28th August 2008, 09:56
0.22 Changes
Took out rounding and unnecessary calls to floor, Pixels shouldn't go out of bounds (some might have before). Slight speed increase as a result.
Updated AvsP sliders Example
http://rapidshare.com/files/140733316/ColorBalance_0.22.zip.html
mikeytown2
28th August 2008, 23:48
Looking at CinePaint
I think i'll use color_balance_row_float and its friends in order to support greater then 8bit color.
http://www.sfr-fresh.com/unix/misc/cinepaint-0.22-1.tar.gz:a/cinepaint-0.22-1/app/depth/color_balance.c
PS
Is there an easy threading class that I can plug-in? OpenMP sounds interesting, but Microsoft Visual Studio Professional 2005 isn't exactly cheap and going GCC means I have to use AviSynth C plugins.
http://gcc.gnu.org/projects/gomp/
Last time I played with threads we used JAVA at school, which if I remember correctly has threads built in.
IanB
28th August 2008, 23:59
Hint 1 :- Compare the quality of the asm code generated by this styler = *(srcp + w+2);
...
r_n = r_lookup[r];
...
*(dstp + w + 2) = r_n;with the asm code generated by this styledstp[w+2] = r_lookup[[srcp[w+2]];
...
Hint 2 :- For the preserve_luminosity case you currently use the same r_n = r_lookup[r]; byte lookup table as for the vanilla case. For no speed cost you could use a higher precision scaled unsigned short (16bit) version of the 256 element table and adjust the scaling constants in the gimp_rgb_to_hsl_int to match. Further as gimp_rgb_to_hsl_int is returning 3 32bit ints anyway you could super scale those results as well for no cost and similarly adjust the constants in gimp_hsl_to_rgb_int to match.
Hint 3 :- In all gimp_rgb_to_hsl_int, gimp_hsl_to_rgb_int and supporting routine you are using type double where type float has more than enough precision and the divides are considerably faster.
mikeytown2
29th August 2008, 01:25
hint 1: Nice trick with killing the pointers, didn't see it (arrays, what?). After I looked at the alpha channel, I finally realized it actually wasn't that complicated. And yeah I agree that the compiler should generate better code doing it this way.
hint 2: Need some time to think this one through.
hint 3: double to float gave a big speed boost in the hsl functions, thanks for the tip!
0.23 Changes
More speed
http://rapidshare.com/files/140922575/ColorBalance_0.23.zip.html
PS I used CinePaint in 8bit with the example above (http://forum.doom9.org/showthread.php?p=1175632#post1175632), going 16 bit makes the function behave completely differently & Preserve Luminosity doesn't work; thus comparisons of settings is useless. 16bit is so much better though!
http://img54.imageshack.us/img54/6114/wikipediamiamisunset200ql7.th.jpg (http://img54.imageshack.us/my.php?image=wikipediamiamisunset200ql7.jpg)
IanB
29th August 2008, 04:41
42.5f is equivalent to (float)42.5 but less typing ;)
As for hint 1 the compiler should generate identical code but for some dumb reason using the array reference is better than the equivalent pointer arithmetic. I guess the array reference was part of some bench mark and the compiler writers put bonus effort into that case.
And yes hint 2 involves a little thought re building the transfer tables.
mikeytown2
29th August 2008, 07:32
0.24 changes
scaled preserve_luminosity code by 64 (256*64=16384; 360*64=23040)
changed (float) to f; thanks for the tip IanB!
http://rapidshare.com/files/140969522/ColorBalance_0.24.zip.html
0.3 branch should have 16bit or float internals. Going camping so it might be done in a week or 2, unless someone wants to pick it up.
@IanB
I didn't touch the transfer tables... I believe they have to change in order to go from 8 bit to xx bit. All I did was scale by 64 what the hsl functions pass around; which should help seeing how I'm rounding down.
mikeytown2
3rd September 2008, 01:24
Got cinepaint 0.22-1 (http://sidux.net/etorix/) (run "apt-get update" before following readme) working on my box with andLinux (http://www.andlinux.org/), decided to do some comparisons.
Settings
S: 100,100,100
M: 100,100,100
H: -100,100,100
Lum - false
http://img230.imageshack.us/img230/6163/wikipediamiamisunset200zg0.th.jpg (http://img230.imageshack.us/my.php?image=wikipediamiamisunset200zg0.jpg) - 8bit int
http://img301.imageshack.us/img301/6055/wikipediamiamisunset200mn3.th.jpg (http://img301.imageshack.us/my.php?image=wikipediamiamisunset200mn3.jpg) - 16bit int
http://img175.imageshack.us/img175/6356/wikipediamiamisunset200jj6.th.jpg (http://img175.imageshack.us/my.php?image=wikipediamiamisunset200jj6.jpg) - 16bit OpenEXR Half Float
32-bit IEEE Float & 16-bit Fixed Point 0-2.0 don't work correctly. I can't see much of any difference between 16bit int
and 16bit float so i'll go with 16bit int; should be faster.
mikeytown2
5th September 2008, 00:16
Using the same settings as above I get this in GIMP and this plugin...
http://img255.imageshack.us/img255/2307/wikipediamiamisunset200yy3.th.jpg (http://img255.imageshack.us/my.php?image=wikipediamiamisunset200yy3.jpg)
I have a feeling that gimp's calculations are wrong. I've looked into the math and they both seem to be doing the same thing... any ideas? Cinepaint's internals look like they would run slow compared to Gimp's.
ps whats the standard way of getting internal calculations of your own plugin's, for debuging/curiosity purposes? I'm used to outputting to a GUI or command line, haven't done graphics before; using MSVC++2005 Express.
EDIT:
found it... it has to do with low and mid
Gavino
5th September 2008, 00:55
whats the standard way of getting internal calculations of your own plugin's, for debuging/curiosity purposes?
Probably the simplest way would be to write to a log file.
Perhaps flushing buffers every frame (or every x frames) so that you can look at it on-the-fly.
found it... it has to do with low and mid
Don't keep us in suspense, tell us more :)
mikeytown2
5th September 2008, 01:18
Don't keep us in suspense, tell us more :)
working on a solution that gives the user an option to choose between gimp and cinepaint... by looking at the code you can see how it differers.
void ColorBalance::Transfer8BitInit(bool clone_gimp)
{
int y = clone_gimp ? 0 : 255;
for (int i = 0; i < 256; i++)
{
double low = (1.075 - 1 / ((double) i / 16.0 + 1));
double mid = 2.0/3.0 * (1 - SQR (((double) i - 127.0) / 127.0));
shadows8_sub[255 - i] = low;
shadows8_add[i] = clone_gimp ? low : mid;
midtones8_sub[i] = mid;
midtones8_add[i] = mid;
highlights8_sub[i] = clone_gimp ? low : mid;
highlights8_add[y - i] = low;
}
}
mikeytown2
5th September 2008, 02:12
The above code is close to what I actually used. highlights8_add with a -i didn't work that well...
0.25 Changes
Added clone_gimp option, default true; false means it behaves like cinepaint
Started to add in 16bit int code, don't try it, bad idea.
http://rapidshare.com/files/142704290/ColorBalance_0.25.zip.html
Gavino
6th September 2008, 00:52
0.25 Changes
Added clone_gimp option, default true; false means it behaves like cinepaint
according to the code, default is false:
args[11].AsBool(false)
Also, I'm a bit puzzled by the Cinepaint transfer functions. It seems that adding a given value to shadows and adding to midtones will both produce exactly the same result. Similarly for subtracting from midtones and subtracting from highlights. Surely this doesn't make sense?
mikeytown2
6th September 2008, 01:49
according to the code, default is false:
args[11].AsBool(false)
Also, I'm a bit puzzled by the Cinepaint transfer functions. It seems that adding a given value to shadows and adding to midtones will both produce exactly the same result. Similarly for subtracting from midtones and subtracting from highlights. Surely this doesn't make sense?
Thanks for pointing that out!
did a quick comparison and yes you are correct. CinePaint doesn't quite add up...
ColorYUV(BlankClip(pixel_type="YUY2"),showyuv=true).ConvertToRGB()
a=last
x1=a.ColorBalance(0,0,0,0,0,0,-100,0,0,false,false,false)
y1=a.ColorBalance(0,0,0,-100,0,0,0,0,0,false,false,false)
x2=a.ColorBalance(0,0,0,0,0,0,-100,0,0,false,true,false)
y2=a.ColorBalance(0,0,0,-100,0,0,0,0,0,false,true,false)
v1=a.ColorBalance(0,100,0,0,0,0,0,0,0,false,false,false)
w1=a.ColorBalance(0,0,0,0,100,0,0,0,0,false,false,false)
v2=a.ColorBalance(0,100,0,0,0,0,0,0,0,false,true,false)
w2=a.ColorBalance(0,0,0,0,100,0,0,0,0,false,true,false)
i=StackHorizontal(Compare(x1,y1).Subtitle("CinePaint", align=5),Compare(x2,y2).Subtitle("GIMP", align=5))
j=StackHorizontal(Compare(v1,w1).Subtitle("CinePaint", align=5),Compare(v2,w2).Subtitle("GIMP", align=5))
StackVertical(i,j)
0.26 Changes
Fixed Default Value - Thanks Gavino!
http://rapidshare.com/files/142967394/ColorBalance_0.26.zip.html
zee944
26th December 2008, 23:16
mikeytown2,
I'm trying to use your plugin - but when I try to load ColorBalance.dll, I get this message:
Avisynth open failure:
LoadPlugin: unable to load "E:\ColorBalance.dll"
...while E:\ColorBalance.dll exists, of course. I can easily load other plugins like this:
LoadPlugin("E:\mt_masktools[2.0a30].dll")
LoadPlugin("E:\MaskTools[1.5.8].dll")
LoadPlugin("E:\RemoveGrain[1.0].dll")
LoadPlugin("E:\GiCoCu.dll")
LoadPlugin("E:\ColorBalance.dll")
The script still stops at ColorBalance (line 5).
I've tried it with Avisynth 2.5.7 first, then installed 2.5.8 beta. Still the same. Perhaps ColorBalance needs other plugins to load first?
kemuri-_9
27th December 2008, 01:29
I've tried it with Avisynth 2.5.7 first, then installed 2.5.8 beta. Still the same. Perhaps ColorBalance needs other plugins to load first?
or it's dynamically linking to libraries you don't have.
VC++ dynamically links to external libraries by default, need to specify it to staticly link for easier distribution.
mikeytown2
27th December 2008, 01:56
Try it after installing this
Microsoft Visual C++ 2005 Redistributable Package
http://www.microsoft.com/downloads/details.aspx?FamilyID=32bc1bee-a3f9-4c13-9c99-220b62a191ee&displaylang=en
zee944
27th December 2008, 14:49
Try it after installing this
Microsoft Visual C++ 2005 Redistributable Package
http://www.microsoft.com/downloads/details.aspx?FamilyID=32bc1bee-a3f9-4c13-9c99-220b62a191ee&displaylang=en
This solved it. Thanks.
lansing
17th April 2012, 19:34
can anyone reupload the colorbalance dll somewhere? The original download link was dead
Gavino
17th April 2012, 19:59
This is the penultimate version (v0.25).
I believe the only difference in v0.26 was to change/correct the default value of the clone_gimp parameter (see post #38 (http://forum.doom9.org/showthread.php?p=1180090#post1180090)).
lansing
18th April 2012, 06:27
12 hours since attachment posted and still no approval?
cretindesalpes
18th April 2012, 07:39
You forgot the magic formula. "I downloaded this MKV from the internets", and the moderators come instantly.
Mounir
19th April 2012, 00:34
i don't understand the syntax, how do you use this filter??
edit: nevermind
real.finder
1st July 2013, 06:59
This is the penultimate version (v0.25).
I believe the only difference in v0.26 was to change/correct the default value of the clone_gimp parameter (see post #38 (http://forum.doom9.org/showthread.php?p=1180090#post1180090)).
I found the v0.26 here (http://www.avisynth.info/?%A5%A2%A1%BC%A5%AB%A5%A4%A5%D6#z066d47f)
BiOSsCZ
16th November 2013, 21:30
Hello,
Please, how to use this interesting plugin?
Can anyone help me?
Bernardd
31st May 2015, 15:21
Hello,
I search a coloryuv autogain function alternative. I have tried to write a script to get automatic white balance with StainlessS RGBAdapt plugin.
Some results were nice, but it is a problem of luma compressed range, that i do not know resolve now. I am now out my knowledge boundary. Thus
i have tried to get automatic white balance with ColorBalance plugin. With my RGBAdapt experiment, i can say now, which is efficiently.
This function need to load ColorBalance.dll, GRunt.dll and MaskTools2.dll. The function has two original ColorBalance args (keep_luma and clone_gimp)
If the output is not nice, the function has two special args. one to tune the the reference middle value. one to increase or decrease the range of midtones.
There are three technical args, one for color space conversion matrix choice, one to display calculated corrections and one to display tones masks.
Note : i do not know Cine paint vs Gimp theorical difference
function ColorBalance_auto(clip, bool "keep_luma", bool "clone_gimp", string "matrix", int "midtones_value", \
string "midtones_size", bool "show_info", bool "show_masks")
{
#----------------------------------------------based on ColorBalance plugin -------------------------------------------------------------------#
# script authors : Gavino, Mikeytown2 http://forum.doom9.org/showpost.php?p=1570511&postcount=44 #
#------------------------------------------------------------------------------------------------------------------------------------------------- #
#---------------------------------------------- need GRunT plugin ----------------------------------------------------------------------------#
# script author : Gavino http://forum.doom9.org/showthread.php?p=1157083#post1157083 #
#----------------------------------------------------------------------------------------------------------------------------------------------- #
#---------------------------------------------- need masktools v2 plugin ----------------------------------------------------------------------------#
# script authors : Kurosu, Manao, mg262 http://forum.doom9.org/showthread.php?p=1157083#post1157083 #
# fork http://avisynth.nl/index.php/MaskTools2 #
#----------------------------------------------------------------------------------------------------------------------------------------------- -------#
keep_luma = default(keep_luma, true) # (original plugin arg) Keep_luma corresponds to Gimp's 'Preserve Luminosity'.
# This option ensures that the brightness is maintained. The value of the brightest pixels are not changed.
clone_gimp = default(clone_gimp, true) # (original plugin arg) If set to false, ColorBalance will behave like CinePaint.
matrix = default (matrix, "Rec601") # Color standart conversion matrix "Rec601" , "PC601" , "Rec709", "PC709"
midtones_value = default (midtones_value, 128) # Between 0 and 255, default 128
midtones_size = default(midtones_size, "64->192") # midtones range "96 - 160" or "64 - 192" or "32 - 224" or "0 - 255"
show_info = Default(show_info, false) # show info or not, default false
show_masks = Default(show_masks, false) # show masks or not, default false
ScriptClip(clip, """
clip = last
#----------- Luma tones evidence
(!isYV12(clip)) ? ConvertToYV12(clip, matrix=matrix) : clip
shadows_mask = (midtones_size == "96->160") ? MT_Lut(clip,"x 96 <= 255 0 ?", y=3,u=1, v=1):\
((midtones_size == "64->192") ? MT_Lut(clip,"x 64 <= 255 0 ?", y=3,u=1, v=1):\
((midtones_size == "32->224") ? MT_Lut(clip,"x 32 <= 255 0 ?", y=3,u=1, v=1):\
MT_Lut(clip,"x 0 <= 255 0 ?", y=3,u=1, v=1)))
midtones_mask = (midtones_size == "96->160") ? MT_Lut(clip,"x 160 <= x 96 > & 255 0 ?", y=3,u=1, v=1):\
((midtones_size == "64->192") ? MT_Lut(clip,"x 192 <= x 64 > & 255 0 ?", y=3,u=1, v=1):\
((midtones_size == "32->224") ? MT_Lut(clip,"x 224 <= x 32 > & 255 0 ?", y=3,u=1, v=1):\
MT_Lut(clip,"x 255 <= x 0 > & 255 0 ?", y=3,u=1, v=1)))
highlights_mask = (midtones_size == "96->160") ? MT_Lut(clip,"x 160 > 255 0 ?", y=3,u=1, v=1):\
((midtones_size == "64->192") ? MT_Lut(clip,"x 192 > 255 0 ?", y=3,u=1, v=1):\
((midtones_size == "32->224") ? MT_Lut(clip,"x 224 > 255 0 ?", y=3,u=1, v=1):\
MT_Lut(clip,"x 225 > 255 0 ?", y=3,u=1, v=1)))
black = BlankClip(clip, color=$000000)
shadows = Overlay(clip,black, mask=shadows_mask, opacity=1.0, mode="blend")
midtones = Overlay(clip,black, mask=midtones_mask, opacity=1.0, mode="blend")
highlights = Overlay(clip,black, mask=highlights_mask, opacity=1.0, mode="blend")
#------------ Color matrix input
Kr = (matrix == "Rec601") ? 0.299 : ((matrix == "PC601") ? 0.229 : 0.2126)
Kg = (matrix == "Rec601") ? 0.587 : ((matrix == "PC601") ? 0.587 : 0.7152)
Kb = (matrix == "Rec601") ? 0.114 : ((matrix == "PC601") ? 0.114 : 0.0722)
#------------ YUV values extraction
(!isYV12(clip)) ? ConvertToYV12(clip, matrix=matrix) : clip
y_shadows = AverageLuma(shadows)
u_shadows = AverageChromaU(shadows)
v_shadows = AverageChromaV(shadows)
y_midtones = AverageLuma(midtones)
u_midtones = AverageChromaU(midtones)
v_midtones = AverageChromaV(midtones)
y_highlights = AverageLuma(highlights)
u_highlights = AverageChromaU(highlights)
v_highlights = AverageChromaV(highlights)
#------------ RGB values
r_shadows = y_shadows + 2*(v_shadows - midtones_value)*(1-Kr)
g_shadows = y_shadows - 2*(u_shadows - midtones_value)*(1-Kb)*Kb/Kg \
- 2*(v_shadows - midtones_value)*(1-Kr)*Kr/Kg
b_shadows = y_shadows + 2*(u_shadows - midtones_value)*(1-Kb)
r_midtones = y_midtones + 2*(v_midtones - midtones_value)*(1-Kr)
g_midtones = y_midtones - 2*(u_midtones - midtones_value)*(1-Kb)*Kb/Kg \
- 2*(v_midtones - midtones_value)*(1-Kr)*Kr/Kg
b_midtones = y_midtones + 2*(u_midtones - midtones_value)*(1-Kb)
r_highlights = y_highlights + 2*(v_highlights - midtones_value)*(1-Kr)
g_highlights = y_highlights - 2*(u_highlights - midtones_value)*(1-Kb)*Kb/Kg \
- 2*(v_highlights - midtones_value)*(1-Kr)*Kr/Kg
b_highlights = y_highlights + 2*(u_highlights - midtones_value)*(1-Kb)
#----------- RGB différence calcul
du_shadows = 128-u_shadows # in YUV range, correction is 128 subtract YUV channel value
dv_shadows = 128-v_shadows
dr_shadows = 2*dv_shadows*(1-Kr)
db_shadows = 2*du_shadows*(1-Kb)
dg_shadows = - 2*du_shadows*(1-Kb)*Kb/Kg - 2*dv_shadows*(1-Kr)*Kr/Kg
du_midtones = 128-u_midtones
dv_midtones = 128-v_midtones
dr_midtones = 2*dv_midtones*(1-Kr)
db_midtones = 2*du_midtones*(1-Kb)
dg_midtones = - 2*du_midtones*(1-Kb)*Kb/Kg - 2*dv_midtones*(1-Kr)*Kr/Kg
du_highlights = 128-u_highlights
dv_highlights = 128-v_highlights
dr_highlights = 2*dv_highlights*(1-Kr)
db_highlights = 2*du_highlights*(1-Kb)
dg_highlights = - 2*du_highlights*(1-Kb)*Kb/Kg - 2*dv_highlights*(1-Kr)*Kr/Kg
#----------- RGB corrections calcul
red_shadows = 100*dr_shadows/r_shadows
green_shadows = 100*dg_shadows/r_shadows
blue_shadows = 100*db_shadows/r_shadows
red_midtones = 100*dr_midtones/r_midtones
green_midtones = 100*dg_midtones/r_midtones
blue_midtones = 100*db_midtones/r_midtones
red_highlights = 100*dr_highlights/r_highlights
green_highlights = 100*dg_highlights/r_highlights
blue_highlights = 100*db_highlights/r_highlights
#-------- ColorBalance use
(!isYV12(clip)) ? clip : ConvertToRGB(clip, matrix=matrix)
ColorBalance(last, red_shadows, green_shadows, blue_shadows, \
red_midtones, green_midtones, blue_midtones, \
red_highlights, green_highlights, blue_highlights,\
keep_luma, clone_gimp,false)
#-------- displayed info or no
(!show_info)? last : \
last.Subtitle("RED" + " Midtones range : " + string(midtones_size)+\
"\nShadows Values : "+String(r_shadows)+ " Midtones Values : "+String(r_midtones)+" Highlights Values: "+String(r_highlights)+\
"\nShadows Values Diff : "+String(dr_shadows)+ " Shadows ColorBalance Corr : "+String(red_shadows)+\
"\nMidtones Values Diff : "+String(dr_shadows)+ " Midtones ColorBalance Corr : "+String(red_midtones)+\
"\nHighlightss Values Diff : "+String(dr_shadows)+ " Highlights ColorBalance Corre : "+String(red_highlights),\
y=40,lsp=20)\
.Subtitle("GREEN" +\
"\nShadows Values : "+String(g_shadows)+ " Midtones Values : "+String(g_midtones)+" Highlights Values: "+String(g_highlights)+\
"\nShadows Values Diff : "+String(dg_shadows)+ " Shadows ColorBalance Corr : "+String(green_shadows)+\
"\nMidtones Values Diff : "+String(dg_midtones)+ " Midtones ColorBalance Corr : "+String(green_midtones)+\
"\nHighlightss Values Diff : "+String(dg_highlights)+ " Highlights ColorBalance Corr : "+String(green_highlights),\
y=160,lsp=20)\
.Subtitle("Blue" +\
"\nShadows Values : "+String(b_shadows)+ " Midtones Values : "+String(b_midtones)+" Highlights Blue Values: "+String(b_highlights)+\
"\nShadows Values Diff : "+String(db_shadows)+ " Shadows ColorBalance Corr : "+String(blue_shadows)+\
"\nMidtones Values Diff : "+String(db_midtones)+ " Midtones ColorBalance Corr : "+String(blue_midtones)+\
"\nHighlightss Values Diff : "+String(db_highlights)+ " Highlights ColorBalance Corr : "+String(blue_highlights),\
y=280,lsp=20)
(!isYV12(clip)) ? last : ConvertToYV12(last, matrix=matrix)
(!show_masks)? last : StackHorizontal(shadows.Subtitle("Shadows"), midtones.Subtitle("Midtones"), highlights.Subtitle("highlights"))\
.BilinearResize( width(clip), height(clip))
return last """, args = "keep_luma, clone_gimp, matrix, midtones_value, midtones_size, show_info, show_masks")
(!show_masks)? last : BilinearResize( 3*width(clip), height(clip))
}
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.