Comment puis-je convertir une image RGB en échelle de gris mais garder une couleur?
j'essaie de créer un effet similaire à Sin City ou d'autres films où ils suppriment toutes les couleurs sauf une d'une image.
j'ai une image RGB que je veux convertir en échelle de gris mais je veux garder une couleur.
voici ma photo:
je veux garder la couleur rouge. Le reste doit être en échelle de gris.
c'est Ce que mon code sorties jusqu'à présent (vous pouvez voir que les zones sont corrects, j' ne sais pas pourquoi ils sont blanc au lieu de rouge):
Voici mon code:
filename = 'roses.jpg';
[cdata,map] = imread( filename );
% convert to RGB if it is indexed image
if ~isempty( map )
cdata = idx2rgb( cdata, map );
end
%imtool('roses.jpg');
imWidth = 685;
imHeight = 428;
% RGB ranges of a color we want to keep
redRange = [140 255];
greenRange = [0 40];
blueRange = [0 40];
% RGB values we don't want to convert to grayscale
redToKeep = zeros(imHeight, imWidth);
greenToKeep = zeros(imHeight, imWidth);
blueToKeep = zeros(imHeight, imWidth);
for x=1:imWidth
for y=1:imHeight
red = cdata( y, x, 1 );
green = cdata( y, x, 2 );
blue = cdata( y, x, 3 );
if (red >= redRange(1) && red <= redRange(2) && green >= greenRange(1) && green <= greenRange(2) && blue >= blueRange(1) && blue <= blueRange(2))
redToKeep( y, x ) = red;
greenToKeep( y, x ) = green;
blueToKeep( y, x ) = blue;
else
redToKeep( y, x ) = 999;
greenToKeep( y, x ) = 999;
blueToKeep( y, x ) = 999;
end
end
end
im = rgb2gray(cdata);
[X, map] = gray2ind(im);
im = ind2rgb(X, map);
for x=1:imWidth
for y=1:imHeight
if (redToKeep( y, x ) < 999)
im( y, x, 1 ) = 240;
end
if (greenToKeep( y, x ) < 999)
im( y, x, 2 ) = greenToKeep( y, x );
end
if (blueToKeep( y, x ) < 999)
im( y, x, 3 ) = blueToKeep( y, x );
end
end
end
imshow(im);
3 réponses
figure
pic = imread('EcyOd.jpg');
for mm = 1:size(pic,1)
for nn = 1:size(pic,2)
if pic(mm,nn,1) < 80 || pic(mm,nn,2) > 80 || pic(mm,nn,3) > 100
gsc = 0.3*pic(mm,nn,1) + 0.59*pic(mm,nn,2) + 0.11*pic(mm,nn,3);
pic(mm,nn,:) = [gsc gsc gsc];
end
end
end
imshow(pic)
une option qui améliore grandement la qualité de l'image résultante est de convertir à un espace de couleur différent afin de sélectionner plus facilement vos couleurs. En particulier, le espace de couleur HSV définit les couleurs des pixels en fonction de leur teinte (couleur), la saturation (la quantité de couleur), et la valeur (la luminosité de la couleur).
par exemple, vous pouvez convertir votre image RVB en espace HSV en utilisant la fonction rgb2hsv
, trouver des pixels avec des teintes qui span ce que vous voulez définir comme des couleurs "non-rouges" (comme, disons, 20 degrés à 340 degrés), mettez la saturation pour ces pixels à 0 (donc ils sont en niveaux de gris), puis convertissez l'image de nouveau à l'espace RVB en utilisant la fonction hsv2rgb
:
cdata = imread('EcyOd.jpg'); % Load image
hsvImage = rgb2hsv(cdata); % Convert the image to HSV space
hPlane = 360.*hsvImage(:, :, 1); % Get the hue plane scaled from 0 to 360
sPlane = hsvImage(:, :, 2); % Get the saturation plane
nonRedIndex = (hPlane > 20) & ... % Select "non-red" pixels
(hPlane < 340);
sPlane(nonRedIndex) = 0; % Set the selected pixel saturations to 0
hsvImage(:, :, 2) = sPlane; % Update the saturation plane
rgbImage = hsv2rgb(hsvImage); % Convert the image back to RGB space
et voici l'image résultante:
remarquez comment, comparé à la solution de zellus, vous pouvez facilement maintenir les tons rose clair sur les fleurs. Avis aussi que tons brunâtres sur la tige et le sol ont disparu.
pour un exemple cool de sélection d'objets à partir d'une image basée sur leurs propriétés de couleur, vous pouvez consulter Steve Eddins blog post Les Deux Amigos qui décrit une solution de Brett Shoelson à MathWorks pour extraire un "amigo" d'une image.
Une remarque sur la sélection de plages de couleurs...
une chose supplémentaire que vous pouvez faire peut vous aider à sélectionner des gammes de couleurs est de regarder un histogramme des teintes (i.e. hPlane
from above) présents dans les pixels de votre image HSV. Voici un exemple qui utilise les fonctions histc
(ou le recommandé histcounts
, si disponible) et bar
:
binEdges = 0:360; % Edges of histogram bins
hFigure = figure(); % New figure
% Bin pixel hues and plot histogram:
if verLessThan('matlab', '8.4')
N = histc(hPlane(:), binEdges); % Use histc in older versions
hBar = bar(binEdges(1:end-1), N(1:end-1), 'histc');
else
N = histcounts(hPlane(:), binEdges);
hBar = bar(binEdges(1:end-1), N, 'histc');
end
set(hBar, 'CData', 1:360, ... % Change the color of the bars using
'CDataMapping', 'direct', ... % indexed color mapping (360 colors)
'EdgeColor', 'none'); % and remove edge coloring
colormap(hsv(360)); % Change to an HSV color map with 360 points
axis([0 360 0 max(N)]); % Change the axes limits
set(gca, 'Color', 'k'); % Change the axes background color
set(hFigure, 'Pos', [50 400 560 200]); % Change the figure size
xlabel('HSV hue (in degrees)'); % Add an x label
ylabel('Bin counts'); % Add a y label
Et voici le pixel de la couleur de l'histogramme:
remarquez comment l'image originale contient principalement du rouge, du vert, et pixels de couleur jaune (avec quelques pixels orange). Il n'y a presque pas de pixels de couleur cyan, bleu, indigo ou magenta. Notez aussi que les gammes que j'ai sélectionnées ci-dessus (20 à 340 degrés) font un bon travail d'exclure la plupart de tout ce qui ne fait pas partie des deux grands groupes rouges à chaque extrémité.
Je ne sais pas vraiment comment fonctionne matlab donc je ne peux pas vraiment commenter le code, mais peut-être que cela aidera à expliquer un peu comment les couleurs RGB fonctionnent.
Lorsqu'on utilise les couleurs RVB,on peut faire une échelle de gris en s'assurant que les valeurs de R, G et b sont toutes les mêmes. Donc, fondamentalement, ce que vous voulez faire est de détecter si un pixel est Rouge, quand pas juste faire R,G et B le même (vous pouvez utiliser une moyenne des 3 pour un résultat rudimentaire).
la partie plus dure est comment détecter si un pixel est réellement rouge, vous ne pouvez pas juste vérifier si un pixel est haut dans la valeur de R car il peut encore être une autre couleur, et une valeur de R faible peut juste signifier un rouge plus foncé.
donc vous pouvez faire quelque chose comme ceci: (je n'ai pas de matlab, donc en assumant la syntaxe):
red = cdata( y, x, 1 ); green = cdata( y, x, 2 ); blue = cdata(y, x, 3); if (red < (blue * 1.4) || red < (green * 1.4) ) { avg = (red + green + blue) / 3; cdata(y, x, 1) = avg; cdata(y, x, 2) = avg; cdata(y, x, 3) = avg; }
Il y a probablement de meilleures façons de détecter et rouge pour obtenir un gris moyen, mais c'est un début ;)