Domanda

Sto cercando di creare un effetto simile a Sin City o di altri film dove si rimuovono tutti i colori tranne uno da un'immagine.

Ho un'immagine RGB, che voglio convertire in scala di grigio, ma voglio mantenere un colore.

Questa è la mia immagine:

alt text

Voglio mantenere il colore rosso. Il resto dovrebbe essere in scala di grigi.

Questo è ciò che i miei uscite di codice finora (si può vedere che le zone siano corrette, non so il motivo per cui sono di colore bianco anziché rosso però):

alt text

Ecco il mio codice finora:

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);
È stato utile?

Soluzione

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

Altri suggerimenti

Una possibilità che migliora notevolmente la qualità dell'immagine risultante è quello di convertire in uno spazio colore diverso, al fine di selezionare più facilmente i tuoi colori. In particolare, il definisce i colori dei pixel in termini di tonalità (colore), saturazione (la quantità di colore), e il valore (la luminosità del colore).

Ad esempio, è possibile convertire l'immagine RGB allo spazio HSV utilizzando la funzione rgb2hsv , trovare pixel con sfumature che si estendono ciò che si desidera definire come i colori "non-rossi" (come, ad esempio, 20 gradi a 340 gradi), regola la saturazione per quei pixel a 0 (in modo che siano in scala di grigi), quindi convertire l'immagine di nuovo allo spazio RGB utilizzando la funzione 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

E qui è l'immagine risultante:

alt text

Si noti come, rispetto al la soluzione dalla zellus , si può facilmente mantenere i toni rosa-chiaro sui fiori. Si noti inoltre che i toni marrone sullo stelo e la terra sono andati pure.

Per un esempio fresco di selezione degli oggetti da un'immagine in base alle loro proprietà di colore, è possibile controllare Steve Eddins post del blog Il Two Amigos che descrive una soluzione da Brett Shoelson ai MathWorks per estrarre un "amigo" da un'immagine.


Una nota sulla selezione colore va ...

Una cosa aggiuntiva che si può fare, che può aiutare a selezionare le gamme di colori è quello di guardare un istogramma dei colori (cioè hPlane dall'alto) presente nei pixel della vostra immagine HSV. Ecco un esempio che utilizza le funzioni histc (o la raccomandata histcounts , se disponibile) e 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

Ed ecco la risultante istogramma colore dei pixel:

alt text

Si noti come l'immagine originale contiene principalmente rosso, verde, giallo e pixel colorati (con un paio di quelli arancioni). Ci sono quasi nessun ciano, blu, indaco, o magenta pixel colorati. Si noti inoltre che gli intervalli ho selezionato in precedenza (da 20 a 340 gradi) fanno un buon lavoro di escludere la maggior parte tutto ciò che non fa parte dei due grandi cluster rossi alle due estremità.

Io non so davvero come funziona MATLAB quindi non posso commentare sul codice, ma forse questo aiuterà a spiegare un po 'modo i colori RGB di lavoro.

Quando si utilizza colori RGB una scala di grigi può essere fatto facendo che i valori di R, G e B sono tutti uguali. Quindi, in pratica ciò che si vuole fare è rilevare se un pixel è rosso, quando non è solo fare R, G e B lo stesso (è possibile utilizzare una media del 3 per un risultato rudimentale).

parte Harder è come rilevare se un pixel è in realtà rosso, non si può semplicemente verificare se un pixel è alto il valore di R in quanto può essere ancora un altro colore, e un basso valore di R può solo significare un rosso più scuro .

in modo che si possa fare qualcosa di simile: (non ho MATLAB, assumendo così la sintassi):

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

Ci sono modi probabilmente meglio per rilevare rosso e per ottenere un grigio medio, ma è un inizio;)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top