convert image from double to uint

I have an image, lets say:
I = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]
I want to convert this image to uint8 and uint2.
uint8 is easy, I just use im2uint8.
The formula MATLAB uses, I believe is:
I_uint8 = round(I * (2^8 - 1))
Because there is no function to convert to uint2, I did the same approach:
I_uint2 = round(I * (2^2 - 1))
I obtain the following result:
0 0 1 1 1 2 2 2 2 3 3
This is clearly wrong, because all double values in [0, 0.25[ should be mapped to 0, all values in [0.25, 0.5[ to 1, all values in [0.5, 0.75[ to 2 and all values in [0.75, 1] to 3. So the right approach should be:
I_uint2_correct = min(2^2 - 1, floor(I * 2^2))
So I used the floor function instead of round, and did not subtract 1. The min function changes the maximum value from 4 to 3.
The output is:
0 0 0 1 1 2 2 2 3 3 3
Everything is correct now.
By analogy, I conclude the im2uint8 funcion uses the wrong procedure as well. For example:
im2uint8(0.1) % same as round(0.1*255)
min(2^8 - 1, floor(0.1 * 2^8))
The output is:
ans =
26
ans =
25
I know for 8 bits the differences are insignificant, and nobody cares. But for 2, 3 or 4 bits, this is important.
And to prove this imprecision, lets do the following:
figure
imshow(0.1)
figure
imshow(im2uint8(0.1))
By using the data cursor on the first image, I obtain a RGB intensity of 0.0980392. In the second, I obtain 1.101961.
So, same image, different RGB values.
If I search for 0.0980392 in a gray(256) colormap, I find it at row 26 of the array, which corresponds to index 25 (because MATLAB starts counting at 1, not 0). On the other hand, the 1.101961 is at row 27, which corresponds to index 26. This is in agreement with the results above.
So I ask, why does im2uint8 use a procedure that is not totally precise? What are the advantages?
And why does MATLAB not compensate for this when plotting the images? This may be relevant for applications such as visual stimulation.

4 Comments

I don't have an answer as to why that's the way it was done. Some tools do the quantizing differently than other tools. It all seems to me as a matter of perspective -- i.e. whether what matters are the bin centers or the bin widths.
inpict = linspace(0,1,100); % assuming input range is [0 1]
n = 3; % going to use more levels for clarity
nlevels = 2^n;
% this is how ind2gray(), imhist(), etc do the quantizing
% the end bins are centered on the input limits,
% making them effectively half-width
op1 = round(inpict*(nlevels-1));
% this is how imagesc(), histogram(), etc do the quantizing
% the end bins are adjacent to the input limits,
% making them the same witdh as the other bins
op2 = min(nlevels - 1, floor(inpict * nlevels));
% display them
imagesc([op1; op2])
op2 bin limits are at 0.125, 0.25, 0.375, 0.5 and so on. Because there is always one more limit than bins, we can say limits are given by linspace(0,1,9).
For op1 I dont know how the centers and limits are calculated. Also doesn't make sense for me the bins having different lengths when inpict is a uniform array. What do you mean with beans being half width?
nlevels = 8;
inrange = [0 1];
% for the first case
binw = diff(inrange)/(nlevels-1);
edges1 = linspace(inrange(1)-binw/2,inrange(2)+binw/2,nlevels+1)
edges1 = 1x9
-0.0714 0.0714 0.2143 0.3571 0.5000 0.6429 0.7857 0.9286 1.0714
% for the second case
edges2 = linspace(inrange(1),inrange(2),nlevels+1)
edges2 = 1x9
0 0.1250 0.2500 0.3750 0.5000 0.6250 0.7500 0.8750 1.0000
For op1, the first three bin edges are approximately [-0.07143 0.07143 0.2143]. The widths of these two bins are both 0.1429, but since our input is constrained at 0, we're only ever actually using half of the first (and last) bin.
This is merely an observation on my part, not a statement of propriety.
Now I understand what you mean. So the first and last been are truncated at 0 and 1 respectively. When you say bins are centered on input limits, the centers are the 0 and 1 values. We do not see the other half becase they are out of range.
So you say in the first approach what matters are the bin centers. The bin centers are actually the colormap values, which can be obtained by gray(8).
Of course, method 1 allows the colormap to include the 0 and 1 values, while method 2 allows to have bins with the same length. It is not possible to have both at the same time, which would be the ideal situation.
I have another 2 questions here:
1 - Can your also confirm that imagecs uses op1, while imshow uses op2? Because imagesc(127) and imshow(127) with a gray(256) colormap have different indexes on the colormap.
2 - if I apply a gray(8) colormap to your previous plot with 8 levels, none of the RGB values of the data cursor match the entries of gray(8). But they match entries of gray(256). Does this mean that MATLAB plotting functions always use entries of the standard 8 bit colormap, regardless of the colormap size we choose?

Sign in to comment.

Answers (0)

Categories

Asked:

on 25 Mar 2024

Commented:

on 27 Mar 2024

Community Treasure Hunt

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

Start Hunting!