如何将RGB图像转换为灰度,但保持一种颜色?

我试图创造一个类似于罪恶城市或其他电影的效果,他们删除除了图像以外的所有颜色。

我有一个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); 
 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) 

替代文字

一个大大提高了图像质量的选项是转换到不同的颜色空间,以便更容易地select你的颜色。 特别是, HSV颜色空间根据其色调(颜色),饱和度(颜色的量)和值(颜色的亮度)来定义像素颜色。

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

 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的解决scheme相比,您可以轻松地在花朵上保持浅粉色调。 还要注意,茎和地面上的褐色色调也不见了。

对于从图像中select对象的很酷的示例,您可以查看Steve Eddins的博客文章The Two Amigos ,它描述了MathWorks的Brett Shoelson解决scheme,用于从图像中提取一个“amigo”。

关于select颜色范围的注意事项…

你可以做的另一件事可以帮助你select颜色范围是看你的HSV图像的像素中存在的色调直方图。 下面是一个使用函数HISTC和BAR的例子:

 binEdges = 0:360; %# Edges of histogram bins N = histc(hPlane(:),binEdges); %# Bin the pixel hues from above hBar = bar(binEdges(1:end-1),N(1:end-1),'histc'); %# Plot the histogram 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(gcf,'Pos',[50 400 560 200]); %# Change the figure size xlabel('HSV hue (in degrees)'); %# Add an x label ylabel('Bin counts'); %# Add ay label 

这里是最终的像素颜色直方图:

替代文字

请注意,原始图像主要包含红色,绿色和黄色的像素(有几个橙色像素)。 几乎没有青色,蓝色,靛蓝或洋红色的像素。 还要注意,我上面select的范围(20到340度)很好地排除了大部分不属于两个大红色聚类的一部分的任何一端。

我真的不知道matlab是如何工作的,所以我不能对代码进行真正的评论,但也许这将有助于解释RGB颜色是如何工作的。

当使用RGB颜色时,可以通过确保R,G和B的值全部相同来实现灰度。 所以基本上你想要做的是检测一个像素是否是红色的,而不仅仅是使R,G和B相同(你可以使用3的平均值作为基本结果)。

更难的部分是如何检测一个像素是否真的是红色的,你不能只是检查一个像素是否在R值高,因为它仍然可以是另一种颜色,低R值可能意味着更深的红色。

所以你可以做这样的事情:(我没有matlab,所以假设语法):

 red = cdata(y,x,1);
绿色= cdata(y,x,2);
 blue = cdata(y,x,3);

 if(red <(blue * 1.4)|| red <(green * 1.4))
 {
     avg =(红+绿+蓝)/ 3;
     cdata(y,x,1)= avg;
     cdata(y,x,2)= avg;
     cdata(y,x,3)= avg;
 }

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