How to order colors (RGB) in my own colorbar?

17 views (last 30 days)
Kris Polaski
Kris Polaski on 27 Nov 2017
Edited: DGM on 28 May 2022
Hi, I created my own colormap basing on an image. Now, I created a colorbar but I want the colors to appear in order like: black, gray, ..., red, orange, yellow, etc. I want a colorbar like jet but with my own colors taken from image. Is this even possible?
photo = imread('kodim23.png');
[rozi, rozj, rozk] = size(photo);
R = photo(:,:,1);
G = photo(:,:,2);
B = photo(:,:,3);
R = double(R);
G = double(G);
B = double(B);
r = R(:);
g = G(:);
b = B(:);
rgb_array = [r g b];
rgb_array = rgb_array/255;
map = rgb_array;

Answers (1)

DGM on 27 May 2022
Edited: DGM on 28 May 2022
I think this is an interesting question. Being "interesting" doesn't mean that it's a problem with a unique solution though. A colormap or color table can be seen as either a set of fixed discrete points in a 3-dimensional space (e.g. the lines() colormap), or as a set of points interpolated along a continuous path in 3-dimensional space (e.g. parula(), jet()). It's this latter interpretation that is important to this discussion.
If you pick a set of colors from an image, you have a set of fixed points in 3D space, but they are yet unordered. In order for them to appear as a visually sensible progression of colors when interpolated, they need to be ordered. There isn't a simple solution to this part of the problem. Just as a set of points in a plane can define multiple different polylines, a set of points in 3-space can define any number of trajectories. See this thread and this thread. I'm sure there are others. You will likely have to do some amount of manual work to sort each color table.
That said, if you're stuck doing things manually, there are ways that may help make the task easier. MIMT ctpath() is a tool for visualizing the trajectory of a color table in various color spaces.
Let's start with the usual peppers picture.
Let's get a random selection of colors as a color table. Use ctpath() to visualize the trajectory of the current table in RGB.
rng(123) % make sure the demo is repeatable
A = imread('peppers.png'); % say we have an image
npoints = 10; % specify a number of points to select
% select colors randomly from within the image
sz = imsize(A,2);
idx = randi([1 prod(sz)],npoints,1);
cmap = zeros(npoints,3,class(A));
for c = 1:3
thischan = A(:,:,c);
cmap(:,c) = thischan(idx);
% this is our new unordered colormap
% the map is the same class and scale as inpict
cmap =
10×3 uint8 matrix
170 14 28
96 12 15
69 43 67
158 154 26
73 68 1
216 61 27
61 35 63
228 65 64
209 161 131
55 60 18
% display the trajectory in 3D
title('Original trajectory in RGB')
The result will be a connected 3D scatter plot. For sake of improving the perception of depth, the image below has been animated. Also shown is a sample swatch showing the current color table ordering.
As you can see, the path between points is a haphazard mess. From the swatch chart, it might not be readily apparent what the order should be, but from the 3D plot, you might be able to imagine a path that is relatively smooth. It helps if you can decide where it starts and ends.
If you hover over (or click on) the markers in the ctpath() plot, it will show you the color values and the index of the color within the color table. For a short CT like this, you can easily mouse over the plot and pick out a vector of reordered indices.
% hover to see index of each point in plot
newidx = [10 5 4 9 8 6 1 2 7 3];
cmap = cmap(newidx,:);
% display the reordered trajectory in 3D
title('Reordered trajectory in RGB')
Again, I animated the plot for clarity. If the plot isn't animated, you might have to right-click and view it.
With less than a minute's worth of mouse hovering, the CT is reordered. The trajectory is no longer a tangled mess. Both the plot and the chart show that it's not exactly a smooth path, but those were the chosen colors.
Now that a path has been defined by reordering the CT, it can be interpolated to form a longer table.
ncfine = 256; % length of longer CT
nc = size(cmap,1); % length of original CT
cmapfine = interp1(1:nc,im2double(cmap),linspace(1,nc,ncfine),'pchip');
% display trajectory of interpolated CT
title('Trajectory of interpolated CT')
At this point, you could use it for whatever you want.
[x y z] = peaks(50);
shading flat
How you visualize the CT might make a difference
It should be noted that this example was visualized entirely in RGB. A CT may appear to have a rather complicated trajectory in one color model, and yet may appear very simple (often a straight line) in another.
Consider the following short 32-color CT used by some of the MIMT documentation plots:
In RGB, this has a smooth trajectory with no apparent simple mathematical form:
In HSV, it's a stretched and wrinkled mess.
... but in HSYp, it's a straight line that crosses the H=0 boundary.
The lesson from this is that it might help to visualize the CT in a color model in which it has a more clearly-defined trajectory.
Not all color tables can be sorted into a visually-pleasing or generally-useful order
In the example above with ccmap('pastel') in RGB, it might certainly not be apparent that the odd curved trajectory is a helix following the surface of an inclined bicone, but the neighboring points are close enough to each other that the trajectory would be obvious even if they were presented in an unsorted fashion. That's not generally the case when picking colors from the cloud of points that describe an image. It's easy to contrive a set of points which not only has no visibly apparent trajectory, but is not sortable into any visually-monotonic progression (for lack of a better term) of colors.
Consider the following 36-color CT:
While unsorted, the points follow a simple uniform 6x6 grid in R-G. You might simply pick a direction and traverse the grid line by line. Let's start from the dark blue and head toward green.
Maybe for sake of continuity, we could traverse the grid in a zig-zag fashion instead.
Well, maybe instead of heading from blue to green, we could shift by 90 degrees...
Maybe instead, we could view points in YPbPr and sort by luma, again using a zig-zag approach to reduce discontinuity.
While some of these results might be better than the original random sorting, they aren't what I would expect to be a useful colormap for plotting anything. There isn't a way to traverse the set of points without one or more aspect of the color progression becoming cyclic. I picked the saddle shape on purpose to make it worse.
Consider that there are good reasons why people often avoid "rainbow" colormaps like jet() or hsv(). The ambiguities caused by representing continuous data with a wildly varying or circular colormap can be a legitimate concern. When colormaps contain cycles within themselves, the visual ambiguities become all that much worse. If you have particular use for such a map, you'll have to decide for yourself what's appropriate and what sorting approach best suits those needs.

Community Treasure Hunt

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

Start Hunting!