Save indexed image as RGB

조회 수: 4 (최근 30일)
Mark H
Mark H 2025년 3월 1일
댓글: Mark H 2025년 3월 2일
I want to display two pseudocolored monochrome images with the same colormap, even though the images have different data ranges. For example one image has the range of values 0-2800 and the other might be like 0-1000. However I want the one with the smaller data range to be displayed using the colormap for the larger range. So far, this is no problem, as I can call clim(), and as you can see from the top row of my visualization below. Everything in the top row is fine.
The problem comes about when I want to save exactly what you see in the upper right image as an RGB image. I've been working on this over several days trying many different ways of using rgb2ind(), exportgraphics(), getframe(), etc. and nothing produces an RGB with the same array size (rows and columns) and with the same displayed colors. I've simplified my actual problem to the simple code below to demonstrate the problem. What I want is the upper right image saved as an RGB image with the full, original resolution (not the resolution of a screenshot) and with the same colors you see in the displayed indexed image. Can anyone figure it out?
% Create an image in the range 0-2800.
data = zeros(700, 200);
[rows, columns] = size(data);
rowValues = linspace(2800, 0, rows);
for row = 1 : rows
data(row, :) = rowValues(row);
end
% Display it with the HSV colormap.
s1 = subplot(2, 2, 1);
cmap = hsv(100); % 100 distinct colors
imshow(data, [], 'ColorMap', cmap, 'Parent', s1);
impixelinfo;
title('Data range 0-2800')
axis('on', 'image');
colorbar(s1)
% clim([20, 1000]);
% Make second image with values from 150 to 750
% The color range should just be in the blue because we're using the same colormap.
s2 = subplot(2, 2, 2);
data2 = zeros(rows, 200);
[rows2, columns2] = size(data2);
% Specify a range for the new data.
minValue = 150;
maxValue = 750;
rowValues = linspace(maxValue, minValue, rows2);
for row = 1 : rows2
data2(row, :) = rowValues(row);
end
imshow(data2, [], 'ColorMap', cmap, 'Parent', s2);
impixelinfo;
caption = sprintf('Data range %.1f to %.1f', minValue, maxValue);
title(caption)
axis('on', 'image');
colorbar(s2)
% If we don't use clim() then the full colormap will go from 150-750.
% If we want it to look like the values from the colormap used for the 2800
% image, we need to use clim to make the colormap go from 0-2800
% instead of from 150 to 750.
clim([0, 2800])
% Now we want to convert it to an RGB image and save to disk for use later.
% First try exportgraphics, however it's a screenshot and not the full resolution.
% exportgraphics(s2, '0000 Screenshot.png') % Not the full resolution!
% Well that didn't work so try ind2rgb.
rgbImage = ind2rgb(data2, cmap); % Doesn't look the same!
% Display the RGB image in the third column
s3 = subplot(2, 2, 3);
imshow(rgbImage);
axis('on', 'image');
title('RGB Image using rgb2ind')
% That didn't work either as you can see from the displayed image.
% More futile attempts by scaling the data.
iData = uint8(rescale(data2, 0, 255)); % Scale data to 0-255
[cmapRows, cmapColumns] = size(cmap);
% Find the indexes in the colormap where the value would be for the min value.
index1 = floor(minValue/2800 * cmapRows)
index1 = 5
% Find the indexes in the colormap where the value would be for the max value.
index2 = floor(maxValue/2800 * cmapRows)
index2 = 26
% Try to convert it with this section of the full colormap.
rgbImage = ind2rgb(data2, cmap(index1:index2, :));
s4 = subplot(2, 2, 4);
imshow(rgbImage);
axis('on', 'image');
title('RGB Image using scaling')
% Well, the above totally failed.
% Try getframe(), but it only produces a screenshot,
% not at the full resolution of the original data.
% axesData = getframe(s2); % Low resolution screenshot.
% rgbImage = axesData.cdata; % Get the image from the structure.
% s2 = subplot(2, 2, 3);
% imshow(rgbImage);
% axis('on', 'image');
% title('RGB Image')
  댓글 수: 2
Walter Roberson
Walter Roberson 2025년 3월 1일
rescale() to [0, sizeOfColorMap], uint16(), and ind2rgb()
Mark H
Mark H 2025년 3월 1일
I'm sorry @Walter Roberson but could you please give the complete script? Because when I tried to do what I thought you said (plus a few variations on it), I couldn't get it to work. The RGB image still does not look like the upper right image.
% Create an image in the range 0-2800.
data = zeros(700, 200);
[imageRows, columns] = size(data);
rowValues = linspace(2800, 0, imageRows);
for row = 1 : imageRows
data(row, :) = rowValues(row);
end
% Display it with the HSV colormap.
s1 = subplot(2, 2, 1);
colormapRows = 100;
cmap = hsv(colormapRows); % 100 distinct colors
imshow(data, [], 'ColorMap', cmap, 'Parent', s1);
impixelinfo;
title('Data range 0-2800')
axis('on', 'image');
colorbar(s1)
% clim([20, 1000]);
% Make second image with values from 150 to 750
% The color range should just be in the blue because we're using the same colormap.
s2 = subplot(2, 2, 2);
data2 = zeros(imageRows, 200);
[rows2, columns2] = size(data2);
% Specify a range for the new data.
minValue = 150;
maxValue = 750;
rowValues = linspace(maxValue, minValue, rows2);
for row = 1 : rows2
data2(row, :) = rowValues(row);
end
imshow(data2, [], 'ColorMap', cmap, 'Parent', s2);
impixelinfo;
caption = sprintf('Data range %.1f to %.1f', minValue, maxValue);
title(caption)
axis('on', 'image');
colorbar(s2)
% If we don't use clim() then the full colormap will go from 150-750.
% If we want it to look like the values from the colormap used for the 2800
% image, we need to use clim to make the colormap go from 0-2800
% instead of from 150 to 750.
clim([0, 2800])
% Now we want to convert it to an RGB image and save to disk for use later.
% Attempt by scaling the data.
[colormapRows, cmapColumns] = size(cmap);
iData = uint16(rescale(data2, 0, colormapRows)); % Scale data to 0-100
rgbImage = ind2rgb(iData, cmap);
% Display image
s4 = subplot(2, 2, 3);
imshow(rgbImage);
axis('on', 'image');
title('RGB Image using scaling')
% That didn't work either as you can see from the displayed image.
The RGB image in the lower left does not look like the image in the upper right.

댓글을 달려면 로그인하십시오.

채택된 답변

DGM
DGM 2025년 3월 2일
편집: DGM 2025년 3월 2일
This doesn't look like you're using indexed-color images. It looks like you're trying to create RGB pseudocolored representations of arbitrarily-scaled 2D data, as one would see if they used imagesc().
There are two types of colormapping: scaled and direct (see CDataMapping here). When there is a direct mapping from integer values in the image to rows in the color table, that's 'direct' mapping. That's what an indexed-color image is, and the map offset is class-dependent. When the extents of the data are mapped linearly across the length of the colortable, that's 'scaled'.
If my assumption above is correct, you probably want to be using scaled color. Objects created by image(), imagesc(), and imshow() can be configured for either mapping mode, though imagesc() is configured for 'scaled' mapping by default. When using the second MAP argument in imshow(), the mapping is direct, but when using the 'colormap' name-value pair, the mapping is scaled.
As far as trying to convert the on-screen representation to a fixed RGB image, see the attached file. Contrary to simple examples based on rescaling and trying to use ind2rgb(), the 'cdscale' option of gray2pcolor() performs the quantization in a manner similar to how imagesc() or other display tools would.
% some parameters
rangeA = [0 2800];
rangeB = [150 750];
datasize = [700 200];
CT = hsv(100);
% create the two data arrays
% these are arbitrarily-scaled intensity images
% not directly-mapped indexed-color images
dataA = linspace(rangeA(2),rangeA(1),datasize(1));
dataA = repmat(dataA.',[1 datasize(2)]);
dataB = linspace(rangeB(2),rangeB(1),datasize(1));
dataB = repmat(dataB.',[1 datasize(2)]);
% display A
s1 = subplot(2, 2, 1);
imagesc(dataA, 'Parent', s1);
impixelinfo;
caption = sprintf('Data range %.1f to %.1f', rangeA(1), rangeA(2));
title(caption)
axis('on', 'image');
colormap(CT)
colorbar(s1)
% clim(rangeA) % this is already implied, since we're using imagesc()
% display B
s2 = subplot(2, 2, 2);
imagesc(dataB, 'Parent', s2);
impixelinfo;
caption = sprintf('Data range %.1f to %.1f', rangeB(1), rangeB(2));
title(caption)
axis('on', 'image');
colormap(CT)
colorbar(s2)
clim(rangeA) % we need to explicitly enforce these limits though
% generate RGB pseudocolored images (see the attached file)
pcimgA = gray2pcolor(dataA,CT,rangeA,'cdscale');
pcimgB = gray2pcolor(dataB,CT,rangeA,'cdscale'); % use the same limits
% display them
s3 = subplot(2, 2, 3);
imshow(pcimgA, 'Parent', s3);
title('dataA as RGB')
s4 = subplot(2, 2, 4);
imshow(pcimgB, 'Parent', s4);
title('dataB as RGB')
EDIT: I mistakenly described the argument usage for the case of imshow(). Fixed that.
  댓글 수: 1
Mark H
Mark H 2025년 3월 2일
Thanks @DGM. This works for me. 🙂

댓글을 달려면 로그인하십시오.

추가 답변 (0개)

카테고리

Help CenterFile Exchange에서 Red에 대해 자세히 알아보기

제품


릴리스

R2024b

Community Treasure Hunt

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

Start Hunting!

Translated by