Convert raw RGB byte sequence into a HxWx3 image - matlab

I have raw RGB (8 bit/channel) data of a WxH image, where bytes are specified in the (row-major) order:
r[1,1] g[1,1] b[1,1] r[1,2] g[1,2] b[1,2] ... r[H,W] g[H,W] b[H,W]
e.g. for a 256x256 RGB image, I have an 196608x1 uint8 array.
In order to convert this data to be used with MATLAB functions like imshow I have to reshape and then permute dims:
% imgvec: 196608x1 uint8
img = permute(reshape(imgvec, 3, H, W), [3 2 1])
% img: 256x256x3 uint8
is there a more straightforward way to it? This layout of raw RGB data is so common, perhaps there is a specific function to convert to/from it...

Related

What does the C do in Image Processing's Logarithmic Transformation do?

Log Transform for image is defined as this
s=T(r) = c*log(r+1)
where
s is the output image
r is the input image
c = 255/log(1+Maximum pixel value from the input image).
If the "Maximum pixel value from the input image" is 255 then the C value will be
105.886458025=255/log(256)
This does not make sense. 105.89 is a very high intensity value. Multiplying with this C value will yield a very bright image. Using the 'tire' image from matlab I get the output below:
I=imread('tire.tif');
I2=im2double(I);
J=105*log(1+I2);
imshow(I)
Is my understanding correct?
Image for demonstration
Alternate image
c is a scaling factor.
The following script works both on Matlab and Octave.
clc;
close all;
clearvars;
%imageFileName = 'https://www.forestfoliage.com/wp-content/original/2010_10/Fall-Foliage-mountain-sunset.jpg';
imageFileName = 'https://pixnio.com/free-images/2020/06/27/2020-06-27-11-50-57-1200x800.jpg';
I = imread(imageFileName);
inputMin = min(I(:))
inputMax = max(I(:))
I2 = double(I);
outputMax = 255
c = outputMax/log10(1 + double(inputMax))
J = uint8(double(c) * log10(1 + I2));
%I2(1:5,1:5,:)
%J(1:5,1:5,:)
imshow(I)
title("Raw")
pause(5)
imshow(J)
title("Processed")
im2double documentation:
im2double(I) converts the image I to double precision. I can be a grayscale intensity image, a truecolor image, or a binary image. im2double rescales the output from integer data types to the range [0, 1].
So, we will use double() instead. Thanks to #CrisLuengo for this. Earlier, I was rescaling the scaled output.
In Matlab,
Images stored as matrices of type double should have values in the range [0, 1].
Images stored as integer matrices should have values in the range [0, 255].
On line 12, we are casting the matrix to an integer matrix for this reason.
From the imshow() documentation,
If you specify a truecolor image of data type single or double, then values should be in the range [0, 1]. If pixel values are outside this range, then you can use the rescale function to scale pixel values to the range [0, 1]. The 'DisplayRange' argument has no effect when the input image is truecolor.

What is the difference between a uint8 and a single image?

I already know uint8 contains intensity values between 0 and 255 (28-1) and single contains values between 0 and 1, it is used to hold larger values without upsetting the range error. But, apart from that, are there any other differences?
What is the difference between imagesc((I/64)*64) and imagesc((Is/64)*64), where I is uint8 and Is is single?
imagesc just calls image underneath. As for image, it behaves a bit differently if integers or floats are supplied, as can be learned from image's documentation:
If C is of type double, then an RGB triplet value of [0 0 0] corresponds to black and [1 1 1] corresponds to white.
If C is an integer type, then the image uses the full range of data to determine the color. For example, if C is of type uint8, then [0 0 0] corresponds to black and [255 255 255] corresponds to white. If CData is of type int8, then [-128 -128 -128] corresponds to black and [127 127 127] corresponds to white.
...
Converting Between Data Types
To convert indexed image data from an integer type to type double, add 1. For example, if X8 is indexed image data of type uint8, convert it to type double using:
X64 = double(X8) + 1;
To convert indexed image data from type double to an integer type, subtract 1 and use round to ensure that all the values are integers. For example, if X64 is indexed image data of type double, convert it to uint8 using:
X8 = uint8(round(X64 - 1));
To convert true color image data from an integer type to type double, rescale the data. For example, if RGB8 is true color image data of type uint8, convert it to double using:
RGB64 = double(RGB8)/255;
To convert true color image data from type double to an integer type, rescale the data and use round to ensure that all the values are integers. For example, if RGB64 is image data of type double, convert it to uint8 using:
RGB8 = uint8(round(RGB64*255));
I = uint8(255*rand(1e3));
Is = single(I)/255;
tmpI = (I/64)*64;
tmpIs = (Is/64)*64;
% plot for prosterity
% figure;
% subplot(211)
% imagesc(tmpI)
% subplot(212)
% imagesc(tmpIs)
numel(unique(tmpI(:))) % gives 5
numel(unique(tmpIs(:))) % gives 256
Dividing an integer basically means binning of values, and then it stretches the data back to the original extend for plotting. In this case, you get 256/64 = 4 bins, with 0 as well, thus 5 possible values for your uint8 image. However, using single you retain all unique numbers, since the precision is a lot higher.
If you'd do the same test with a lot (order 2^52) elements in the rand and use double you'd see that that again has 2^32 times the number of unique elements of single, just as uint16 will have 2^8 the number of unique elements of uint8.

Histogram Equalization yielding unexpected results

I have a series of images with decreasing brightness that I would like to try to correct with histogram equalization. I applied histeq to some test data to learn how the function works
% Image that I would like to apply histogram equalization to
C = gallery('wilk',21);
figure, imagesc(C)
E = histeq(C);
figure, imagesc(E);
However, when I look at the output of histeq, I get a result that only has two unique values: 0.873 and 1.000. How come the output doesn't span the whole range of the input? I would expect there to be more than two unique values in the output.
According to the documentation for histeq, if the input is of type double or single it is expected to be in the range: [0, 1].
Intensity values in the appropriate range: [0, 1] for images of class double, [0, 255] for images of class uint8, and [0, 65535] for images of class uint16.
Your data is not normalized and is of type double,
whos C
% Name Size Bytes Class Attributes
%
% C 21x21 3528 double
[min(C(:)), max(C(:))]
% 0 10
You will need to normalized it first. You can use mat2gray to do this:
E = histeq(mat2gray(C));

convert any image type to RGB using MATLAB

I have an image I get it using this code
[path,user_cance]=imgetfile();
im=imread(path);
Now I don't know if this image is RGB or indexed or ...
How to convert im to RGB for example ?
If it is indexed image you can easily use ind2rgb function:
read the image:
[X,map] = imread('imagefile.tif');
Verify that the colormap, map, is not empty, and convert the data in X to RGB.
if ~isempty(map)
Im = ind2rgb(X,map);
end
finally you can View the size and class of X.
whos Im
ind2rgb converts the matrix X and corresponding colormap map to RGB (truecolor) format.
X can be of class uint8, uint16, single, or double. RGB is an m-by-n-by-3 array of class double.
here you can find the image formats that you can read using MATLAB.
According to Mathworks documentation (http://www.mathworks.fr/fr/help/matlab/ref/imread.html), imread can infer the data type from its content.
You could do test if the colormap exists or is empty :
[im, map] = imread(path_to_image);
if(isempty(map)) % image is RGB or grayscale
if(size(im, 3) == 1) % image is grayscale
im = cat(3, img, img, img);
end
else % image is indexed
im = ind2rgb(im, map);
end
% now 'im' is a RGB-image

DICOM to grayscale in matlab

How can I convert a DICOM image into a grayscale image in matlab?
Thanks.
I'm not sure what specific DICOM image you are talking about that is not grayscale already. The following piece of code demonstrates how you read and display a DICOM image:
im = dicomread('sample.dcm'); % im will usually be of type uint16, already in grayscale
imshow(im, []);
If you want a uint8 grayscale image, use:
im2 = im2uint8(im);
However to keep as much of the precision as possible, it's best to do:
im2 = im2double(im);
To stretch the limits temporarily only when displaying the image, use:
imshow(im2, []);
To stretch the limits permanently (for visualization only not for analysis), use:
% im3 elements will be between 0 and 255 (uint8) or 0 and 1 (double)
im3 = imadjust(im2, stretchlim(im2, 0), []);
imshow(im3);
To write the grayscale image as jpg or png, use:
imwrite(im3, 'sample.png');
UPDATE
If your version of Matlab does not have im2uint8 or im2double, assuming that your DICOM image is always uin16 a quick workaround to convert the DICOM image to a more manageable format would be:
% convert uint16 values to double values
% im = double(im);
% keep the current relative intensity levels for analysis
% involving real values of intensity
im2 = im/2^16
% if displaying, create a new image with limits stretched to maximum
% for visualization purposes. do not use this image for
% calculations involving intensity value.
im3 = im/(max(im(:));