web-dev-qa-db-fra.com

Comment puis-je convertir une image RVB en niveaux de gris mais conserver 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 RVB que je veux convertir en niveaux de gris mais je veux garder une couleur.

C'est ma photo:

alt text

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

C'est ce que mon code produit jusqu'à présent (vous pouvez voir que les zones sont correctes, je ne sais pas pourquoi elles sont blanches au lieu de rouges):

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);
36
Richard Knop
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
zellus

Une option qui améliore considérablement la qualité de l'image résultante est de la convertir dans un espace colorimétrique différent afin de sélectionner plus facilement vos couleurs. En particulier, le espace colorimétrique HSV définit les couleurs des pixels en termes de teinte (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 en utilisant la fonction rgb2hsv , recherchez des pixels avec des teintes qui s'étendent sur ce que vous voulez définir comme des couleurs "non rouges" (comme, par exemple, 20 degrés à 340 degrés), définissez la saturation de ces pixels sur 0 (ils sont donc en niveaux de gris) , puis reconvertissez l'image en espace RVB à l'aide de 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, par rapport à la solution de 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 également disparu.

Pour un exemple sympa de sélection d'objets dans une image en fonction de leurs propriétés de couleur, vous pouvez consulter l'article de blog de Steve Eddins The Two Amigos qui décrit une solution de Brett Shoelson au MathWorks pour extraire un "amigo" à partir d'une image.


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

Une autre chose que vous pouvez faire pour vous aider à sélectionner des gammes de couleurs est de regarder un histogramme des teintes (c'est-à-dire hPlane d'en haut) présentes dans les pixels de votre image HSV. Voici un exemple qui utilise les fonctions histc (ou les recommandations histcounts , si disponibles) 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 de couleur des pixels résultant:

alt text

Remarquez comment l'image d'origine contient principalement des pixels de couleur rouge, verte et jaune (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é.

87
gnovice

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 le fonctionnement des couleurs RVB.

Lorsque vous utilisez des couleurs RVB, une échelle de gris peut être créée en vous assurant que les valeurs de R, G et B sont identiques. Donc, fondamentalement, ce que vous voulez faire est de détecter si un pixel est rouge, alors ne faites pas que R, G et B de la même manière (vous pouvez utiliser une moyenne des 3 pour un résultat rudimentaire).

La partie la 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 toujours être une autre couleur, et une valeur R faible peut simplement signifier un rouge plus foncé.

vous pouvez donc faire quelque chose comme ceci: (je n'ai pas de matlab, donc en supposant la syntaxe):

 rouge = cdata (y, x, 1); 
 vert = cdata (y, x, 2); 
 bleu = cdata (y, x, 3); 
 
 si (rouge <(bleu * 1,4) || rouge <(vert * 1,4)) 
 {
 moy = (rouge + vert + bleu)/3; 
 cdata (y, x, 1) = moy; 
 cdata (y, x, 2) = moy; 
 cdata (y, x, 3) = moy; 
} 

Il existe probablement de meilleures façons de détecter le rouge et d'obtenir un gris moyen, mais c'est un début;)

2
Doggett