2010-10-31 35 views
33

Estoy intentando crear un efecto similar al Sin City u otras películas en las que se eliminan todos los colores excepto uno de una imagen.¿Cómo puedo convertir una imagen RGB a escala de grises pero mantener un solo color?

que tienen una imagen RGB que quiero convertir a escala de grises, pero quiero guardar un color.

Esta es mi foto:

alt text

Quiero mantener el color rojo. El resto debe ser en escala de grises.

Esto es lo que da salida a mi código hasta el momento (se puede ver que las áreas son correctos, no sé por qué ellos son de color blanco en lugar de rojo, aunque):

alt text

Aquí está mi código hasta el momento:

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

Parece Matlab está proporcionando una solución, pero sería interesante ver un campo de código de este ... Gracias – gary

Respuesta

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

Gracias, esa es una manera mucho más fácil de hacerlo. Sin embargo, ¿cómo obtuviste esos coeficientes (0.3, 0.59, 0.11)? No entiendo eso. –

+3

@Richard Knop: Esa es la fórmula utilizada por [RGB2GRAY] (http://www.mathworks.com/help/toolbox/images/ref/rgb2gray.html), tal como se detalla en la documentación. – gnovice

+0

@ Richard Knop: http://www.mathworks.com/help/toolbox/images/ref/rgb2gray.html desplácese un poco hacia abajo hasta que llegue al párrafo * 'Algorithm' *. Pero también hay otros en la web. – zellus

2

que no se sabe muy bien cómo funciona Matlab, así que no puedo comentar sobre el código, pero tal vez esto ayude a explicar un poco cómo funcionan los colores RGB.

Al utilizar colores RGB una escala de grises se pueden hacer por asegurándose de que los valores de R, G y B son todos iguales. Entonces, básicamente, lo que quieres hacer es detectar si un píxel es rojo, cuando no solo haces R, G y B iguales (puedes usar un promedio de 3 para obtener un resultado rudimentario).

La parte más difícil es cómo detectar si un píxel es realmente rojo, no puede simplemente verificar si un píxel es alto en el valor R ya que todavía puede ser de otro color, y un valor bajo R solo puede significar un más oscuro rojo.

por lo que podría hacer algo como esto: (no tengo Matlab, por lo que suponiendo sintaxis):

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

probablemente hay mejores maneras de detectar rojo y de obtener un gris medio, pero es una Inicio;)

+0

. He cambiado un poco mi código y ya obtengo algunos resultados, pero las áreas que deberían ser rojas son blancas. Verifique mi pregunta actualizada –

+0

Sus colores son blancos porque eliminó los valores originales de verde y azul para los píxeles que desea conservar. Es por eso que en el ejemplo solo modifica la matriz para los píxeles que desea convertir en gris y deja el resto solo. – Doggett

+0

Tipo de implementado su algoritmo sin notar su publicación. Espero que no te moleste. – zellus

82

una opción que mejora notablemente la calidad de la imagen resultante es la de convertir a un espacio de color diferente con el fin de seleccionar más fácilmente los colores. En particular, el HSV color space define colores de los píxeles en términos de su color (el color), la saturación (la cantidad de color), y el valor (el brillo del color).

Por ejemplo, puede convertir su imagen RGB al espacio HSV utilizando la función rgb2hsv, encuentre píxeles con matices que abarquen lo que desea definir como colores "no rojos" (como, por ejemplo, 20 grados a 340 grados) , ajustar la saturación de los píxeles a 0 (por lo que son en escala de grises), a continuación, convertir la imagen al espacio RGB utilizando la función 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 

Y aquí es la imagen resultante:

alt text

Aviso cómo, en comparación con the solution from zellus, se puede mantener fácilmente los tonos de color rosa claro en las flores. Observe también que los tonos marrones en el tallo y en el suelo también desaparecen.

Para un buen ejemplo de selección de objetos de una imagen basada en sus propiedades de color, puede consultar la publicación del blog Steve Eddins The Two Amigos que describe una solución de Brett Shoelson en MathWorks para extraer un "amigo" de una imagen.


Una nota sobre la selección de gamas de colores ...

Una cosa adicional que puede hacer que pueden ayudarle a seleccionar gamas de colores es mirar a un histograma de los tonos (es decir hPlane desde arriba) presente en los píxeles de su imagen HSV. He aquí un ejemplo que utiliza las funciones histc (o el histcounts recomendada, si está disponible) y 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 

Y aquí está el histograma de color de pixel resultante:

alt text

Aviso cómo la imagen original contiene en su mayoría píxeles de color rojo, verde y amarillo (con algunos de color naranja). Casi no hay píxeles de color cian, azul, índigo o magenta. Observe también que los rangos que seleccioné arriba (20 a 340 grados) hacen un buen trabajo al excluir casi todo lo que no es parte de los dos grandes grupos rojos en cada extremo.

+0

Gracias. Probaré eso. Mientras tanto, he actualizado mi pregunta. ¿Podrías echarle un vistazo? :) –

+3

+1 para apreciar su solución. Superior en resultado y código. – zellus

+0

Histogramas FTW. – Spike0xff

Cuestiones relacionadas