imwrite() saved colormap incorrectly
Mostra commenti meno recenti
imwrite() was used to save indexed images along with its colormap. Suppose we use 'givenMap' to denote the colormap provided to imwrite() and 'savedMap' to denote the colormap obtained using imread() on the saved image.
The weird things were that:
1) For some colormaps, exact values in 'givenMap' and 'savedMap' were different. The magnitude of differences was in the order of 10%-20%;
2) But for other colormaps, the content in 'givenMap' and 'savedMap' were the same.
Below are exemplar codes:
% file path for saving image
savedFilePath = 'D:\BMP\imwriteTest';
if ~exist(savedFilePath,'dir')
mkdir(savedFilePath);
end
% load image data
givenData = load('clown.mat');
givenData = givenData.X;
% set range of image to 0-1
minImg = min(givenData(:));
maxImg = max(givenData(:));
givenData = (givenData-minImg)./(maxImg-minImg);
% set image to uint8 type
givenData = givenData*255;
givenData = uint8(givenData);
Exemplar colormap that remained the same after imwrite():
% create a colormap
defaultMap = (0:255)'*[1,1,1]; % 256*3
defaultMap = defaultMap./255;
givenMap = defaultMap;
% use imwrite to save both data and colormap
imwrite(givenData,givenMap,[savedFilePath,'\copperclown.bmp'],'bmp');
% load saved data and colormap
[~,savedMap] = imread([savedFilePath,'\copperclown.bmp']);
% sum of differences
diffMap = sum(abs(givenMap(:)-savedMap(:)));
Exemplar colormap that changed after imwrite():
% create a colormap
defaultMap = (0:255)'*[1,1,1]; % 256*3
defaultMap = defaultMap./255;
givenMap = defaultMap;
% modify centeral part of colormap
centralMapValue = (0:200)/200;
givenMap(2:202,:) = repmat(centralMapValue(:),1,3);
% use imwrite to save both data and colormap
imwrite(givenData,givenMap,[savedFilePath,'\copperclown.bmp'],'bmp');
% load saved data and colormap
[~,savedMap] = imread([savedFilePath,'\copperclown.bmp']);
% sum of differences
diffMap = sum(abs(givenMap(:)-savedMap(:)));
Below are first 10 rows of 'givenMap' and 'savedMap', it's obvious that they were quite different:

Moreever, we can see that differences of adjacent rows was fixed at 0.05 in 'givenMap', but the value oscillate at '0.39' and '0.78' in 'savedMap'.
% show differences in adjacent rows of colormap
modifiedMapIndex = 2:202;
diffGivenMap_adjacentRow = diff(givenMap(modifiedMapIndex,1));
diffSavedMap_adjacentRow = diff(savedMap(modifiedMapIndex,1));
diffGivenMap_adjacentRow = [0;diffGivenMap_adjacentRow(:)];
diffSavedMap_adjacentRow = [0;diffSavedMap_adjacentRow(:)];
maxDiffMap_adjacentRow = max(abs([diffGivenMap_adjacentRow(:);diffSavedMap_adjacentRow(:)]));
maxDiffMap_adjacentRow = maxDiffMap_adjacentRow*(1+0.05*sign(maxDiffMap_adjacentRow));
minDiffMap_adjacentRow = 0;
figure;
fontSize = 15;
subplot(1,2,1)
plot(modifiedMapIndex,diffGivenMap_adjacentRow,'ko')
xlim([2 202])
ylim([minDiffMap_adjacentRow maxDiffMap_adjacentRow])
xlabel('#Row','FontSize',fontSize)
ylabel('mapDiff\_adjacentRow','FontSize',fontSize)
title('Difference in Adjacent Row@givenMap','FontSize',fontSize)
subplot(1,2,2)
plot(modifiedMapIndex,diffSavedMap_adjacentRow,'ro')
xlim([2 202])
ylim([minDiffMap_adjacentRow maxDiffMap_adjacentRow])
xlabel('#Row','FontSize',fontSize)
ylabel('mapDiff\_adjacentRow','FontSize',fontSize)
title('Difference in Adjacent Row@savedMap','FontSize',fontSize)

More detailled comparison can see the attached code.
My question is: are these differences caused by
1) the innate 'imprecision' of imwrite() or imread()?
or
2) my misuse of imwrite() or imread()?
5 Commenti
Stephen23
il 9 Lug 2021
"are these differences caused by 1) the innate 'imprecision' of imwrite() or imread()? or 2) my misuse of imwrite() or imread()?"
The differences are caused by the fact that you have not taken into account that BMP files only store integer values, not floating point values. The exact map values in your second example cannot be stored in a BMP file, instead they are converted to the nearest suitable integer values before saving to the file.
Waveform Dai
il 9 Lug 2021
"values in the two exemplar colormaps I gave are both of floating point type, but only one of them were correctly saved using imwrite()"
The values are the cause, not their class. All that really matters is that in your first example, all of the values could be scaled and converted exactly to integer values. In your second example, not all of them to whole numbers, so rounding occurs.
"So I still don't understand what imwrite() does so as to result in such opposite results or what a correct/proper colormap should be so as to be faithfully saved?"
What makes you think that any image file format is required to "faithfully save" all of the exact values that you want?
BMP supports some integer values. Some of your values cannot be represented exactly using those integers.
Actually there is a very simple answer to your question: the map must only include values which when scaled by 255 are whole numbers. Thus no rounding will occur when they are converted to 8 bit integer (perhaps the map can support other integer precisions, I did not check).
"I still don't understand what imwrite() does so as to result in such opposite results..."
Lets take a look at some values are you trying to save, for example (quite randomly) the fifth row:
Example 1:
defaultMap = (0:255)'*[1,1,1]; % 256*3
defaultMap = defaultMap./255;
defaultMap(5,:) % for comparison with "imported" value
tmp = defaultMap(5,:)*255 % scaled -> these are whole numbers!
bmp = uint8(tmp) % saved as integer inside BMP file
double(bmp)./255 % file import
Example 2:
givenMap = defaultMap;
centralMapValue = (0:200)/200;
givenMap(2:202,:) = repmat(centralMapValue(:),1,3);
givenMap(5,:) % for comparison with "imported" value
int = givenMap(5,:)*255 % scaled -> are these whole numbers? (hint: no)
imp = uint8(int) % saved as integer inside BMP file
double(imp)./255 % file import
Walter Roberson
il 9 Lug 2021
Modificato: Walter Roberson
il 9 Lug 2021
Representing colors using at most one byte per component (0:255) is inherent in bitmap format. With some options, even fewer bits are used.
I have to wonder about that first map. 0.005 * 255 is about 1 1/4 so if that table 0.005 apart were to continue to 256 entries you would be dealing with relative intensity greater than 1.
Waveform Dai
il 9 Lug 2021
Risposte (0)
Categorie
Scopri di più su Images in Centro assistenza e File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!
