Extract RGB from an Image and fit to color legend values in MATLAB
15 views (last 30 days)
Show older comments
Dear all,
I'm trying to extract each values from map.
The image consists of colorbar and map. So I have extracted the each RGB values but, I don't know how to FIT the
colorbar's value to map. This is the code what I use.
%% 1.Importing Data
img_path = 'imagename.jpg';
img = importdata(img_path);
figure(1)
imshow(img);
%% 2. Show amplitude of R G B respectively
% save image's amplitude of R G B respectively in 2D array
red=img(:,:,1);
green=img(:,:,2);
blue=img(:,:,3);
[bougrow,bougcol,X]=size(img);
%Caution: must put X
figure(2);
subplot(3,1,1);
imshow(red);
subplot(3,1,2);
imshow(green);
subplot(3,1,3);
imshow(blue);
%% 3. Extract R G B
redimg=zeros(row,col,3);
redimg(:,:,1)=red;
greenimg=zeros(row,col,3);
greenimg(:,:,2)=green;
blueimg=zeros(row,col,3);
blueimg(:,:,3)=blue;
%uint8
figure(3);
subplot(3,1,1);
imshow(uint8(redimg));
subplot(3,1,2);
imshow(uint8(greenimg));
subplot(3,1,3)
imshow(uint8(blueimg));
This is the map I want to extract from.
So, I have extracted RGB values(255~0) from map & colorbar.
Next step, I want to fit this RGB values(255~0) to colorbar's range (5 to 65) and apply to a map RGB. Please help.
0 Comments
Accepted Answer
DGM
on 21 Sep 2023
Edited: DGM
on 21 Sep 2023
There are a number of examples of doing this. Here's another.
% another crusty JPG of a questionable plot
inpict = imread('https://www.mathworks.com/matlabcentral/answers/uploaded_files/1489162/image.jpeg');
% get the colorbar extents
% there are no ticks, so it's hard to say that these are exact
cblim = [5 65];
% get the colormap from the colorbar
cbar = imcrop(inpict,[335.51 225.51 271.98 25.98]);
cbar = im2double(cbar);
CT0 = permute(mean(cbar,1),[2 3 1]);
% CT0 looks similar to jet()
% the jpg artifacts distort the ends
% but it still clearly not the same
% both ends of the map are constant
%ctpath(CT0,'rgb','2D','invert')
%ctpath(jet(size(CT0,1)),'rgb','2D','invert')
% find the region of interest
[H,S,V] = rgb2hsv(inpict);
colorareas = S >= 0.40;
colorareas = bwareaopen(colorareas,100); % get rid of specks
colorareas = ~bwareaopen(~colorareas,100); % get rid of holes
% colorareas = bwareafilt(colorareas,1); % get rid of the colorbar
lineareas = V <= 0.98;
validmask = colorareas & ~lineareas;
imshow(validmask,'border','tight')
% convert the pseudocolor image into an estimate of the data
dpict = rgb2ind(inpict,CT0,'nodither');
dpict = rescale(dpict,cblim(1),cblim(2));
% try to inpaint all the holes created by the contour lines, etc
dpict = regionfill(dpict,~validmask);
% fill non-data areas with NaN
dpict(~colorareas) = NaN;
imshow(dpict,[],'border','tight')
The end result is a 2D array where the values are in the range 5-65 within the ROI, and NaN outside. Use the data cursor to inspect it as desired.
You might be wondering why it looks like there's holes in the map. The answer is simple, and it's the reason I didn't remove the colorbar from the demo output. Look at the colorbar, and notice the step near dark gray. If this is a simple linear mapping, then the colorbar should appear as a linear gradient from black to white. It's not. It's constant-valued at each end. Data in those regions has been completely lost. This figure can only represent values on the interval [11 56], not [5 65]. Was that intentional? Was that a mistake? I don't know. Is it misleading and problematic for data estimation? Yes.
If you noticed that problem, you would have to go another step further to make sure it actually mapped between the real extents of the available information, not the misleading colorbar.
% another crusty JPG of a questionable plot
inpict = imread('https://www.mathworks.com/matlabcentral/answers/uploaded_files/1489162/image.jpeg');
% get the colorbar extents
% there are no ticks, so it's hard to say that these are exact
cblim = [5 65];
% get the colormap from the colorbar
cbar = imcrop(inpict,[335.51 225.51 271.98 25.98]);
cbar = im2double(cbar);
CT0 = permute(mean(cbar,1),[2 3 1]);
% trim the colormap to its valid extents
validx = [29 232]; % the only part of CT0 which is not constant-valued
cblim = interp1([1 size(CT0,1)],cblim,validx,'linear'); % adjust the colorbar extents
CT0 = CT0(validx(1):validx(2),:); % trim the CT
% find the region of interest
[H,S,V] = rgb2hsv(inpict);
colorareas = S >= 0.40;
colorareas = bwareaopen(colorareas,100);
colorareas = ~bwareaopen(~colorareas,100);
colorareas = bwareafilt(colorareas,1); % get rid of the colorbar
lineareas = V <= 0.98;
validmask = colorareas & ~lineareas;
% convert the pseudocolor image into an estimate of the data
dpict = rgb2ind(inpict,CT0,'nodither');
dpict = rescale(dpict,cblim(1),cblim(2));
% try to inpaint all the holes created by the contour lines, etc
dpict = regionfill(dpict,~validmask);
% fill non-data areas with NaN
dpict(~colorareas) = NaN;
imshow(dpict,[],'border','tight')
Now everything lies within [11.2 56.1]. Did the original data extend outside that interval? Maybe. Probably. What happened to all those points that were outside the adjusted cblim? They're clamped. The information in those regions is gone.
Plots and graphs are conveniences for visualizing data. They are not stores of data. They are often inaccurate presentations, and are subject to any amount of mistakes in creation (e.g. a poor choice of colormap or limits) and damage during transport (e.g. JPG compression). The result of the above efforts is a rough estimate of data, not the actual data.
2 Comments
DGM
on 21 Sep 2023
Edited: DGM
on 21 Sep 2023
To put this in perspective, let's perform a little exercise where we know what the original data actually is. We can replicate similar conditions (poor map choice, ambiguous colorbar limits, compression damage, etc) and then try to see how good our estimate actually is.
% some fake data
Z = (peaks(500)*0.8 + 5.9)*100;
% create a problematic colormap
CT = jet(256);
CT = CT(27:218,:);
CT = padarray(CT,[27 0],'replicate','pre');
CT = padarray(CT,[23 0],'replicate','post');
% plot stuff
pcolor(Z)
shading flat
colormap(CT)
cb = colorbar;
cb.TickLength = 0;
hold on
[~,hc] = contour(Z,15);
hc.LevelList = round(hc.LevelList);
hc.LineColor = 'k';
hc.ShowText = 'on';
xt = xticks;
yt = yticks;
for k = 1:numel(xt)
xline(xt(k));
end
for k = 1:numel(yt)
yline(yt(k));
end
% save it as a crusty JPG
fname = 'trash.jpg';
saveas(gcf,fname)
clf
%% try to estimate Z from the image
% these crop parameters are specific to the image used
% the entire figure
inpict0 = imread(fname);
% get the colorbar extents
% there are no ticks, so it's hard to say where the ends are
% let's pretend we made a really good guess
cblim = [50 1250];
% get the colormap from the colorbar
cbar = imcrop(inpict0,[473.51 30.51 30.98 327.98]);
cbar = im2double(cbar);
CT0 = permute(mean(cbar,2),[1 3 2]);
CT0 = flipud(CT0);
%ctpath(CT0,'rgb','2D','invert')
% trim the colormap to its valid extents
validx = [43 292]; % the only part of CT0 which is not constant-valued
cblim = interp1([1 size(CT0,1)],cblim,validx,'linear'); % adjust the colorbar extents
CT0 = CT0(validx(1):validx(2),:); % trim the CT
% we can just crop out just the plot box this time
inpict = imcrop(inpict0,[64.51 30.51 368.98 327.98]);
inpict = flipud(inpict);
% find the region of interest
[H,S,V] = rgb2hsv(inpict);
colorareas = S >= 0.40;
colorareas = bwareaopen(colorareas,100);
colorareas = ~bwareaopen(~colorareas,100);
lineareas = V <= 0.98;
validmask = colorareas & ~lineareas;
%imshow(validmask)
% convert the pseudocolor image into an estimate of the data
dpict = rgb2ind(inpict,CT0,'nodither');
dpict = rescale(dpict,cblim(1),cblim(2));
% try to inpaint all the holes created by the contour lines, etc
dpict = regionfill(dpict,~validmask);
% fill non-data areas with NaN
dpict(~colorareas) = NaN;
pcolor(dpict)
shading flat
colorbar
% rescale the estimate to the original size of Z
Zest = imresize(dpict,size(Z));
% plot the relative error between the data and the estimate
relzerror = (Z-Zest)/range(Z,'all');
imagesc(relzerror);
colorbar
colormap(parula(256))
Those are not exactly small errors. We could do better with the cblim estimation, but it's hard to make up for missing data.
More Answers (1)
Florian Bidaud
on 21 Sep 2023
You need to create a colormap from your RGB values.
The format must be
your_colormap = [255 0 0; 255 150 0; 0 255 0];
Let's say you have the right format
your_colormap = rgb_values;
c = colormap(rgb_values);
clim([5 65])
See Also
Categories
Find more on Colormaps in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!