Подтвердить что ты не робот

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

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

У меня есть изображение 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);
4b9b3361

Ответ 1

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

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

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

alt text

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

Ответ 3

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

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