如何将RGB图像转换为灰度图像但保持一种颜色?
image-processing
matlab
5
0

我正在尝试创建一种类似于《 罪恶之城》或其他电影的效果,其中它们会删除图像中除一种颜色以外的所有颜色。

我有一个RGB图像,我想将其转换为灰度,但我想保留一种颜色。

这是我的照片:

替代文字

我想保持红色。其余应为灰度。

到目前为止,这是我的代码输出的内容(您可以看到这些区域是正确的,但是我不知道为什么它们是白色而不是红色):

替代文字

到目前为止,这是我的代码:

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);
参考资料:
Stack Overflow
收藏
评论
共 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;
}

可能有更好的方法来检测红色并获得平均灰色,但这只是一个开始;)

收藏
评论

一种可以大大改善生成的图像质量的选项是转换为其他颜色空间,以便更轻松地选择颜色。特别是, HSV颜色空间根据像素的色相(颜色),饱和度(颜色量)和值(颜色的亮度)来定义像素颜色。

例如,您可以使用rgb2hsv函数将RGB图像转换为HSV空间,找到具有跨越您要定义为“非红色”颜色(例如20度到340度)的色相的像素,设置饱和度对于那些像素为0(因此它们是灰度),然后使用函数hsv2rgb将图像转换回RGB空间:

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

这是结果图像:

替代文字

请注意,与zellus的解决方案相比,您可以轻松地维持花朵上的浅粉色调。还要注意,茎和地面上的褐色调也消失了。

有关根据对象的颜色属性从图像中选择对象的出色示例,请查看Steve Eddins博客文章《两个朋友》 ,其中描述了MathWorks的Brett Shoelson提出的从图像中提取一个“ amigo”的解决方案。


有关选择颜色范围的说明...

您可以做的另一件事是帮助您选择颜色范围,这是查看HSV图像像素中出现的色调(即,上方的hPlane )的直方图。这是一个使用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

这是生成的像素颜色直方图:

替代文字

请注意,原始图像如何主要包含红色,绿色和黄色的像素(以及一些橙色的像素)。几乎没有青色,蓝色,靛蓝或洋红色的像素。还要注意,我在上面选择的范围(20到340度)可以很好地排除不属于两端两个大红色群集的大部分内容。

收藏
评论
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)

替代文字

收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号