Change specific color in an image to another one

123 vues (au cours des 30 derniers jours)
Dries Weytjens
Dries Weytjens le 5 Mai 2017
Modifié(e) : DGM le 4 Sep 2022
Hello,
I am trying to change colors in an image into another color. I have generated some code myself but something seems to be wrong. What I am trying to achieve on the attached file is to change every purple data point into a green data point, or whatever color I would prefer. Currently, the code that I have written is able to change purple to green but the edges of the marked points are still in purple, I believe this has something to do with the intensity at the edges being different or something...
[I,m] = imread('iteration31.png');
%image = imshow(I,'Colormap',m);
rgbImage = ind2rgb(I,m);
redChannel = rgbImage(:, :, 1);
greenChannel = rgbImage(:, :, 2);
blueChannel = rgbImage(:, :, 3);
purplePixels = redChannel == 1 & greenChannel == 0 & blueChannel == 1;
% MAKE THEM GREEN
redChannel(purplePixels) = 0;
greenChannel(purplePixels) = 1;
blueChannel(purplePixels) = 0;
rgbImage = cat(3, redChannel, greenChannel, blueChannel);
imshow(rgbImage);

Réponse acceptée

Matthew Eicholtz
Matthew Eicholtz le 5 Mai 2017
This is a tough problem. Since you are using a raster image, objects that look purple are actually many small variations of purple. One thing you could try to do is compute which colors are purple-ish, and then modify those colors in the colormap.
Here is an example that may yield slightly better results than what you were experiencing, but still not perfect:
% Read image
[I,m] = imread('iteration31.png');
% Find purple-ish colors
mask1 = abs(m(:,3)-m(:,1))<0.8;
mask2 = abs(m(:,3)-m(:,2))>0.3;
mask3 = abs(m(:,2)-m(:,1))>0.3;
mask = mask1 & mask2 & mask3;
% Convert purple-ish colors to green-ish colors
m(mask,:) = 1-m(mask,:);
% Create and show newly colored image
rgb = ind2rgb(I,m);
imshow(rgb);
  2 commentaires
Trying To Learn
Trying To Learn le 4 Sep 2022
Hi, I got "Index in position 2 exceeds array bounds." error for mask1 = abs(m(:,3)-m(:,1))<0.8;
Could I get the explanation for mask1, mask2, mask3 values? Or somewhere else that I can read for the theory. Thank you.
DGM
DGM le 4 Sep 2022
Modifié(e) : DGM le 4 Sep 2022
The code works for me without error.
% Read image
[I,m] = imread('iteration31.png');
% Find purple-ish colors
mask1 = abs(m(:,3)-m(:,1))<0.8;
mask2 = abs(m(:,3)-m(:,2))>0.3;
mask3 = abs(m(:,2)-m(:,1))>0.3;
mask = mask1 & mask2 & mask3;
% Convert purple-ish colors to green-ish colors
m(mask,:) = 1-m(mask,:);
% Create and show newly colored image
rgb = ind2rgb(I,m);
imshow(rgb(200:600,1100:1450,:)); % show a small area
As you can see, this still has the problem of leaving fringes at the edge of the target regions. Trying to change the color of a soft-edged region by either direct color replacement or value inversion is always going to give poor results when using a binary mask. The binary mask will always be either overselecting or underselecting the region, and inversion or direct replacement will make the imperfect mask extents conspicuous.
There are various ways to approach this depending on how perfect the results need to be. I may post an answer if my network connection stays up today.

Connectez-vous pour commenter.

Plus de réponses (1)

DGM
DGM le 4 Sep 2022
Consider the following example using the OP's original image and task.
% Load image
[idxpict,ct] = imread('iteration31.png');
rgbpict = im2uint8(ind2rgb(idxpict,ct));
% Play around with the thresholds until you get what you want.
thresholds = [0.82 0.85]; % [Hmin Hmax]
hsvpict = rgb2hsv(rgbpict);
isPurple = hsvpict(:,:,1)>0.82 & hsvpict(:,:,1)<0.85;
% clean up the mask
isPurple = imerode(isPurple,ones(2));
% dilate it to hopefully include the extremes of the region extent
isPurple = imdilate(isPurple,ones(3));
imshow(isPurple(250:450,1200:1350,:)) % show a closeup of the mask
% expand to simplify addressing later
isPurpleArray = repmat(isPurple,1,1,3);
% Once you're happy with your thresholds above, adjust the image content.
hsvpict(:,:,1) = mod(hsvpict(:,:,1)-0.5,1); % rotate hue by 180d
adjpict = hsv2rgb(hsvpict);
% combine the adjusted image and the original using logical composition
% images must be the same class and scale
outpict = rgbpict;
outpict(isPurpleArray) = im2uint8(adjpict(isPurpleArray));
% Compare the original and new image.
figure(3)
subplot(1,2,1)
imshow(rgbpict(250:450,1200:1350,:))
title('Original')
subplot(1,2,2)
imshow(outpict(250:450,1200:1350,:))
title('Modified')
This is a relatively simplified case since the colored dots are well separated by neutral colors. In this scenario, there's little harm in making the mask overselect the dots. If the background were not neutral, things would be different.
I've posted a number of answers to "change one color to another" problems. The above example uses no special tools, but some of the other examples use freely available third party tools.
Change the colors in a smoothly-graduated rainbow image (uses MIMT color2alpha())
Naive channel swap, hard masked filling/tweaking, lin masked colorization (color chips against table)
Color squares example (hue rotate, hue replace, solid fill; (mostly MIMT)
Pink strawberries (HSV segmentation & adjustment; no MIMT)
Change hair color (colorization of black objects and the challenges of realism)

Catégories

En savoir plus sur Purple dans Help Center et File Exchange

Produits

Community Treasure Hunt

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

Start Hunting!

Translated by