Skip to content
Snippets Groups Projects
gtColorspace.m 9.04 KiB
function [hf,hc] = gtColorspace(Cmd, labels, varargin)
% Modified version of colorspace_demo.m - 3D visualizations of various color spaces

% Pascal Getreuer 2006

if ~exist('labels','var') || isempty(labels)
    labels = {'R''','G''','B'''};
end
if ~exist('Cmd','var') || isempty(Cmd)
    Cmd = 1;
end

[hasP,ind]=ismember('LineWidth',varargin(1:2:end));
if (hasP)
    LineWidth = varargin{ind*2};
else
    LineWidth = 2;
end
[hasP,ind]=ismember('FontSize',varargin(1:2:end));
if (hasP)
    FontSize = varargin{ind*2};
else
    FontSize = 12;
end

hf = figure('Color',[1,1,1]);

if nargin == 0
   % Create a figure with a drop-down menu
   h = uicontrol('Style','popup','Position',[15,10,90,21],...
      'BackgroundColor',[1,1,1],'Value',2,...
      'string',{'sRGB','Y''PbPr','HSV','HSL','L*a*b*','L*u*v*','L*ch'});
   set(h,'Callback',sprintf('%s(get(%.20g,''Value''))',mfilename,h));   
end

% Plot a figure
switch Cmd
case 1
   [x,y,z,Tri] = makeshape('Cube');
   CData = [x,y,z];
   myplot(x*0.8,y*0.8,(z+0.5)*0.8,Tri,CData);
   coloraxis(labels{1},7,0.5*0.8,FontSize,LineWidth);
   coloraxis(labels{2},8,0.5*0.8,FontSize,LineWidth); 
   coloraxis(labels{3},9,0.5*0.8,FontSize,LineWidth);
case 2
   [x,y,z,Tri] = makeshape('Cylinder');
   CData = colorspace('rgb<-ypbpr',[z,x/2,y/2]);
   myplot(x,y,0.8*z,Tri,CData);
   coloraxis('Y''',3,[],FontSize,LineWidth);
   coloraxis('P_b',5,0.8,FontSize,LineWidth); 
   coloraxis('P_r',6,0.8,FontSize,LineWidth); 
case 3
   [x,y,z,Tri] = makeshape('Hexacone');
   CData = colorspace('rgb<-hsv',[(pi+atan2(-y,-x))*180/pi,sqrt(x.^2+y.^2),z]);
   myplot(x,y,z,Tri,CData);
   coloraxis('H',1,[],FontSize,LineWidth);
   coloraxis('S',2,[],FontSize,LineWidth);
   coloraxis('V',3,[],FontSize,LineWidth);
case 4
   [x,y,z,Tri] = makeshape('Double Hexacone');
   CData = colorspace('rgb<-hsl',[(pi+atan2(-y,-x))*180/pi,sqrt(x.^2+y.^2),z]);      
   myplot(x,y,2*z,Tri,CData);
   coloraxis('H',1,[],FontSize,LineWidth);
   coloraxis('S',2,[],FontSize,LineWidth);   
   coloraxis('L',4,[],FontSize,LineWidth);
case 5
   [x,y,z,Tri] = makeshape('Blobs');
   CData = colorspace('rgb<-lab',[z*100,x*100,y*100]);
   myplot(x,y,2*z,Tri,CData);
   coloraxis('L*',4,[],FontSize,LineWidth);
   coloraxis('a*',5,2,FontSize,LineWidth); 
   coloraxis('b*',6,2,FontSize,LineWidth); 
case 6
   [x,y,z,Tri] = makeshape('Blobs');
   CData = colorspace('rgb<-luv',[z*100,x*125,y*125]);
   myplot(x,y,2*z,Tri,CData);
   coloraxis('L*',4,[],FontSize,LineWidth);
   coloraxis('u*',5,2,FontSize,LineWidth); 
   coloraxis('v*',6,2,FontSize,LineWidth);
case 7
   [x,y,z,Tri] = makeshape('Blobs');
   CData = colorspace('rgb<-lab',[z*100,x*100,y*100]);
   myplot(x,y,2*z,Tri,CData);
   coloraxis('L*',4,[],FontSize,LineWidth);
   coloraxis('c',2,[],FontSize,LineWidth); 
   coloraxis('h',1,[],FontSize,LineWidth);
case 8
   [x,y,z,Tri] = makeshape('Cone');
   CData = colorspace('rgb<-hsi',[(pi+atan2(-y,-x))*180/pi,sqrt(x.^2+y.^2),1-z]);
   myplot(x,y,z,Tri,CData);
   coloraxis('H',1,[],FontSize,LineWidth);
   coloraxis('S',2,[],FontSize,LineWidth);
   coloraxis('1-I',3,[],FontSize,LineWidth);
case 9
   [x,y,z,Tri] = makeshape('Cone');
   CData = colorspace('rgb<-hsi',[(pi+atan2(-y,-x))*180/pi,sqrt(x.^2+y.^2),z]);
   myplot(x,y,z,Tri,CData);
   coloraxis('H',1,[],FontSize,LineWidth);
   coloraxis('S',2,[],FontSize,LineWidth);
   coloraxis('I',3,[],FontSize,LineWidth);
end


axis equal;
axis off;
pbaspect([1,1,1]);
view(135,35);
rotate3d on;

hc = get(hf,'Children');
set(hc,'tag','colorspace');

end

%%
% sub-function
function myplot(x,y,z,Tri,CData)
% Plot a triangular mesh with color data
cla;
CData = min(max(CData,0),1);
patch('Faces',Tri,'Vertices',[x,y,z],'FaceVertexCData',CData,...
   'FaceColor','interp','EdgeColor','none');
hold on;
end

function coloraxis(Name,Type,h,FontSize,LineWidth)
% Draw color axes as 3D objects

switch Type
case 1
   set(text(-0.25,-1.3,1.1,Name),'FontWeight','bold',...
      'FontSize',FontSize,'Color',[0,0,0]);
   t = linspace(0,pi*3/2,60);
   x = cos(t)*1.1;
   y = sin(t)*1.1;
   set(plot3(x,y,zeros(size(x)),'k-'),'LineWidth',LineWidth,'Color',[1,1,1]*0.8);
   x = [x,-0.1,0,-0.1];
   y = [y,-1.05,-1.1,-1.15];
   set(plot3(x,y,ones(size(x)),'k-'),'LineWidth',LineWidth);   
case 2
   set(text(0,-0.6,0.15,Name),'FontWeight','bold','FontSize',FontSize,'Color',[0,0,0]);
   set(plot3([-0.05,0,0.05,0,0],[-0.9,-1,-0.9,-1,0],[0,0,0,0,0],'k-'),'LineWidth',LineWidth);
case 3
   set(text(0,0.15,1.3,Name),'FontWeight','bold','FontSize',FontSize,'Color',[0,0,0]);
   set(plot3([0,0,0,0,0],[-0.05,0,0.05,0,0],[1.6,1.7,1.6,1.7,0],'k-'),'LineWidth',LineWidth);
case 4
   set(text(0,0.15,2.4,Name),'FontWeight','bold','FontSize',FontSize,'Color',[0,0,0]);
   set(plot3([0,0,0,0,0],[-0.05,0,0.05,0,0],[2.4,2.5,2.4,2.5,0],'k-'),'LineWidth',LineWidth);
case 5
   set(text(0.6,0,h+0.15,Name),'FontWeight','bold','FontSize',FontSize,'Color',[0,0,0]);
   set(plot3([0.9,1,0.9,1,-1,-0.9,-1,-0.9],[-0.05,0,0.05,0,0,-0.05,0,0.05],...
      zeros(1,8)+h,'k-'),'LineWidth',LineWidth);
case 6
   set(text(0,0.6,h+0.15,Name),'FontWeight','bold','FontSize',FontSize,'Color',[0,0,0]);
   set(plot3([-0.05,0,0.05,0,0,-0.05,0,0.05],[0.9,1,0.9,1,-1,-0.9,-1,-0.9],...
      zeros(1,8)+h,'k-'),'LineWidth',LineWidth);
case 7
   set(text(1.5,0,h+0.25,Name),'FontWeight','bold','FontSize',FontSize,'Color',[0,0,0]);
   set(plot3([1.4,1.5,1.4,1.5,-0.5,-0.5],[-0.05,0,0.05,0,0,0],...
      zeros(1,6)+h,'k-'),'LineWidth',LineWidth);
case 8
   set(text(0,1.5,h+0.25,Name),'FontWeight','bold','FontSize',FontSize,'Color',[0,0,0]);
   set(plot3([-0.05,0,0.05,0,0,0],[1.4,1.5,1.4,1.5,-0.5,-0.5],...
      zeros(1,6)+h,'k-'),'LineWidth',LineWidth);
case 9
   set(text(0,0.25,1.5,Name),'FontWeight','bold','FontSize',FontSize,'Color',[0,0,0]);
   set(plot3([0,0,0,0,0],[-0.05,0,0.05,0,0],[1.4,1.5,1.4,1.5,0],'k-'),'LineWidth',LineWidth);
end

end

function [x,y,z,Tri] = makeshape(Shape)
% Make a 3D shape: Shape = 'Cube', 'Cylinder', 'Cone', 'Double Cone', 'Blobs'

% Cube
N = 12;    % Vertices per edge
% Cylinder, Cone, Double Cone
Nth = 25;  % Vertices over angles, (Nth - 1) should be a multiple of 12 
Nr = 4;    % Vertices over radius
Nz = 8;    % Vertices over z-dimension

switch lower(Shape)
case 'cube'
   [u,v] = meshgrid(linspace(0,1,N),linspace(0,1,N));
   u = u(:);
   v = v(:);
   x = [u;u;u;u;zeros(N^2,1);ones(N^2,1)];
   y = [v;v;zeros(N^2,1);ones(N^2,1);v;v];
   z = [zeros(N^2,1);ones(N^2,1);v;v;u;u];
   Tri = trigrid(N,N);
   Tri = [Tri;N^2+Tri;2*N^2+Tri;3*N^2+Tri;4*N^2+Tri;5*N^2+Tri];
case 'cylinder'
   Nth = ceil(Nth*0.75);
   [u,v] = meshgrid(linspace(0,pi*3/2,Nth),linspace(0,1,Nz));
   Tri = trigrid(Nth,Nz);
   x = cos(u(:));
   y = sin(u(:));
   z = v(:);
   [u,v] = meshgrid(linspace(0,pi*3/2,Nth),linspace(0,1,Nr));
   Tri = [Tri;Nth*Nz+trigrid(Nth,Nr);Nth*Nz+Nth*Nr+trigrid(Nth,Nr)];
   x = [x;v(:).*cos(u(:));v(:).*cos(u(:))];
   y = [y;v(:).*sin(u(:));v(:).*sin(u(:))];
   z = [z;zeros(Nth*Nr,1);ones(Nth*Nr,1)];
   [u,v] = meshgrid(linspace(0,1,Nr),linspace(0,1,Nz));
   Tri = [Tri;Nth*Nz+2*Nth*Nr+trigrid(Nr,Nz);Nth*Nz+2*Nth*Nr+Nr*Nz+trigrid(Nr,Nz)];
   x = [x;u(:);zeros(Nr*Nz,1)];
   y = [y;zeros(Nr*Nz,1);-u(:)];
   z = [z;v(:);v(:)];
case 'cone'
   [u,v] = meshgrid(linspace(0,2*pi,Nth),linspace(0,1,Nz));
   Tri = trigrid(Nth,Nz);
   x = v(:).*cos(u(:));
   y = v(:).*sin(u(:));
   z = v(:);
   [u,v] = meshgrid(linspace(0,2*pi,Nth),linspace(0,1,Nr));
   Tri = [Tri;Nth*Nz+trigrid(Nth,Nr);];
   x = [x;v(:).*cos(u(:));];
   y = [y;v(:).*sin(u(:));];
   z = [z;ones(Nth*Nr,1)];
case 'double cone'
   Nz = floor(Nz/2)*2+1;
   [u,v] = meshgrid(linspace(0,2*pi,Nth),linspace(0,1,Nz));
   Tri = trigrid(Nth,Nz);
   r = 1 - abs(2*v(:) - 1);
   x = r.*cos(u(:));
   y = r.*sin(u(:));
   z = v(:);
case 'hexacone'
   [u,v] = meshgrid(linspace(0,2*pi,Nth),linspace(0,1,Nz));
   Tri = trigrid(Nth,Nz);
   r = 0.92./max(max(abs(cos(u)),abs(cos(u - pi/3))),abs(cos(u + pi/3)));
   x = v(:).*cos(u(:)).*r(:);
   y = v(:).*sin(u(:)).*r(:);
   z = v(:);
   [u,v] = meshgrid(linspace(0,2*pi,Nth),linspace(0,1,Nr));
   Tri = [Tri;Nth*Nz+trigrid(Nth,Nr);];
   v = 0.92*v./max(max(abs(cos(u)),abs(cos(u - pi/3))),abs(cos(u + pi/3)));
   x = [x;v(:).*cos(u(:));];
   y = [y;v(:).*sin(u(:));];
   z = [z;ones(Nth*Nr,1)];
case 'double hexacone'
   Nz = floor(Nz/2)*2+1;
   [u,v] = meshgrid(linspace(0,2*pi,Nth),linspace(0,1,Nz));
   Tri = trigrid(Nth,Nz);
   r = 1 - abs(2*v - 1);
   r = 0.92*r./max(max(abs(cos(u)),abs(cos(u - pi/3))),abs(cos(u + pi/3)));
   x = r(:).*cos(u(:));
   y = r(:).*sin(u(:));
   z = v(:);   
case 'blobs'
   Nz = 47;
   [u,v] = meshgrid(linspace(0,2*pi,Nth),linspace(0,1,Nz));
   Tri = trigrid(Nth,Nz);
   r = sin(v(:)*pi*3).^2.*(1 - 0.6*abs(2*v(:) - 1));
   x = r.*cos(u(:));
   y = r.*sin(u(:));
   z = v(:);   
end
end

function Tri = trigrid(Nu,Nv)
% Construct the connectivity data for a grid of triangular patches
i = (1:(Nu-1)*Nv-1).';
i(Nv:Nv:end) = [];
Tri = [i,i+1,i+Nv;i+1,i+Nv+1,i+Nv];
end