Changing one color to another in a RGB image

32 views (last 30 days)
Larry Muester
Larry Muester on 29 Jan 2019
Commented: DGM on 22 Mar 2022
I have a RGB image and I want to turn all of the white portions of it to red. What I have so far is
rgbImage = imread('rainbow.jpg');
redChannel = rgbImage(:, :, 1);
greenChannel = rgbImage(:, :, 2);
blueChannel = rgbImage(:, :, 3);
whitePixels = redChannel == 255 & greenChannel == 255 & blueChannel == 255;
redChannel(whitePixels) = 255;
greenChannel(whitePixels) = 0;
blueChannel(whitePixels) = 0;
rgbImage1 = cat(3, redChannel, greenChannel, blueChannel);
image(rgbImage1)
However, the code simply returns the original image without any changes.
rgbImage is of type uint8 whereas whitePixels is of type logical. Would this have any affect on the outcome?
  5 Comments
Adam
Adam on 30 Jan 2019
Edited: Adam on 30 Jan 2019
Look at
nnz( whitePixels )
in your code also to see if there are actually any white pixels picked up by your logic.
When I run your code on 'gantrycrane.png', which is the only Matlab-based image I could remember off the top of my head!, I get 8 white pixels and when I visualise the end result I can see they have turned red.
Walter Roberson
Walter Roberson on 30 Jan 2019
And remember that .jpg blurs sharp lines so what looks like pure white might not be exactly pure white.

Sign in to comment.

Answers (2)

DGM
DGM on 22 Mar 2022
Edited: DGM on 22 Mar 2022
I kind of wish this weren't a dead question. Oh well.
You could certainly try to do a logical masking operation. Depending on your image and goals, that might be appropriate, or it might not. The given filename implies an image with smooth color transitions. That sounds like a bad case for using a logical masking approach.
Consider the following image:
As Walter says, your mask doesn't select anything except [255 255 255]. Even a more lenient mask specification will produce ugly results:
inpict = imread('rainbow.png');
th = 240;
whitePixels = repmat(all(inpict >= th,3),[1 1 3]);
outpict = inpict;
outpict(whitePixels) = repmat(permute([255 0 0],[1 3 2]),[nnz(whitePixels)/3 1]);
imshow(outpict)
Depending on the goals, this may be the desired outcome. If appearances are what's important, then maybe this isn't a very good approach.
You could take the image saturation and use that as a mask for multiplicative composition:
inpict = imread('rainbow.png');
s = size(inpict);
hsvpict = rgb2hsv(inpict);
colorpict = repmat(permute([255 0 0],[1 3 2]),s(1:2));
satmap = hsvpict(:,:,2); % a map of color saturation
% compose image
outpict = uint8(double(inpict).*satmap + colorpict.*(1-satmap));
imshow(outpict)
If desired, you could adjust the slope and extent of the mask with imadjust():
inpict = imread('rainbow.png');
s = size(inpict);
hsvpict = rgb2hsv(inpict);
colorpict = repmat(permute([255 0 0],[1 3 2]),s(1:2));
satmap0 = hsvpict(:,:,2);
% a simple gamma adjustment to reduce extent of color replacement
satmap = imadjust(satmap0,[0 1],[0 1],0.5);
outpict = uint8(double(inpict).*satmap + colorpict.*(1-satmap));
imshow(outpict)
% a simple gamma adjustment to increase extent of color replacement
satmap = imadjust(satmap0,[0 1],[0 1],2);
outpict = uint8(double(inpict).*satmap + colorpict.*(1-satmap));
imshow(outpict)
More to the general question as stated in the title, how can this be generally applied to any color? Consider the following example wherein green is replaced with purple. This is similar to the decomposition used by GIMP's "Color to Alpha" tool, though without the corrections.
inpict = imread('rainbow.png');
incolor = [0 1 0];
outcolor = [0.6 0 1];
% create a mask
inpict = im2double(inpict);
mask = zeros(size(inpict));
s = size(inpict);
for c = 1:3
if incolor(c) < 0.0001
mask(:,:,c) = inpict(:,:,c);
else
cdiff = abs(inpict(:,:,c)-incolor(c));
mA = inpict(:,:,c) > incolor(c);
mB = inpict(:,:,c) < incolor(c);
mask(:,:,c) = cdiff./(1-incolor(c)+eps) .* mA + cdiff./incolor(c) .* mB;
end
end
mask = max(mask,[],3);
% compose image
outcp = repmat(permute(outcolor,[1 3 2]),s(1:2));
outpict = im2uint8(inpict.*mask + outcp.*(1-mask));
imshow(outpict)
That works, though maybe the transitions aren't the best. Doing the operations in linear RGB might help, but this is already getting pretty complicated.
The aforementioned GIMP tool is replicated in MIMT's color2alpha(). Combining that with MIMT imblend(), we can get this with relatively simple syntax:
inpict = imread('rainbow.png');
incolor = [0 1 0];
outcolor = [0.6 0 1];
s = size(inpict);
outcp = colorpict(s,outcolor); % a solid color RGB image
tppict = color2alpha(inpict,incolor); % an RGBA image
outpict = imblend(tppict,outcp,1,'normal'); % compose
outpict = outpict(:,:,1:3); % strip alpha
imshow(outpict)
As mentioned, this composition can also be done in linear RGB without complication:
outpict = imblend(tppict,outcp,1,'normal','linear'); % compose
outpict = outpict(:,:,1:3); % strip alpha
imshow(outpict)
Depends what suits the situation.
  2 Comments
Image Analyst
Image Analyst on 22 Mar 2022
It's not necessarily dead. We find that many, many times people reply to very old threads, so the threads are still being accessed and people are still learning from them even though they're old, so it's not a bad idea to add an answer, especially if there is not any answers yet.
By the way, I'm attaching my color change demos that I posted for other questions.
DGM
DGM on 22 Mar 2022
While I justify it by observing the current traffic on old posts, I still feel a tiny bit bad when I stir things back to the top of the recent queue just because I'm bored and disinterested in the current questions that people actually want answered.
Then I remember that this isn't a job.

Sign in to comment.


Image Analyst
Image Analyst on 22 Mar 2022
See attached demos from my huge list of over 400 old demos I've posted before.
Adapt as needed.

Categories

Find more on Images in Help Center and File Exchange

Products


Release

R2018b

Community Treasure Hunt

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

Start Hunting!