How to draw a L*a*b* colour space or HSV colour space (2D)?

조회 수: 57 (최근 30일)
Salad Box
Salad Box 2019년 3월 6일
편집: Image Analyst 2023년 5월 17일
Hi
I would like to draw the LAB or HSV colour space in 2D (see below) but I don't know how to draw it.
hsl.jpg
I found some code online (see below) which do something very similar (see the graph below) but NOT the same. The main difference is the colour at the center, it should be white, and the colours should graduately getting more and more saturated instead of one same colour from center all the way to the edge. What do I need to do in order to obtain a plot like the first graph??
r = linspace(0,1,10);
theta = linspace(0, 2*pi, 100);
[rg, thg] = meshgrid(r,theta);
[x,y] = pol2cart(thg,rg);
pcolor(x,y,thg);
colormap(hsv);
shading flat;
axis equal;
untitled.jpg
  댓글 수: 1
Guillaume
Guillaume 2019년 3월 6일
Note that HSV and Lab are 3D colour spaces. They can't be fully plotted in 2D. For example, your desired plot is simply a slice of the HSV cylinder at maximum lightness/value. Basically, the top of the HSV cylinder.

댓글을 달려면 로그인하십시오.

채택된 답변

Guillaume
Guillaume 2019년 3월 6일
As commented in your question, note that you're only plotting one slice of the 3D colour space.
Of course, your original code doesn't work, you end up doing
pcolor(x, y, thg);
so you're only plotting the hue (angle) against x and y. There's no saturation or value information in your plot. You then apply a colour map called hsv whose colours are derived from the hsv cylinder, but in no way does it mean you've done any conversion to/from hsv. The whole idea is flawed.
Here is how I'd do it:
%inputs:
%plotradius: the plot radius of the disk. Image will be 2*plotradius+1 x 2*plotradius+1
%plotvalue: the Value at which the slice of the HSV cylinder is to be taken. In the range 0-1
plotradius = 100;
plotvalue = 1;
[x, y] = meshgrid(-plotradius:plotradius); %get x,y coordinates of pixels in image
[hue, saturation] = cart2pol(x, y); %convert to angle, radius. Angle is the hue, radius is the saturation in the HSV cylinder
hue = (hue + pi) / (2*pi); %rescale from -pi:pi to 0:1 since matlab use 0:1 for the range of the hue
saturation = saturation / plotradius; %rescale saturation to range 0:1. Not that anything above 1 is outside the cylinder
value = ones(size(hue)) * plotvalue; %set value constant for all points in the disk
%now set points outside the disk (saturation >1) to white. That'd be a value of 1 and saturation of 0. hue doesn't matter
outsidedisk = saturation > 1;
saturation(outsidedisk) = 0;
value(outsidedisk) = 1;
%finally, convert hsv to rgb and plot
rgb = hsv2rgb(cat(3, hue, saturation, value));
imshow(rgb);
  댓글 수: 3
Guillaume
Guillaume 2019년 3월 6일
Matlab always draw the axis at the border of the image. If you want that:
imshow(rgb, 'XData', [-plotradius, plotradius], 'YData', [-plotradius, plotradius]);
axis on;
You can fake axes in the middle by drawing lines yourselves:
imshow(rgb, 'XData', [-plotradius, plotradius], 'YData', [-plotradius, plotradius]);
ax = gca;
ax.YDir = 'normal';
hold on;
plot(ax.XLim, [0, 0], 'k');
plot([0, 0], ax.YLim, 'k');
plot([ax.XTick; ax.XTick], repmat([-plotradius; plotradius] * ax.TickLength(1) * 3, 1, numel(ax.XTick)), 'k');
plot(repmat([-plotradius; plotradius] * ax.TickLength(1) * 3, 1, numel(ax.YTick)), [ax.YTick; ax.YTick], 'k');
text(ax.XTick, zeros(size(ax.XTick)) + plotradius*ax.TickLength(1)*10, ax.XTickLabel);
text(zeros(size(ax.YTick)) + plotradius * ax.TickLength(1) * 5, ax.YTick, ax.YTickLabel);
hold off;
Marco A. Acevedo Z.
Marco A. Acevedo Z. 2023년 5월 17일
편집: Image Analyst 2023년 5월 17일
Thanks Guillaume, it saved me some time :)
I needed the wheel [0-180] clockwise from X-axis positive using value (darkness from 0.5 to 1) at constant saturation. For that, use:
plotradius = 500;
plotsaturation = 1;
[x, y] = meshgrid(-plotradius:plotradius); %get x,y coordinates of pixels in image
%convert to angle, radius. Angle is the hue, radius is the saturation in the HSV cylinder
[hue, value] = cart2pol(x, y); %clock-wise from X-axis
%rescale from -pi:pi to 0:1 since matlab use 0:1 for the range of the hue
hue2 = rescale(hue, 0, 1, 'InputMin', 0, 'InputMax', pi);
%rescale saturation to range 0:1. Not that anything above 1 is outside the cylinder
value = value/plotradius;
%set value constant for all points in the disk
saturation = ones(size(hue)) * plotsaturation;
%now set points outside the disk (saturation >1) to white. That'd be a value of 1 and saturation of 0. hue doesn't matter
outsidedisk = (value > 1) | (hue < 0);
value(outsidedisk) = 0;
saturation(outsidedisk) = 1;
%finally, convert hsv to rgb and plot
rgb = hsv2rgb(cat(3, hue2, saturation, value));
figure
imshow(rgb)
[EDIT] ran the code so we can see the image it makes.

댓글을 달려면 로그인하십시오.

추가 답변 (3개)

darova
darova 2019년 3월 6일
clc, clear, cla
m = 100;
n = 10;
r = linspace(0,1,n);
theta = linspace(0, 2*pi, m);
[rg, thg] = meshgrid(r,theta);
[x,y] = pol2cart(thg,rg);
a = hsv(m);
hold on
whitebg('k')
for i = 1:m
for j = 1:n
color = [1 1 1] - (1-a(i,:))*j/n;
plot(x(i,j), y(i,j),'color',color,'marker','.');
end
end
hold off
  댓글 수: 1
Salad Box
Salad Box 2019년 3월 6일
Hi,
Thanks for the answer but I'm not sure whether that's what I asked for. Because I got the below image from your code.
Untitled.png

댓글을 달려면 로그인하십시오.


Image Analyst
Image Analyst 2019년 3월 6일
See attached demo.
0000 Screenshot.png
0001 Screenshot.png
Capture.PNG
Image.png

DGM
DGM 2022년 5월 10일
One thing that should be pointed out is that when plotting these things in a rectangular image, some consideration should be given to the geometry of what's being shown. The results are otherwise misleading.
When plotting slices of the cylindrical representation of HSV/HSL, it makes sense to omit points outside of the circular S=1 boundary (like @Guillaume's answer does). Points outside that boundary are just truncated.
The same applies for any other color model, but the boundary of interest may not be intuitively obvious beforehand. Consider the extent of sRGB in LAB:
That's not a cylinder or a grid-aligned rectangular prism. Showing it as a set of full rectangular color fields misrepresents its extents. To add confusion, the appearance of out-of-gamut color points is determined by the rendering intent of the conversion tools, which is something that a viewer won't have any way of knowing.
Consider the example:
sz = [300 300]; % size of each slice image
nslices = 25;
% set up base LAB image
A = linspace(-110,110,sz(1));
B = linspace(-110,110,sz(2));
[A B] = meshgrid(A,B);
l = linspace(1,99,nslices);
outpict = cell(nslices,1);
for k = 1:nslices
% construct this slice
thisl = l(k)*ones(sz);
thisrgb = lab2rgb(cat(3,thisl,A,B));
% mark out-of-gamut regions
isoog = any(thisrgb>1,3) | any(thisrgb<0,3);
thisrgb(repmat(isoog,[1 1 3])) = 0;
% flip so that coordinates are correct
thisrgb = flipud(thisrgb);
% add a text label directly to the image
% textim() is part of MIMT (see File Exchange)
lbl = textim(sprintf('L = %d',round(l(k))),'ibm-iso-16x9');
thisrgb(10:size(lbl,1)+9,10:size(lbl,2)+9,:) = repmat(lbl,[1 1 3]);
outpict{k} = thisrgb;
end
% show all slices
montage(outpict)
The above example shows only the in-gamut regions for each slice. Right-click and view the image for more detail.
What if you want to draw a border around the in-gamut regions? In the HSV example, that might seem simple; just overlay a circle. It's not a simple in LAB. See this answer for an example:
Where did that spinning 3D plot come from?
csview('lab','invert')
th = linspace(0,360,25);
outpict = cell(numel(th)-1,1);
for f = 1:numel(th)-1
view(th(f),20)
outpict{f} = iminv(frame2im(getframe(gcf)));
end
outpict = imstacker(outpict,'padding',0);
gifwrite(outpict,'spinlab.gif',0.2);
The functions csview(), iminv(), imstacker(), gifwrite() and textim() are from MIMT on the File Exchange.
Csview() can either be used as a command-line tool like shown, or it can be launched with a GUI for interactive visualization of different color models.

카테고리

Help CenterFile Exchange에서 Annotations에 대해 자세히 알아보기

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by