How can I convert an RGB histogram into a color spectrum?

て烟熏妆下的殇ゞ 提交于 2019-12-07 15:02:30

问题


How can I convert an RGB histogram of an image to create a histogram showing the combined colors along with correct color wavelength range?

Example code:

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');

Example image along with separate RGB histogram the code produces:

I'm trying to get the histogram to look like the image below but have the colors go from red to blue:

Another image example:

PS: I'm using Octave 4.0 which is very similar to MATLAB.


回答1:


There's a huge hurdle to converting between standard color representations (like RGB or HSV) and spectral wavelength: many colors can't be represented by a single wavelength of light. Colors such as magenta, pink, brown, or any grayscale color represent mixtures of different wavelengths. Generating an equivalent spectral wavelength is therefore a much more complicated endeavor (you may find some useful ideas and links here and here).

Creating histograms of the colors themselves may be a better way to go (illustrated in one of my other answers), but if you really want to relate color to wavelength in a simple fashion you can try the following...

A first step will be to convert RGB values to HSV values, then create a histogram of the hue channel. I'll adapt part of my answer from here to do that. The next step will be to map hues to wavelengths of light, using some rather gross approximations adapted from 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

NOTE: For the above to work properly in Octave, it may be necessary to change the set(hBar, ... line to the following:

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

And here's the histogram:

There is, however, one issue with this. If we instead use the code exactly as it is in my other answer to plot the histogram of all the hue values, we would get this:

Note that there is a big cluster of magenta, pink, and reddish pixels that gets excluded when we toss out part of the hue range to convert to wavelengths (they don't correspond to a single wavelength in the light spectrum). Incorporating these into the results would require a more complicated conversion from hue to wavelength.




回答2:


you can not convert RGB to wavelength unless some physical properties of the image and light is met. Anyway you can fake this by inversing:

  • RGB values of visible spectrum

if you do not know how look at:

  • Reverse complex 2D lookup table

But the result will not be the same as physical wavelengths histogram ... For that you would need multi-band image acquisition either by rotating prism optics or by set of bandpass filters ...

PS. HSV is far from accurate ...

Btw. the easiest way to do this is create palette from the spectral colors and convert your input image to it (indexed colors) and then just create histogram sorted by wavelength (and or color index)...




回答3:


Based on gnovices answer but with an image instead of bar (take 0.12s on my system):

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');



来源:https://stackoverflow.com/questions/43503190/how-can-i-convert-an-rgb-histogram-into-a-color-spectrum

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!