Effacer les filtres
Effacer les filtres

Convert an 8 bit image to 12 bit

42 vues (au cours des 30 derniers jours)
Amir Cawich
Amir Cawich le 22 Août 2022
Modifié(e) : DGM le 6 Juil 2024 à 4:29
I am trying to convert an image from 8bit to 12 bit. I understand 8 bit can go from 0-256 while 12 can go from 0-4095 i believe. Basically i am using the bit value for analysis purpose so using a 12 bit image makes more sense for me. However I don't have a lot of experience with image processing. Can i simply multiply the 8 bit values by a fraction of 256 or something similar? If anyone has any experience doing this can provide some feedback. I have read about going from 12 bit to 8 bit but it is hard to find information on going the other way.

Réponse acceptée

Chunru
Chunru le 22 Août 2022
I = imread("peppers.png"); % 8-bit image
whos
Name Size Bytes Class Attributes I 384x512x3 589824 uint8 cmdout 1x33 66 char
I1 = double(I)/256; % 8->12bit
imwrite(I1, 'test.jpg', 'BitDepth', 12); % JPEG supports 12 bits
I2 = imread('test.jpg');
class(I2)
ans = 'uint16'
I2 = rescale(I2); % rescale
class(I2)
ans = 'double'
imshow(I2)
  2 commentaires
Amir Cawich
Amir Cawich le 22 Août 2022
Thank you so much. It works
DGM
DGM le 6 Juil 2024 à 3:14
Modifié(e) : DGM le 6 Juil 2024 à 4:29
I have to disagree, not only to using JPG temp files, but the scaling is wrong.
% images don't always span the domain implied by their class
I0 = imread("peppers.png"); % uint8
I = imadjust(I0,[0 1],[0.25 0.75]); % reduce the contrast
% this scaling factor is incorrect
% [0 255] is mapped to [0 0.996], not [0 1]
% so the uint12 image will be [0 4078], not [0 4095]
% this should just be replaced with im2double()
I = double(I)/256; % this is off by one
% JPG doesn't do anything other than damage the image.
% I does actually need to be unit-scale float here,
% otherwise the result will be wildly mis-scaled or full of
% banding artifacts from some sort of integer overflow.
% i'm not sure if that's a bug, but it doesn't seem to be documented.
imwrite(I, 'test.jpg', 'BitDepth', 12); % JPEG supports 12 bits
I2 = imread('test.jpg');
% this will not preserve the contrast of the image
% not merely because we're using the extrema instead of the domain limits
% but because the extrema have been grossly shifted by imwrite()/imread()
% as a consequence, we don't even get remotely close to the contrast
% of either the original image or the low-contrast image copy
% we just get something random in-between
I2 = rescale(I2); % stretch global extrema to [0 1]
% original image
% low-contrast copy
% some degraded copy with random wrong contrast
imshow([im2double(I0) I I2])
If you want to rescale the data, rescale the data.
% images don't always span the domain implied by their class
I0 = imread("peppers.png"); % uint8
I = imadjust(I0,[0 1],[0.25 0.75]); % reduce the contrast
% rescale it and shove it into a class that can hold it
% Y = X/((2^8 - 1)/(2^12 - 1)), not X/2^(8-12)
ir = getrangefromclass(I); % input scale
or = [0 2^12-1]; % output scale for 12b
scalefactor = diff(or)/diff(ir);
I2 = cast((double(I) - ir(1))*scalefactor,'uint16');
% original image
% low-contrast copy
% correct contrast, but uint12-scale in uint16
imshow([im2double(I0) im2double(I) double(I2)/4095])
That said, if you want to work with uint12-scale image data, you're going to constantly be working around the fact that it's improperly-scaled for its class, no matter what class (e.g. 'uint16','double') you cram it into. No scale-dependent tools will handle it properly without extra effort, including imshow() and imwrite().
If you want to store technical working data in a native 12-bit image format, then as far as I recall, JPG is the only thing imwrite says it supports. As far as I'm concerned, that's only an option if you don't mind ruining your data.
You can always write non-native uint12-scale uint16 in anything that supports uint16 though (e.g. PNG). It'll be lossless, but now you're just exporting the problem of improper scale outside of MATLAB.
Alternatively, you could do something like this with PNG. In this usage, any native-scale image is written to a 16-bit PNG, ostensibly keeping the 4 least significant bits. The data returned by imread() will not be uint12-scale. It will be uint16-scale. The size of the last argument to imwrite() must be tailored to match the depth of the image.
% a uint8 image
inpict = imread('peppers.png');
% write it as bitshifted uint12-scale data in uint16
imwrite(inpict,'testme.png','bitdepth',16,'SignificantBits',[12 12 12]);
% imread() won't shift the data back
recovered = imread('testme.png'); % uint16-scale
% so shift it back
recovered = bitshift(recovered,-4); % uint12-scale
Because of the way the data is represented in the file, it should remain readable by other apps. Likewise, there may be similar roundabout things you can do with PNM.

Connectez-vous pour commenter.

Plus de réponses (1)

DGM
DGM le 6 Juil 2024 à 3:22
Modifié(e) : DGM le 6 Juil 2024 à 3:25
MIMT imcast() does this sort of rescaling without needing to jump through hoops.
% a properly-scaled image of any class
inpict = imread('peppers.png'); % uint8 RGB
% any native-scale image --> uint12-scale uint16
outpict = imcast(inpict,class(inpict),'uint12');

Community Treasure Hunt

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

Start Hunting!

Translated by