How to convert color map into contour map?

I have a file of color map with known boundary coordinates and color bar scale either horizontal or vertical. How can we transform the color map into contour map, such that the value of contours expressed the same in the color bar values?

 Accepted Answer

Umar
Umar on 14 Jul 2025

Hi @Moustafa,

I did read your comments and after some research, I implemented the example code in MATLAB. Hope this is what you are looking for if I interpret your comments correctly.

    % Step 1: Read the Color Map Image
   colorMapImg = imread('/MATLAB Drive/Color map.jpg');
   % Step 2: Convert Image to Grayscale (if necessary)
   grayMap = rgb2gray(colorMapImg); % Convert to grayscale
   % Step 3: Create X and Y coordinates based on image dimensions
   [rows, cols] = size(grayMap);
   [x, y] = meshgrid(1:cols, 1:rows);
   % Step 4: Normalize grayscale values to match contour levels
    normalizedGrayMap = double(grayMap) / 255; % Normalize to [0, 1]
   % Step 5: Define Contour Levels Based on Color Bar Values
   % Assuming color bar ranges from minValue to maxValue
   minValue = 0; % Adjust according to your color bar
   maxValue = 1; % Adjust according to your color bar
   numContours = 10; % Define number of contour levels
   contourLevels = linspace(minValue, maxValue, numContours);
   % Step 6: Generate Contours
   figure;
   contour(x, y, normalizedGrayMap, contourLevels);
   colorbar; % Display color bar for reference
   % Step 7: Add Titles and Labels
   title('Contour Map from Color Map');
   xlabel('X-axis');
   ylabel('Y-axis');

Please see attached.

So, let me explain what the above code is doing step by step.

Reading and Processing: The `imread` function loads the image. If your color map is not grayscale, converting it helps simplify contour generation.

Creating Meshgrid: This sets up a grid for plotting the contours.

Normalization: The grayscale values are normalized between 0 and 1 for contouring.

Contour Levels: You can adjust `minValue`, `maxValue`, and `numContours` based on your specific color bar scale.

Plotting Contours: The `contour` function generates contour lines based on your specified levels.

Further tips below to enhance code if you prefer

Color Mapping: If your original image has specific RGB values corresponding to certain data points, you may need a more complex mapping function to convert those RGB values directly into numeric data values.

Boundary Coordinates: If you have specific boundary coordinates, you might need to adjust your meshgrid accordingly or crop your image before processing.

Visualization: Always check your output visually to ensure that contours represent the expected data accurately.

By following these steps and using the provided code as a foundation, you should be able to successfully convert your color map into a contour map in MATLAB while maintaining alignment with your original color bar values.

Hopefully this helps.

4 Comments

Well I guess you got a contour plot out of it, but it doesn't mean anything, and the values are all completely wrong.
You can't use rgb2gray() to map the image to the original data. The transformation is not linear -- it's not even monotonic. This is your transfer function curve.
% read the file, crop out the colorbar
inpict = imread('Color map.jpg'); % i even tried to manually clean this
inpict = imcrop(inpict,[74.51 281.51 128.98 2.98]);
inpict = im2gray(inpict);
% "normalize"
y = mean(im2double(inpict),1); % position in the data scale
x = linspace(0,1,numel(y)); % position in the color scale
% this should be a monotonic curve from [0 0] to [1 1]
plot(x,y)
xlabel('normalized position on the color scale')
ylabel('normalized position on the data scale')
unitaxes(gca)
So pixels associated with ~20C now map to ~30C, and pixels at ~30C map to ~10C. The transformation can't even map the ends of the color scale to the ends of the data scale.
What's worse is the application to a contour map. What good is information about gradient, when we've artificially reversed the gradient arbitrarily in random places? The result is not meaningful.
So enough about that. If this isn't the answer, then what is? Well, I could throw out some examples of doing this sort of questionable data estimation before ...
... but the real answer is way easier to dispense. (I guess Walter beat me to it). If you want to get data from this image, then too bad. This microscopic damaged JPG is not worth using (in my opinion). A plot is a visualization of data. It is not a store of data. Reducing the plot to a thumbnail or taking a picture of it from orbit only makes it less justifiable.
The data scale cannot be accurately obtained since the numbers aren't readable. While we can't read some of the scale numbers, we can read enough to know that it's not linear. That means we need to know all of them, not just the ends.
The color scale also cannot be accurately obtained, simply as a consequence of the low resolution, the occluding ticks, and the JPG damage. Note the JPG damage causes damage near the ends of the scale. While the data scale numbers are not linearly spaced, we can also tell that the tick positions are not uniformly spaced in color scale. Worse yet, we can tell that the end ticks are not on the ends of the color scale. We don't actually know where the ends of the color scale should map to without guessing with some nonlinear extrapolation into the least-estimable part of the color scale.
Without those two things, there is no transformation to be done.
If you created the plot, then you have the data. Use the data, not the image. If this is a thumbnail of a larger image, then why are we focusing on trying to use the worse copy?
If that image is really truly the only thing you have, and you really need some results no matter how wrong they are, then feel free to try. The linked thread #1938509 involves a nonlinear scale. You're going to have to do some additional masking, since the non-data white regions will not map to anything meaningful. Reading the numbers is going to be mostly guessing. In the end, will we be able to justify the error if we don't even know how big the error is?

In brief summary, while transforming a color map into a contour map can be achieved through MATLAB coding techniques, it is paramount to ensure that all transformations are based on an accurate understanding of how colors correspond to numerical values in specific context. So, by following a methodical approach as outlined above, you can derive meaningful contours that reflect true underlying data characteristics.

You cannot derive meaningful contours from that plot.
The colormap is clearly non-linear and non-logarithm. We have no reason to believe that it is piecewise linear or piecewise log or piecewise alternating linear and log. We must assume that the mapping of values to colors is irregular within colormap tic marks .
For example -24.8 to 10.4 is 35.2 degrees but 10.4 to 19.2 is 8.8 degrees. We have no reason to expect that the 10.4 to 19.2 segment is strictly linear but the -24.8 to 10.4 is strictly log; we have to guess that if there is a strictly linear section that it extends to some unknown point in the -24.8 to 10.4 range... but we have no way of figuring out where that unknown hypothetical breakpoint is.
The spacing to tick values are seriously irregular, not even close to being linear or log. There is no useful information to be found from the colorbar.
There is only one thing to do in such a case: give up on reverse-engineering the colors to value table, and declare the contour problem unsolvable given only the plot.
I threw together a little exercise. I generated some data with a randomly-generated nonlinear scale, plotted it with a nonstandard colormap, took a screenshot, and then destroyed the screenshot. The randomly-generated scale means that the tick values are not uniformly spaced, and the tick positions are neither uniformly spaced along the colorbar, nor do they share the same relative spacing as the tick values.
%% try to back-estimate the data from a bad screenshot
% read the image
inpict = imread('garbagegraph.png');
imshow(inpict,'initialmagnification','fit','border','tight')
% the extracted colortable
cbpict = imcrop(inpict,[85.51 279.51 139.98 3.98]);
CT0 = permute(mean(im2double(cbpict),1),[2 3 1]);
% interpolate to form new CT
N = 256;
x0 = linspace(0,1,size(CT0,1));
xf = linspace(0,1,N);
CT = interp1(x0,CT0,xf);
% this is the approximate nonlinear temperature scale from the image
d0 = [-75.6 -57.2 -37.9 -16.6 -8.8 10.8 32.3 47.4]; % the ticks were randomly generated, so i have to try to read them
x0 = [86.09 93.16 111.8 130 151.7 170.9 183.6 207.8 223.4 225]; % use ginput(); [boxedge ticks boxedge]
x0 = imrescale(x0(2:end-1),imrange(x0),[0 1]); % normalize to box extents in x
xt = linspace(0,1,N);
d = interp1(x0,d0,xt,'pchip'); % interpolate to form new temp scale
figure; plot(xt,d) % at least it's monotonic and fairly straight
% crop the data region from composite image
inpict = imcrop(inpict,[40.51 22.51 234.98 234.98]);
inpict = flip(inpict,1); % rectify what pcolor() did
% convert the pseudocolor image into an index array
dataestimate = rgb2ind(inpict,CT,'nodither');
% convert the indexes into estimated data values
dataestimate = d(double(dataestimate)+1);
%% compare against the actual data
load xy.mat % load the data
dataestimate = imresize(dataestimate,size(datapict)); % resize
% show and tell
figure
imshow(datapict,[],'initialmagnification','fit','border','tight')
colorbar
figure
imshow(dataestimate,[],'initialmagnification','fit','border','tight')
colorbar
% let's look at the error
err = datapict - dataestimate;
figure
imshow(err,[],'initialmagnification','fit','border','tight')
colorbar
figure
histogram(err)
I could have probably improved that if I had done some manual inpainting on the colorbar, but I think this is more than enough of a show of effort. I'm surprised that the error is only as big as it is, but unless I had constructed this example from scratch, I would have no idea what it was at all.
Still, is +/- 10 units worth of error acceptable? How can we know if we don't even know what the units are either? Should we just base our error off the variation within this sample alone, or are there practical considerations that are implied by the actual data units?
Okay, well that was as good as I could manage with more effort than was warranted. What's the quality of the outcome of OP's trajectory?
% the accepted example (condensed)
colorMapImg = imread('garbagegraph.png');
grayMap = rgb2gray(colorMapImg); % Convert to grayscale
normalizedGrayMap = double(grayMap) / 255; % Normalize to [0, 1]
% we still need to fix the geometry
dataestimate = imcrop(normalizedGrayMap,[40.51 22.51 234.98 234.98]);
dataestimate = flip(dataestimate,1); % rectify what pcolor() did
dataestimate = imresize(dataestimate,size(datapict)); % resize
% the original example didn't put the units in data-scale.
% they were just put in unit-scale (same as im2double())
% we still need to put them in data scale if we want to compare.
% granted, the error this guesswork adds is my own, but we have to do something.
% i'm just going to rescale the presumed data extents to the tick extents.
dataestimate = imrescale(dataestimate,[0 1],[-75.6 47.4]);
% compare against the actual data (same as before)
dataestimate = imresize(dataestimate,size(datapict)); % resize
% show and tell
figure
imshow(datapict,[],'initialmagnification','fit','border','tight')
colorbar
figure
imshow(dataestimate,[],'initialmagnification','fit','border','tight')
colorbar
% let's look at the error
err = datapict - dataestimate;
figure
imshow(err,[],'initialmagnification','fit','border','tight')
colorbar
figure
histogram(err)
We already saw from my prior comment that the transfer curve is nonmonotonic, and we can see the inversions in the estimated data. It doesn't even look similar to the original data. If +/- 10 data units of error is questionable, what's -50/+60 units worth? That's nearly the entire range of the data.
Just for sake of completeness:
% throw down some contours
% i'm only using 5 levels for clarity
figure
contour(datapict,5)
colorbar
figure
contour(dataestimate,5)
colorbar
It's not subtle.

Sign in to comment.

More Answers (1)

YourImageArray = imread('Color map.jpg');
cropped_image = imcrop(YourImageArray, Crop_Rectange_Of_Image);
cropped_colorbar = imcrop(YourImageArray, Crop_Rectangel_of_Colorbar);
mean_colormap = reshape(mean(cropped_colorbar, 1, "native"), [], 3); %assuming horizontal colormap
image_idx = rgb2ind(cropped_image, mean_colormap);
At this point, image_idx is a linear range mapping color into index in colormap.
At this point, you have the problem that your colormap is decidedly non-uniform in a way that is neither linear nor logarithm. We cannot guess how to interpolate colormap index into temperature properly. The distance from -50.8 to -24.8 is 26 degrees, but the distance from -24.8 to 10.4 is 35.2 degress. The distance from 10.4 to 19.2 is 8.8 degrees. There is no logic in those choice of distances, so we have to assume that within the 35.2 degree gap that some unknown portion of the range is a linear mapping but below that in the range it switches to log scaling. There is no way for us to know where that breakpoint is.
With us being unable to map colormap index into temperature due to the inconsistent mapping, we are unable to draw a contour plot.

Categories

Products

Release

R2014b

Asked:

on 14 Jul 2025

Edited:

DGM
on 17 Jul 2025

Community Treasure Hunt

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

Start Hunting!