如何将RGB直方图转换为色谱?

时间:2017-04-19 18:12:14

标签: matlab image-processing histogram octave matlab-figure

如何转换图像的RGB直方图以创建显示组合颜色以及正确颜色波长范围的直方图?

示例代码:

pkg load image
f=imread('/tmp/marbles.jpg');
f=uint8(f); %need to convert back to uint8 to show picture

%Split into RGB Channels
f_red = f(:,:,1);
f_green = f(:,:,2);
f_blue = f(:,:,3);

%Get histValues for each channel
[y_f_red, x] = imhist(f_red);
[y_f_green, x] = imhist(f_green);
[y_f_blue, x] = imhist(f_blue);
subplot (2,1,1); imshow(f);
subplot (2,1,2); plot(x, y_f_red, 'r', x, y_f_green, 'g', x, y_f_blue, 'b');

示例图像以及代码生成的单独RGB直方图:

Current Histogram

我试图让直方图看起来像下图,但颜色从红色变为蓝色:

enter image description here

另一个图片示例:

Histogram I want

PS:我使用的Octave 4.0与MATLAB非常相似。

3 个答案:

答案 0 :(得分:7)

在标准颜色表示(如RGB或HSV)和光谱波长之间进行转换存在巨大障碍:许多颜色无法用单一波长的光表示。品红色,粉红色,棕色或任何灰度色等颜色代表不同波长的混合物。因此,生成等效光谱波长是一项复杂得多的工作(您可能会发现一些有用的想法和链接herehere)。

创建颜色的直方图本身可能是更好的方法(在my other answers之一中说明),但如果您真的想以简单的方式将颜色与波长联系起来,您可以尝试以下方法......

第一步是将RGB值转换为HSV值,然后创建色调通道的直方图。我会调整my answer from here的一部分来做到这一点。下一步是将色调映射到光的波长,使用从this answer改编的相当粗略的近似值:

rgbImage = imread('test_image.png');  % Load image
hsvImage = rgb2hsv(rgbImage);         % Convert the image to HSV space
hPlane = 360.*hsvImage(:, :, 1);      % Get the hue plane scaled from 0 to 360

binEdges = 0:270;                     % Edges of histogram bins
N = histc(hPlane(:), binEdges);       % Bin the pixel hues from above
wavelength = 620-(170/270).*(0:269);  % Approximate wavelength

hBar = bar(wavelength, N(1:end-1), 'histc');  % Plot the histogram

set(hBar, 'CData', 270:-1:1, ...    % 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([450 620 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('Wavelength (nm)');          % Add an x label
ylabel('Bin counts');               % Add a y label

注意:为了使上述内容在Octave中正常工作,可能需要将set(hBar, ...行更改为以下内容:

set(hBar, 'FaceColor', 'flat', 'EdgeColor', 'none');
set(get(hBar, 'Children'), 'CData', 270:-1:1, 'CDataMapping', 'direct');

这里是直方图:

enter image description here

然而,这有一个问题。如果我们改为使用my other answer中的代码来绘制所有色调值的直方图,我们就会得到这个:

enter image description here

请注意,当我们丢弃部分色调范围以转换为波长时,会有一大群洋红色,粉红色和红色像素被排除在外(它们不会对应于光谱中的单个波长) )。将这些结合到结果中需要从色调到波长的更复杂的转换。

答案 1 :(得分:3)

除非满足图像和光线的某些物理属性,否则无法将 RGB 转换为波长。无论如何,你可以通过反转伪造这个:

如果你不知道怎么看:

但结果与物理波长直方图不同......为此你需要通过旋转棱镜光学系统或一组带通滤波器来获取多波段图像......

<强> PS。 HSV 远非准确......

Btw。最简单的方法是从光谱颜色创建调色板并将输入图像转换为它(索引颜色),然后创建按波长(和/或颜色索引)排序的直方图...

答案 2 :(得分:1)

基于gnovices回答但是使用图像而不是条形图(在我的系统上取0.12秒):

rgbImage = imread ("17S9PUK.jpg");
hsvImage = rgb2hsv(rgbImage);

hPlane = 360 .* hsvImage(:, :, 1); 
binEdges = 1:360;
N = histc (hPlane(:), binEdges);

cm = permute (hsv (360), [3 1 2]);
img = repmat (cm, max(N), 1);

row_index = max(N) - N';
sp = sparse (row_index(row_index>0), (1:360)(row_index>0), true);
mask = flipud (cumsum (sp));

img(repmat (logical(1 - full(mask)), [1 1 3])) = 0;
image (img)
set (gca, "ydir", "normal");
xlabel('hue');
ylabel('Bin counts');

output of script