matlab - saber - ¿Cómo puedo convertir una imagen RGB a escala de grises pero mantener un solo color?
reconocimiento de colores rgb matlab (3)
Intento crear un efecto similar a Sin City u otras películas donde eliminan todos los colores, excepto uno de una imagen.
Tengo una imagen RGB que quiero convertir a escala de grises, pero quiero mantener un solo color.
Esta es mi foto:
Quiero mantener el color rojo El resto debe ser en escala de grises.
Esto es lo que mi código produce hasta ahora (se puede ver que las áreas son correctas, no sé por qué son blancas en lugar de rojas):
Aquí está mi código hasta ahora:
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);
Realmente no sé cómo funciona Matlab, así que no puedo comentar el código, pero quizás esto ayude a explicar un poco cómo funcionan los colores RGB.
Al usar colores RGB, se puede hacer una escala de grises asegurándose de que los valores para R, G y B sean 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 se 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 de R solo puede significar un rojo más oscuro.
entonces podrías hacer algo como esto: (No tengo matlab, así que supongo 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 haya mejores formas de detectar rojo y obtener un gris promedio, pero es un comienzo;)
Una opción que mejora en gran medida la calidad de la imagen resultante es convertirla en un espacio de color diferente para seleccionar más fácilmente sus colores. En particular, el espacio de color HSV define los colores de los píxeles en términos de su tono (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 usando la función rgb2hsv
, buscar píxeles con matices que abarcan lo que quiere definir como colores "no rojos" (como, por ejemplo, 20 grados a 340 grados), establecer la saturación para esos píxeles a 0 (para que sean en escala de grises), luego hsv2rgb
nuevo a espacio RGB usando 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í está la imagen resultante:
Observe cómo, en comparación con la solución de zellus , puede mantener fácilmente los tonos rosas claros 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 en función de sus propiedades de color, puede consultar la publicación del blog de 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 cómo seleccionar rangos de color ...
Una cosa más que puede hacer que puede ayudarlo a seleccionar rangos de colores es mirar un histograma de los matices (es decir, hPlane
desde arriba) presente en los píxeles de su imagen HSV. Aquí hay un ejemplo que usa las funciones histc
(o los histcounts
recomendados, si están disponibles) y la 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 píxeles resultante:
Observe cómo la imagen original contiene principalmente 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.
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)