How to extract information from a 'true color' image and interpolate?

9 visualizaciones (últimos 30 días)
Eric
Eric el 21 de Oct. de 2023
Comentada: DGM el 14 de Nov. de 2023
Good afternoon,
I would like to extract information contained in a 'true color' image. I explain myself a little bit. The attached image ('17p.png') is the vertical displacement in milimeters of a concrete beam at certain magnitude of vertical load. The displacement associated to each color is shown in the scale bar located to the right of the image. This bar has horizontal black lines across it to define some values. When you zoom in around a black line, the color palette is not continuous (see ZoomInBar.png). I would like to know the displacement "field" of the colored area in the beam (i.e., the displacement of each colored pixel). Then I will compare the displacement of two points (two pixels) with the data registered by two displacement transducers (see image LVDT-Points.png). I will repeat this process for multiple images. My idea to do this is:
(1) Open, extract the metadata and show the image
imagename = [num2str(i) 'p.jpg'];
[im,cmap] = imread(imagename); % Read the index and color map. Color map rescale to [0,1]
imshow(im,cmap); % Display the image
immetadata = imfinfo(imagename); % metadata to check the type of image
imageinfo(im,immetadata) % open the Image Information Tool.
(2) Select manually some points in the scale bar (ideally the point at the center between black lines), extract the RGB value, and associate a displacement to those values (manually). The scale will be constant in all the images, so I will do this only one time. For example: a point at the center of the second red box from top to bottom have a displacement of (1.52745+1.4263)/2=1.476875 mm
% Select the point on the bar (at the center)
disp('Select n points in the scale then press Enter');
[scx,scy] =ginput; % X&Y coordinates are changed when extracting info from the RGB
scx = int32(scx);
scy = int32(scy);
% Input the displacement for each color (average between two values
% associated to two black lines)
prompt = "Input the displacement values (n points, use [x1; x2; ...]): ";
imscale = input(prompt);
% Extract the RGB value of the n points. The first line (RGB color) of
% sc_fgr have a displacement value equal to the first line of imscale.
for j=1:length(imscale)
sc_rgb(j,1) = im(scy(j),scx(j),1); % Red, the image is 675x1219=scy,scx
sc_rgb(j,2) = im(scy(j),scx(j),2); % Green
sc_rgb(j,3) = im(scy(j),scx(j),3); % Blue
end
(3) Select two points in the colored area of the beam (indicated in LVDT-Point.png image) to extract their RGB values and then calculate the displacement based on a interpolation using the data associated to each color determined in step (2). Since the image is 'true color', the interpolation must use the same palette. The first idea I had was to calculate the displacement of those points. However, if I can have the entire displacement field of the whole colored area will be great.
% Select the points of interest
[x,y] =ginput;
px = int32(x);
py = int32(y);
% Extract the RGB value of the points.
for k=1:length(px)
p_rgb(k,1) = im(scy(k),scx(k),1); % Red, the image is 675x1219=scy,scx
p_rgb(k,2) = im(scy(k),scx(k),2); % Green
p_rgb(k,3) = im(scy(k),scx(k),3); % Blue
end
% Interpolate to calculate the displacement
% I do not know how to so this step. I will interpo
I don't know how to interpolate a RGB value (3 values, red-green-blue) with displacement (1 value). I changed the RGB to grayscale (inten = 0.299*sc_rgb(1,1) + 0.587*sc_rgb(1,2) + 0.114*sc_rgb(1,3)), but the dark red and dark blue (top and bottom in the scale bar) look like black.
It would be great to have the data associated with this image, but unfortunatelly I only have the images.
Thank you very muck for your kind help.
All the best,
Eric
  1 comentario
DGM
DGM el 21 de Oct. de 2023
Editada: DGM el 21 de Oct. de 2023
This is going to be a problem unless you know how the original pseudocolor image was created.
There are a few things we would ideally want to know in order to know what the displacement is based on the pseudocolored region in the image:
  • the applied colormap
  • the original grayscale image without the overlay
  • the overlay opacity
That said, we might be able to cut some corners if we knew the applied colormap accurately (it appears to just be jet()). We might be able to just use hue as a proxy for the index value, but chances are that it wouldn't be sufficiently accurate.

Iniciar sesión para comentar.

Respuesta aceptada

DGM
DGM el 21 de Oct. de 2023
Editada: DGM el 21 de Oct. de 2023
As I said, the given image is the weighted sum of two things:
% compositeimage = alpha*pseudocolorimage + (1-alpha)*grayscaleimage;
In this case, we know compositeimage, and we know the set of colors from which pseudocolorimage was created, but we don't know pseudocolorimage itself. We don't know alpha or grayscaleimage (unless you know otherwise). We need to know pseudocolorimage in order to estimate the original data.
That leaves us with few options. We can try to use color information (specifically hue) on the assumption that it will be unaffected by the composition so long as the grayscale background image is neutral.
% read the image
inpict = imread('https://www.mathworks.com/matlabcentral/answers/uploaded_files/1517356/17p.png');
% crop out the rough area of interest
inpict = imcrop(inpict,[104 294 993 239]);
% get the hue of the applied colormap
maplen = 256;
CTref = jet(maplen); % the map does appear to be jet()
[Href,~,~] = rgb2hsv(CTref);
% function is not unique-valued (this is problematic)
% but luckily, most of the image stays away from those hues
plot(Href)
xlabel('index')
ylabel('hue')
% get the hue of the pseudocolor image region
[H,S,~] = rgb2hsv(inpict);
% convert the hue image into data-scale
indpict = rgb2ind(repmat(H,[1 1 3]),repmat(Href,[1 3]));
datarange = [0.0102 1.6286];
idxrange = [0 length(Href)-1];
%displacement = imrescale(indpict,idxrange,datarange); % nice and concise
displacement = rescale(indpict,datarange(1),datarange(2),... % ugh
'inputmin',idxrange(1),'inputmax',idxrange(2));
% find gray (unmapped) regions
% hue data will be invalid in these areas anyway
mask = S > 0.01;
% display it
hi = imagesc(displacement,datarange);
hi.AlphaData = mask; % hide the junk unmapped data
axis image
colorbar('location','southoutside')
colormap(jet)
As you can see, this has a couple problems. First, the applied colormap (jet()) is constant-valued on hue near its ends. Any parts of the image in those regions will be ambiguous. We could get an idea of where those ambiguous regions are and how much of a problem they actually pose. It's only a relatively small portion of the image.
Hreflim = [32 224]/256*size(Href,1); % manually picked
ambiguousregion = indpict<Hreflim(1) | indpict>Hreflim(2);
ambiguousregion = ambiguousregion & mask;
imshow(ambiguousregion)
Second, the image hue (after compression) is not entirely independent of the grayscale background. That can be seen as error in the estimated displacement image.
These are other examples of doing the reverse colormapping with plain pseudocolor images:
Related:
  7 comentarios
Eric
Eric el 13 de Nov. de 2023
Hi, thank you for the updated script. It works as intended! I agree, a linear interpolation seems more reasonable in this case.
Thanks, you rocks!!
DGM
DGM el 14 de Nov. de 2023
Yeah, I'm used to these pseudocolor-to-data estimation problems being presented in a way where using rgb2ind() is appropriate because we're essentially trying to do 3D lookup. This problem is fairly unique in that we were forced to reduce it to 1D, but I just kept using rgb2ind() out of habit.

Iniciar sesión para comentar.

Más respuestas (0)

Community Treasure Hunt

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

Start Hunting!

Translated by