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:

alt text

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

alt text

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);
34
demandé sur Peter O. 2010-10-31 19:33:03

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)

alt text

19
répondu zellus 2010-10-31 17:41:52

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:

alt text

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:

alt text

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é.

83
répondu gnovice 2018-02-19 15:52:58

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

2
répondu Doggett 2010-10-31 17:19:48