How to white balance the each RGB components of an image?

56 views (last 30 days)
First I uploaded an image and splitted it into RGB components..Then I want to white balance each rgb components seperately.. Is the double value of R component is supported to white balance algorithm? or the doubling of r or g or b component is possible?

Accepted Answer

Image Analyst
Image Analyst on 8 Oct 2015
You can't white balance a single color channel (that doesn't even make sense because a single channel is monochrome, not color), but if you want to make the means of each color channel the same, then you can do this
grayImage = rgb2gray(rgbImage); % Convert to gray so we can get the mean luminance.
% Extract the individual red, green, and blue color channels.
redChannel = rgbImage(:, :, 1);
greenChannel = rgbImage(:, :, 2);
blueChannel = rgbImage(:, :, 3);
meanR = mean2(redChannel);
meanG = mean2(greenChannel);
meanB = mean2(blueChannel);
meanGray = mean2(grayImage);
% Make all channels have the same mean
redChannel = uint8(double(redChannel) * meanGray / meanR);
greenChannel = uint8(double(greenChannel) * meanGray / meanG);
blueChannel = uint8(double(bluedChannel) * meanGray / meanB);
% Recombine separate color channels into a single, true color RGB image.
rgbImage = cat(3, redChannel, greenChannel, blueChannel);
It can get more complicated, but see if this simple way works for you and meets your needs.
  2 Comments
gunturu gunturu
gunturu gunturu on 23 Mar 2021
(double(redChannel) * meanGray / meanR)
is this a formula to make all channels have the same mean?
Image Analyst
Image Analyst on 23 Mar 2021
Yes. Doing that to each channel (dividing by it's actual mean and multiplying by some desired mean) would make each color channel have the same mean. Of course this will change the color of the image. And the gray mean should be computed only on parts of the image that are meant to be "white" (not colored) and should not include any saturated values (values of 0 or 255 if 8 bit or 65535 if 16 bit images).

Sign in to comment.

More Answers (3)

DGM
DGM on 2 Oct 2023
Edited: DGM on 2 Oct 2023
I'm bored on a sunday night, so I'm just going to throw this here. I don't really ever have need for auto white balancing, but the last few times I did, I had a terrible time trying to get decent results using recommended approaches. Out of sheer confusion avoidance, I just figured something out that worked for the extreme casts I was dealing with. Given that I'm using MIMT autowb(), I'm just going to use whatever other MIMT tools I care to use here.
Consider the following test image:
%% hall (automatic)
inpict = imread('sources/standardmods/hallway_small.jpg');
% use simple grayworld assumption in sRGB
% this is the same as the accepted answer above
op1 = rgbwb(inpict);
% use illumwhite()/chromadapt()
% overexposed regions tend to become unnaturally saturated
% causing an apparent brightness inversion and loss of local contrast
percentileToExclude = 10;
illuminant_wp1 = illumwhite(inpict,percentileToExclude);
op2 = chromadapt(inpict,illuminant_wp1,'colorspace','srgb','method','bradford');
% use autowb() with auto white region determination
% results are generally moderated, but saturated white regions are not molested
op3 = autowb(inpict);
outpict = [op1; op2; op3];
imshow(outpict)
Here, the given sRGB approach works fine. Using illumwhite()/chromadapt() is often difficult. It's all to easy for neutral regions to be overcorrected. Note how the bright regions suffer contrast distortion and are no longer neutral. MIMT autowb() tends to err on the side of undercorrection, but at least the contrast is preserved in the bright regions. It's corrected enough to be plausible.
Could we do better if we specified a neutral region to use as a reference? Potentially, but it's up to the user to make a good selection, and manual selection may be a source of inconsistency or hassle if you're trying to automate processing a large number of images.
Consider this answer and this mask:
%% hall (masked)
inpict = imread('sources/standardmods/hallway_small.jpg');
mask = imread('sources/standardmods/hallway_small_mask.png');
% use simple grayworld assumption in sRGB
op1 = rgbwb_masked(inpict,mask);
% use autowb() with an explicit mask
% results may be improved, but it's up to you to create a good mask
op2 = autowb(inpict,mask);
outpict = [op1 op2];
imshow(outpict)
While the sRGB example is severely overcorrected in the bright regions, the autowb() example is notably improved by the masking. I suppose that's a little unfair, since autowb() isn't skewed by the inclusion of saturated regions to the extent that the sRGB approach is. This kind of reinforces the need to make a good selection. The sRGB example could be improved as noted in the comments in the functions below, but neutral colors are still overcorrected.
None of that's all that bad though. Once you run into dark images with severe casts, trying to do this with the given sRGB approach will tend to fail spectacularly.
%% hands (automatic)
inpict = imread('sources/handcar_small.jpg');
% use simple grayworld assumption in sRGB
op1 = rgbwb(inpict);
% use autowb() with auto white region determination
op2 = autowb(inpict);
outpict = [inpict op1 op2];
imshow(outpict)
Illumwhite()/chromadapt() tend to not have this problem, but I still didn't like dealing with all the specular reflections in the image turning into vivid cyan.
function outpict = rgbwb(inpict)
% this is a class-agnostic simplification of the accepted answer
[inpict inclass] = imcast(inpict,'double');
% get channel means
meanRGB = mean(inpict,[1 2]);
meanGray = gettfm('luma','601')*meanRGB(:);
% adjust
outpict = inpict.*meanGray./meanRGB;
outpict = imcast(outpict,inclass);
end
function outpict = rgbwb_masked(inpict,mask)
% this is a class-agnostic simplification of #73720
% but for sake of consistency, i'm adding mask support
[inpict inclass] = imcast(inpict,'double');
mask = gray2rgb(imcast(mask,'logical'));
% get channel means
sample = reshape(inpict(mask),[],1,3);
meanRGB = mean(sample,1);
%meanGray = gettfm('luma','601')*meanRGB(:); % this may be better
meanGray = mean(meanRGB); % but this is what the demo does
% adjust
outpict = inpict.*meanGray./meanRGB;
outpict = imcast(outpict,inclass);
end
MIMT autowb() uses a constrained grayworld assumption. The sample region is the set of pixels whose L* is in the upper 80th percentile, and whose chroma is in the lower 80th percentile (default parameters). Fully saturated white pixels are excluded from the sample. Operations are performed in LAB with chroma constraint to avoid local value inversion and excessive saturation boosting in bright regions.
If desired, autowb() will return the calculated mean neutral point in the AB plane. That can be used in subsequent calls to autowb() for referenced white balancing tasks.
I think a picky person would find it problematic that autowb() tends to undercorrect, but the whole point was to create something that could be fed a large number of images taken under variously terrible lighting conditions. All it needed to do is make them better. I did not want to have to babysit the thing to catch any distorted highlight regions and red/blue speckles.

Walter Roberson
Walter Roberson on 8 Oct 2015
No, white balance inherently requires access to all three channels, as it is necessary to estimate the color temperature.
  2 Comments
anil aggarwal
anil aggarwal on 4 Apr 2018
yea I agree with this and my request to "ImageAnalyst" to update his reply please...

Sign in to comment.


Mahmoud Afifi
Mahmoud Afifi on 12 Aug 2019
You can apply diagonal white balance correction to raw-RGB images that are a linear representation constructed at the begining of camera rendering pipeline. If you have a rendered sRGB image (e.g., JPEG image), applying white balance in that space by scaling each color channel will not help too much in serious color cast cases. In that case you may need to use an algorithm for white balancing images in sRGB space.
Try this one:
Reference: When Color Constancy Goes Wrong: Correcting Improperly White-Balanced Images, CVPR'19.

Categories

Find more on Convert Image Type in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!