2010-10-31 5 views
33

J'essaye de créer un effet semblable à Sin City ou d'autres films où ils enlèvent toutes les couleurs sauf une d'une image.Comment puis-je convertir une image RVB en niveaux de gris mais conserver une couleur?

J'ai une image RVB que je veux convertir en niveaux de gris mais je veux garder une couleur.

Ceci est mon image:

alt text

Je veux garder la couleur rouge. Le reste devrait être en niveaux de gris.

C'est ce que mon code sorties à ce jour (vous pouvez voir que les zones sont correctes, je ne sais pas pourquoi ils sont blancs au lieu de rouge bien):

alt text

Voici mon code jusqu'à présent:

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); 
+0

Il semble Matlab fournit une solution, mais il serait intéressant de voir un terrain de code de cette ... – gary

Répondre

18
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) 

alt text

+0

Merci, c'est beaucoup plus facile de le faire. Comment avez-vous obtenu ces coefficients (0.3, 0.59, 0.11)? Je ne comprends pas ça. –

+3

@Richard Knop: C'est la formule utilisée par [RGB2GRAY] (http://www.mathworks.com/help/toolbox/images/ref/rgb2gray.html), comme indiqué dans la documentation. – gnovice

+0

@ Richard Knop: http://www.mathworks.com/help/toolbox/images/ref/rgb2gray.html faites défiler un peu jusqu'à ce que vous atteigniez le paragraphe * 'Algorithm' *. Mais il y en a d'autres sur le web aussi. – zellus

2

Je fais cela aiderai sais pas vraiment comment fonctionne Matlab je ne peux pas vraiment commenter le code, mais peut-être expliquer un peu comment fonctionnent les couleurs RVB. Lorsque vous utilisez des couleurs RVB, vous pouvez effectuer une échelle de gris en vous assurant que les valeurs de R, V et B sont les mêmes. Donc, fondamentalement, ce que vous voulez faire est de détecter si un pixel est rouge, quand ce n'est pas juste de faire R, G et B la même chose (vous pouvez utiliser une moyenne de 3 pour un résultat rudimentaire). Plus difficile est de savoir si un pixel est réellement rouge, vous ne pouvez pas simplement vérifier si un pixel est élevé dans la valeur R, car il peut encore être une autre couleur, et une faible valeur R peut simplement signifier une plus sombre rouge.

pour que vous puissiez faire quelque chose comme ceci: (Je n'ai pas Matlab, donc en supposant 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 rouge et d'obtenir un gris moyen, mais il est un start;)

+0

Merci. J'ai un peu changé mon code et j'ai déjà une sortie mais les zones qui devraient être rouges sont blanches. Vérifiez ma question mise à jour. –

+0

Vos couleurs sont blanches car vous avez supprimé les valeurs d'origine du vert et du bleu pour les pixels que vous souhaitez conserver. C'est pourquoi dans l'exemple, il ne fait que modifier la matrice pour les pixels que vous voulez rendre gris et laisse le reste seul. – Doggett

+0

Type de implémenté votre algorithme sans remarquer votre message. J'espère que cela ne vous dérange pas. – zellus

82

Une option qui améliore grandement la qualité de l'image résultante consiste à convertir dans un espace de couleur différent afin de sélectionner plus facilement vos couleurs. En particulier, le HSV color space définit les couleurs de pixel en termes de couleur (la couleur), de saturation (la quantité de couleur) et de valeur (la luminosité de la couleur). Par exemple, vous pouvez convertir votre image RVB en espace HSV à l'aide de la fonction rgb2hsv, pour trouver des pixels dont les teintes correspondent à ce que vous voulez définir comme couleurs «non-rouges» (par exemple, 20 degrés à 340 degrés) , régler la saturation pour les pixels à 0 (donc ils sont en niveaux de gris), puis de convertir l'image à l'espace RGB 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:

alt text

Notez comment, par rapport à the solution from zellus, vous pouvez facilement maintenir les tons rose clair sur les fleurs. Notez également que les tons brunâtres sur la tige et le sol ont disparu.Pour un bon exemple de sélection d'objets à partir d'une image basée sur leurs propriétés de couleur, vous pouvez consulter le blog The Two Amigos de Steve Eddins qui décrit une solution de Brett Shoelson à MathWorks pour extraire un "amigo" d'une image.


Une note sur la sélection des gammes de couleurs ...

Une chose supplémentaire que vous pouvez faire qui peut vous aider à sélectionner les gammes de couleurs est de regarder un histogramme des couleurs (c.-à-hPlane ci-dessus) présent dans les pixels de votre image HSV. Voici un exemple qui utilise les fonctions histc (ou recommandé histcounts, le cas échéant) 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 l'histogramme des couleurs de pixel résultant:

alt text

Remarquez comment l'image originale contient principalement des pixels rouges, verts et jaunes (avec quelques pixels orange). Il n'y a presque pas de pixels de couleur cyan, bleu, indigo ou magenta. Notez également que les plages 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é.

+0

Merci. Je vais essayer ça. En attendant, j'ai mis à jour ma question. Pourriez-vous vérifier? :) –

+3

+1 pour apprécier votre solution. Supérieur dans le résultat et le code. – zellus

+0

Histogrammes FTW. – Spike0xff

Questions connexes