If I have an image with 16 bit depth, does matlab convert it into 8 bit before display if I use imshow? If I convert the data from 16 bit to 8 bit using uint8, I don't get the same image.

 Respuesta aceptada

DGM
DGM el 8 de Dic. de 2022
Editada: DGM el 8 de Dic. de 2022

0 votos

It's hard to know what you're doing wrong exactly since you didn't give a code example, but I'm going to guess.
Imshow() will display images of various classes so long as the image is scaled correctly with respect to its current class. If you have uint16 data cast as double, it won't be displayed as expected.
Alternatively, if you did something like this, you'll probably lose most of the image data due to truncation.
inpict = imread('myskeleton.tif'); % uint16 [0 65535]
inpict = uint8(inpict); % truncate everything above 255
When changing an image to another class, scale is important. Tools like uint8(), double(), etc. only cast the data. Tools like im2uint8(), im2double(), etc. rescale the data to fit the expected range of the destination class.
inpict = im2uint8(inpict); % rescale [0 65535] to fit within [0 255]
That avoids data truncation, and it keeps things scaled as other tools (imshow(), imwrite()) expect it.

8 comentarios

Jiayun Liu
Jiayun Liu el 8 de Dic. de 2022
I actually have three 8 bit images which is converted into a single precision image using the makehdr function. If I use tonemap function next, the data can be converted into uint8 which can be displayed just fine. However, if I use localtonemap instead, the output is still single precision. So the question is how does the monitor which has 8 bit depth display a single precision image (the image in monotone) using imshow?
DGM
DGM el 8 de Dic. de 2022
From the perspective of the user, imshow(), etc are basically class-agnostic. You feed it an image, and it shows up the same way regardless of its class, so long as the image is always scaled similarly with respect to the nominal range of the class.
For the purposes of display, images are necessarily scaled from their respective class-dependent range (or the range specified in the 'displayrange' parameter, if applicable) to the range appropriate for the output . For floating-point classes, that would be a simple linear mapping from [0 1] to [0 255]. That's something that's already going to happen internally, so if your images are properly-scaled, you don't need to do it.
Where exactly that conversion happens in the depths of image() and all its underlying code, I'm not sure. Like you mention, it's something that must happen at some point.
Similarly, imwrite() will generally cast/scale inputs as necessary to fit them into the specified output format.
Jiayun Liu
Jiayun Liu el 9 de Dic. de 2022
Does this mean that the internal mapping is doing what the function 'tonemap' is doing?
Stephen23
Stephen23 el 9 de Dic. de 2022
Editada: Stephen23 el 9 de Dic. de 2022
"Does this mean that the internal mapping is doing what the function 'tonemap' is doing? "
No, TONEMAP changes the relative values within an image using non-linear scaling. The TONEMAP file explains this as "Transform the HDR image to a new HDR image in the range [0,1] by taking the base-2 logarithm and linearly scaling it." Using a logarithm is a form of image compression, where low intensity pixel values are enhanced and high intensity values are compressed into a relatively small range.
As DGM already explained, the mapping for type conversion is a simple linear one, used in all of IM2DOUBLE, IM2INT16, IM2SINGLE, IM2UINT16, IM2UINT8, and internally in every function that accepts images as an input.
Lets try it ourselves:
M = randi(255,7,7,'uint8')
M = 7×7
150 5 89 229 51 215 111 225 225 169 10 171 7 17 9 247 183 4 132 135 84 62 163 111 157 53 241 83 27 54 175 28 63 48 37 119 20 133 234 56 34 138 21 161 218 191 147 64 125
A = im2double(M)
A = 7×7
0.5882 0.0196 0.3490 0.8980 0.2000 0.8431 0.4353 0.8824 0.8824 0.6627 0.0392 0.6706 0.0275 0.0667 0.0353 0.9686 0.7176 0.0157 0.5176 0.5294 0.3294 0.2431 0.6392 0.4353 0.6157 0.2078 0.9451 0.3255 0.1059 0.2118 0.6863 0.1098 0.2471 0.1882 0.1451 0.4667 0.0784 0.5216 0.9176 0.2196 0.1333 0.5412 0.0824 0.6314 0.8549 0.7490 0.5765 0.2510 0.4902
B = double(M)./255
B = 7×7
0.5882 0.0196 0.3490 0.8980 0.2000 0.8431 0.4353 0.8824 0.8824 0.6627 0.0392 0.6706 0.0275 0.0667 0.0353 0.9686 0.7176 0.0157 0.5176 0.5294 0.3294 0.2431 0.6392 0.4353 0.6157 0.2078 0.9451 0.3255 0.1059 0.2118 0.6863 0.1098 0.2471 0.1882 0.1451 0.4667 0.0784 0.5216 0.9176 0.2196 0.1333 0.5412 0.0824 0.6314 0.8549 0.7490 0.5765 0.2510 0.4902
isequal(A,B)
ans = logical
1
You can check the others yourself.
Jiayun Liu
Jiayun Liu el 9 de Dic. de 2022
Shouldn't the internal mapping map the double precision data to 8 bit before it can display? How can you display 64 bit data with 8 bit data through linear scaling? There are 52 bit to encode the fraction part, how can you separate 0.00001 and 0.000011 with 8 bit?
DGM
DGM el 9 de Dic. de 2022
Editada: DGM el 9 de Dic. de 2022
Perhaps it's clearer if we stick to values that are easy to recognize in each scale.
A = [0 0.5 1]; % a unit-scale 'double' image with one px each [black gray white]
% let's go from double to uint8
B1 = uint8(A) % without rescaling, data loss occurs due to rounding
B1 = 1×3
0 1 1
B2 = im2uint8(A) % black and white map to the expected values for uint8 class
B2 = 1×3
0 128 255
% let's go from double to uint16
C1 = uint16(A) % same problem
C1 = 1×3
0 1 1
C2 = im2uint16(A) % black and white map to the expected values for uint16 class
C2 = 1×3
0 32768 65535
% let's go from uint16 to uint8
D1 = uint8(C2) % without rescaling, data loss occurs due to truncation
D1 = 1×3
0 255 255
D2 = im2uint8(C2) % black and white map to the expected values for uint8 class
D2 = 1×3
0 128 255
% let's go from uint16 to double
A1 = double(C2) % results aren't damaged, but just improperly-scaled
A1 = 1×3
0 32768 65535
A2 = im2double(C2) % black and white map to the expected values for float classes
A2 = 1×3
0 0.5000 1.0000
As an aside, note that the rescaling is done with respect to the nominal range expected of the class, not the range of the input data. For instance:
A = uint8([12 128 253]); % a uint8 image that doesn't quite span the full range
% rescale with respect to input extrema; [12 253] maps to [0 1]
B1 = mat2gray(A) % mean and extrema are changed relative to [0 1]
B1 = 1×3
0 0.4813 1.0000
% rescale with respect to nominal range; [0 255] maps to [0 1]
B2 = im2double(A) % relative scale is maintained
B2 = 1×3
0.0471 0.5020 0.9922
B3 = im2uint8([B1; B2]) % convert both back to uint8, compare to A
B3 = 2×3
0 123 255 12 128 253
Bear this in mind when using the implicit 'DisplayRange' parameter with imshow() or using mat2gray() or similar normalization. It's something that's often seen recommended, but unless you want to blindly stretch contrast, you shouldn't be normalizing images merely to convert them.
Stephen23
Stephen23 el 9 de Dic. de 2022
Editada: Stephen23 el 9 de Dic. de 2022
"How can you display 64 bit data with 8 bit data through linear scaling?
Type conversions are inherently lossy: if you convert from 16 bit to 8 bit then you will lose information. This is why people who work with images professionally do not switch between data types and colorspaces, but select one that has enough range for their work.
"There are 52 bit to encode the fraction part, how can you separate 0.00001 and 0.000011 with 8 bit?"
You cannot see the difference and your monitor definitely cannot display the difference, so why would it matter?
It is very very unlikely that your image source can even record data with such precision (unless you happen to be working with the James Webb Space Telescope).
Lets have a look at those values:
255*(0.000011-0.00001)
ans = 2.5500e-04
According to a quick internet search, humans can distinguish around 1 million colors, fewer than the 16.7 million provided by 8 bit sRGB images (or around the same if we are being very generous). The values you are asking about have a difference a thousand times smaller than those of 8-bit TrueColor sRGB, well beyond any human visual capability.
I do not know where you got your alien monitor technology from, but please send me some! No human could distinguish between the values that you gave, so presumably you are also an alien. Welcome to earth.
Instead of tilting against windmills, perhaps some reading on image sensor noise, image compression algorithms, image colorspaces, and human perceptual limits would help.
"Shouldn't the internal mapping map the double precision data to 8 bit before it can display?"
Why?
Jiayun Liu
Jiayun Liu el 9 de Dic. de 2022
Guess I misunderstood what you said earlier about the linear scaling as direct mapping. Your explanation exactly answered my question. I just feel that going from higher to lower bit, it can't be a 1-to-1 mapping. I just do not know how they do this many to one mapping. It would seem that matlab uses something similar or exactly the function 'im2uint8' when displaying data with higher bit depth.

Iniciar sesión para comentar.

Más respuestas (0)

Categorías

Más información sobre Convert Image Type en Centro de ayuda y File Exchange.

Etiquetas

Preguntada:

el 8 de Dic. de 2022

Editada:

el 9 de Dic. de 2022

Community Treasure Hunt

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

Start Hunting!

Translated by