convert image from double to uint
6 views (last 30 days)
Show older comments
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
DGM
on 26 Mar 2024
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)
% for the second case
edges2 = linspace(inrange(1),inrange(2),nlevels+1)
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.
Answers (0)
See Also
Categories
Find more on Red 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!