switch between colors on image

51 views (last 30 days)
Stas
Stas on 5 Nov 2012
Edited: DGM on 2 May 2022
hey
How can I switch the red color with the green color on image i mean the red will become green and green become red ?
thanks
  2 Comments

Sign in to comment.

Accepted Answer

DGM
DGM on 2 May 2022
Edited: DGM on 2 May 2022
A lot of people are looking at this old thread, so I assume their needs are not necessarily the same as the OP. I think when most people say "I want to change one color to another", they don't intend what a channel swap would cause.
For example, let's start with this image:
In order to swap channels, you don't need to make a pile of temporary images or split anything. Just use basic indexing. Just one line.
% do a basic channel swap
inpict = imread('coloredChips.png');
outpict = inpict(:,:,[2 1 3]); % swap R and G
imshow(outpict)
If a channel swap is all you really want, then there you go. While this particular image is somewhat forgiving in this case, turning the green objects into burgundy and turning all the red and orange objects into vibrant green and casting the background in a faint green doesn't seem like the obvious interpretation of "make red things green and make green things red"
You can do basic color-based logical (hard-edged) masking and simply fill certain regions with a new color. There are a number of examples around, including this one based on the same image. The idea is simply to generate a set of logical masks describing "red" and "green" objects. Then use basic logical indexing or linear (multiplicative) composition to replace the masked regions of the image with a new color. Since I've already provided an example of doing that the tedious way, I'm going to make it easy on myself and use purpose-built composition tools from MIMT.
% do solid color fill with binary masks
inpict = imread('coloredChips.png');
% create binary masks
rangeR = [0.963 0.016; 0.258 1; 0.338 1];
rangeG = [0.380 0.453; 0.258 1; 0.338 1];
hsvpict = rgb2hsv(inpict);
maskR = all(hsvpict >= permute(rangeR(:,1),[2 3 1]),3) ...
| all(hsvpict <= permute(rangeR(:,2),[2 3 1]),3);
maskG = all(hsvpict >= permute(rangeG(:,1),[2 3 1]),3) ...
& all(hsvpict <= permute(rangeG(:,2),[2 3 1]),3);
% clean the masks
maskR = bwareaopen(maskR,100);
maskG = bwareaopen(maskG,100);
% reference colors
r = [0.9323 0.0854 0.1486];
g = [0.0502 0.6458 0.3619];
% replace masked regions with solid color fill
outpict = replacepixels(r,inpict,maskR);
outpict = replacepixels(g,outpict,maskG);
imshow(outpict)
That might be a bit closer to what one might expect, but two things are of note. Since the masked regions were simply filled with a new color, the lightness details were lost; also, the hard mask edges aren't the nicest.
What can be done about the loss of lightness details? One might look at the masking operation and realize that the selected colors are basically the same S and V, but simply differ in H. Why can't we just swap H in those regions?
% do a hue rotation with binary masking
inpict = imread('coloredChips.png');
% create binary masks
rangeR = [0.963 0.016; 0.258 1; 0.338 1];
rangeG = [0.380 0.453; 0.258 1; 0.338 1];
hsvpict = rgb2hsv(inpict);
maskR = all(hsvpict >= permute(rangeR(:,1),[2 3 1]),3) ...
| all(hsvpict <= permute(rangeR(:,2),[2 3 1]),3);
maskG = all(hsvpict >= permute(rangeG(:,1),[2 3 1]),3) ...
& all(hsvpict <= permute(rangeG(:,2),[2 3 1]),3);
% clean the masks
maskR = bwareaopen(maskR,100);
maskG = bwareaopen(maskG,100);
% adjust the hue of the masked regions
% doing uncorrected H/S adjustment in HSV isn't great
H = hsvpict(:,:,1);
H(maskR) = mod(H(maskR)-0.5730,1); % rotate CW
H(maskG) = mod(H(maskG)+0.5730,1); % rotate CCW
hsvpict(:,:,1) = H;
% assemble output
outpict = hsv2rgb(hsvpict);
imshow(outpict)
Wait a minute. If V is preserved, then why is the new green so bright and the new red so dark? Generally, HSV isn't a good choice to do H or S adjustment in due to the poor separation of brightness and color information. HSL is marginally better due to its symmetry, but most tools that use either for doing colorization or HS swaps use some sort of compensation technique to make up for the deficiencies of the color model. That hard-edged logical masking is still pretty ugly too.
So we still have two issues: swap H and S without losing lightness information, and make the mask edges less ugly. As I mentioned, there are ways to do colorization that can compensate to some degree. MIMT has a few methods to choose from. As far as the masking goes, we could choose to simply feather the binary mask by simply blurring it, or using a combination of dilation and blurring. On the other hand, maybe we can be a little more strategic.
% using constrained linear masking and HSL+Y colorization
inpict = imread('coloredChips.png');
% these are logical masks which only roughly select the object regions
% the actual object selection is done by a linear mask within each region
rangeR = [0.963 0.016; 0.258 1; 0.338 1];
rangeG = [0.380 0.453; 0.258 1; 0.338 1];
hsvpict = rgb2hsv(inpict);
roiR = all(hsvpict >= permute(rangeR(:,1),[2 3 1]),3) ...
| all(hsvpict <= permute(rangeR(:,2),[2 3 1]),3);
roiG = all(hsvpict >= permute(rangeG(:,1),[2 3 1]),3) ...
& all(hsvpict <= permute(rangeG(:,2),[2 3 1]),3);
% clean the mask
roiR = bwareaopen(roiR,100);
roiG = bwareaopen(roiG,100);
% dilate beyond object extents
roiR = imdilate(roiR,strel('disk',3));
roiG = imdilate(roiG,strel('disk',3));
% reference colors for finding color distance
r = [0.9323 0.0854 0.1486]; % HSL [355.5225 0.8622 0.5089]
g = [0.0502 0.6458 0.3619]; % HSL [151.4003 0.8557 0.3480]
% get color distance maps
labpict = rgb2lab(inpict);
Dr = sqrt(sum((labpict-ctflop(rgb2lab(r))).^2,3));
Dg = sqrt(sum((labpict-ctflop(rgb2lab(g))).^2,3));
% convert color distances to linear masks
near = 20;
far = 70;
maskR = 1-mat2gray(Dr,[near far]);
maskG = 1-mat2gray(Dg,[near far]);
% create colorized copies of the source image
% gcolorize does HS substitution in luma-corrected HSL
Rcolorized = gcolorize(inpict,[356 86 0]);
Gcolorized = gcolorize(inpict,[151 86 10]);
% replace the masked regions with colorized copies
outpict = replacepixels(Gcolorized,inpict,maskR.*roiR,'linear');
outpict = replacepixels(Rcolorized,outpict,maskG.*roiG,'linear');
imshow(outpict)
It's not perfect, but it's a lot closer. Alternatively to using gcolorize(), similar can be done using blending approaches.
% ...
% colorize by image blending
R = colorpict(size(inpict),[0.9323 0.0854 0.1486]);
G = colorpict(size(inpict),[0.0502 0.6458 0.3619]);
Rcolorized = imblend(inpict,R,1,'luma');
Gcolorized = imblend(inpict,G,1,'luma');
% replace the masked regions with colorized copies
outpict = replacepixels(Gcolorized,inpict,maskR.*roiR,'linear');
outpict = replacepixels(Rcolorized,outpict,maskG.*roiG,'linear');
imshow(outpict)
While this example deals with salient objects of relatively unique colors in relatively even illumination, object color replacement isn't generally this simple. You might refer to this question for other ideas. You might also realize that image nonuniformity and poor object saliency means that programmatic approaches based on global reference values are often going to be more difficult and time-consuming to accomplish than just throwing it in GIMP or Photoshop and using your own eyes and hands.
The functions colorpict(), ctflop(), gcolorize(), imblend() and replacepixels() are part of MIMT and are available on the File Exchange. MIMT exists for convenience; anything that MIMT tools do can also be done with base MATLAB tools. If you don't want to use MIMT and you like reinventing wheels, simply open up the function files and see how they work.
For creating color fields as colorpict does, see this answer. For other colorization ideas, this answer might be a bit tangential, but should help. Alternatively, you could colorize by converting a copy to grayscale and then doing something like what's described here. For composition like what replacepixels() does, this answer shows blending approaches, as well as opacity composition both with and without MIMT. It also links to several other composition-related questions.

More Answers (1)

Image Analyst
Image Analyst on 5 Nov 2012
DON'T use "image" as the name of your variable. You will blow away the built-in function called image(). Do something like this:
% Read in image.
rgbImage = imread ('peppers.png');
subplot(1, 2, 1);
imshow(rgbImage);
title('Original Image', 'FontSize', 20);
% Enlarge figure to full screen.
set(gcf, 'units','normalized','outerposition',[0 0 1 1]);
% Now switch color channels.
image_switch(:,:,1)= rgbImage(:,:,2);
image_switch(:,:,2)= rgbImage(:,:,1);
image_switch(:,:,3)= rgbImage(:,:,3);
% Display switched image.
subplot(1, 2, 2);
imshow(image_switch);
title('Red and Green Switched', 'FontSize', 20);

Community Treasure Hunt

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

Start Hunting!