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

35

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

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

Это моя фотография:

Изображение 550

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

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

Изображение 551

Вот мой код:

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
    Кажется, Matlab предлагает решение, но было бы интересно увидеть код-гольф этого ...
Теги:
image-processing
rgb
colors
grayscale

3 ответа

19
Лучший ответ
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)

Изображение 6357

  • 0
    Спасибо, это намного проще. Как вы получили эти коэффициенты (0,3, 0,59, 0,11), хотя? Я этого не понимаю
  • 3
    @Richard Knop: эта формула используется RGB2GRAY , как указано в документации.
Показать ещё 2 комментария
83

Один из вариантов, который значительно улучшает качество результирующего изображения, - это преобразование в другое цветовое пространство, чтобы легче выбирать цвета. В частности, цветовое пространство 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

И вот получившееся изображение:

Изображение 6358

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

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


Заметка о выборе цветовых диапазонов...

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

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

Изображение 6359

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

  • 0
    Благодарю. Я попробую это. Тем временем я обновил свой вопрос. Не могли бы вы проверить это? :)
  • 4
    +1 за оценку вашего решения. Превосходный результат и код.
Показать ещё 1 комментарий
2

Я не знаю, как работает 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;
}

Есть, вероятно, лучшие способы обнаружить красный цвет и получить средний серый цвет, но это начало;)

  • 0
    Благодарю. Я немного изменил свой код, и я уже получил вывод, но области, которые должны быть красными, вместо этого белые. Проверьте мой обновленный вопрос.
  • 0
    Ваши цвета белые, потому что вы удалили исходные значения зеленого и синего для пикселей, которые хотите сохранить. Вот почему в примере он изменяет матрицу только для пикселей, которые вы хотите сделать серым, и оставляет все остальное в покое.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню