Как я могу преобразовать изображение RGB в оттенки серого, но сохранить один цвет? - PullRequest
35 голосов
/ 31 октября 2010

Я пытаюсь создать эффект, подобный Город грехов или другим фильмам, в которых удаляются все цвета, кроме одного, из изображения.

У меня есть изображение RGB, которое я хочу преобразовать в оттенки серого, но хочу сохранить один цвет.

Это моя картинка:

alt text

Я хочу сохранить красный цвет. Остальное должно быть в оттенках серого.

Это то, что мой код выводит до сих пор (вы можете видеть, что области правильные, хотя я не знаю, почему они белые, а не красные):

alt text

Вот мой код:

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

Ответы [ 3 ]

87 голосов
/ 31 октября 2010

Одним из вариантов, который значительно улучшает качество получаемого изображения, является преобразование в другое цветовое пространство для более удобного выбора цветов.В частности, цветовое пространство HSV определяет цвета пикселей с точки зрения их оттенка (цвет), насыщенности (количество цвета) и значения (яркость цвета).

Например, вы можете преобразовать ваше изображение RGB в пространство HSV с помощью функции rgb2hsv, найти пиксели с оттенками, которые охватывают то, что вы хотите определить как «не красные» цвета (например, 20 градусов)до 340 градусов), установите насыщенность для этих пикселей равной 0 (чтобы они были в оттенках серого), затем преобразуйте изображение обратно в пространство RGB с помощью функции 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

И вот результирующее изображение:

alt text

Обратите внимание, что по сравнению с раствором от Zellus вы можете легко поддерживать светло-розовые тона на цветах.Обратите также внимание на то, что коричневатые тона на стебле и на земле также исчезли.

Интересный пример выбора объектов из изображения на основе их цветовых свойств вы можете проверить в блоге Стива Эддинса The TwoAmigos , который описывает решение от Бретта Шоелсона из MathWorks для извлечения одного "amigo" из изображения.


Примечание по выбору цветовых диапазонов ...

Еще одна вещь, которую вы можете сделать, которая может помочь вам выбрать диапазоны цветов, - это посмотреть гистограмму оттенков (то есть hPlane сверху), присутствующих в пикселях вашего изображения HSV.Вот пример, в котором используются функции histc (или рекомендуемые histcounts, если доступны) и 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

А вот итоговая гистограмма цвета пикселей:

alt text

Обратите внимание, что исходное изображение содержит в основном пиксели красного, зеленого и желтого цвета (с несколькими оранжевыми).Пикселей голубого, синего, индиго или пурпурного цвета почти нет.Также обратите внимание, что диапазоны, которые я выбрал выше (от 20 до 340 градусов), отлично справляются с исключением большинства всего, что не является частью двух больших красных кластеров на обоих концах.

19 голосов
/ 31 октября 2010
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

2 голосов
/ 31 октября 2010

Я действительно не знаю, как работает Matlab, поэтому я не могу комментировать код, но, возможно, это поможет немного объяснить, как работают цвета RGB.

При использовании цветов RGB шкала серого можетсделать, убедившись, что значения для R, G и B одинаковы.Поэтому в основном вы хотите определить, является ли пиксель красным, а не просто сделать R, G и B одинаковыми (вы можете использовать среднее значение 3 для элементарного результата).

СложнееКак определить, является ли пиксель действительно красным, вы не можете просто проверить, является ли пиксель высоким в значении R, поскольку он все еще может быть другого цвета, а низкое значение R может означать только более темный красный цвет.

чтобы вы могли сделать что-то вроде этого: (у меня нет matlab, поэтому с синтаксисом):

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

Возможно, есть лучшие способы обнаружить красный и получить средний серый, но это начало;)

...