Matlab is opening a pgm image with different values using imread - matlab

I have a pgm image with 1251 different pixel values, ranging from 0 to 1250. I know this because I can open this image file with kate and see the values.
But when I open the same file using Matlab's imread, it also returns me 1251 different pixel values, but these values are not consecutive. The minimum value is 0 and the maximum value is 65483.
I want to iterate through these values in a for loop so I need to read the original and consecutive values as they exist in the file. How to do that in Matlab?
EDIT: That's the image if someone wants to try.
image

The values are scaled so that when you view the image it's not mostly black.
I tested that the scaling works with straight integer truncation by checking that:
[A] = imread( 'myfile.pgm', 'pgm' );
p = sort(unique(A(:));
q = uint16((0:1250) * 65535 / 1251)';
all(p == q) % returns 1
So, you can restore the image like this:
map = arrayfun( #(x) uint16(x * 1251 / 65536), 0:65535 );
B = arrayfun( #(x) map(x+1), A );

Related

Making a copy of an image via a Loop not working

Idk why the code won't work. All it does is give me a blank white image. And if you don't declare a matrix before by zeros(x, y) then it works fine. Wth is wrong here?
I tried not declaring the zeros matrix before and only that works. I even tried doing img2(i,j) = img2(i,j)+img1(i,j)
function [imgOut] = scaleLoopBased(img,s)
%UNTITLED4 Summary of this function goes here
% creating a zero matrix of the given scale
[rows,columns]=size(img);
imgTemp=zeros(rows, columns);
for i=1:rows
for j=1:columns
imgTemp(i, j) = img(i, j);
end
end
imshow(imgTemp);
imgOut = imgTemp;
end
Blank white image
This is a result of your new image (of type double, what zeros creates by default) not having the same type as your original image (typically type uint8). You can fix this by initializing your new image to have the same data type as the original using the class function and passing an additional argument to zeros:
imgTemp = zeros(rows, columns, class(img));
The reason it works correctly when you don't initialize imgTemp is because MATLAB initializes the variable for you using the data type of img by default when you perform the first indexed assignment.
The imshow utility expects one of the standard image types in MATLAB. An image of type double is expected to have values spanning the range [0 1], while images of type uint8 will have values in the range [0 255]. In your example you likely have a matrix imgTemp that is of type double but has values spanning [0 255]. Another way to fix your issue is to explicitly tell imshow what value range to use for the display (since the default [0 1] doesn't work):
imshow(imgTemp, [0 255]);
Always be aware of the data type when manipulating or processing images. You may need to scale or convert back and forth, using a double type for calculations (since integers saturate) and a uint8 type for display and reading/writing to files.

How can I imwrite a double in Matlab?

I am producing 3500x7500 size double matrices in a loop that I want to export as tif files.
A section of the code
for k = 1:length(basinlist{1})
#some operation that produces GRID
imwrite(GRID,filename);
end
But, when I do this, the TIF file produced contains only 255 and output is in uint8. I read about it in the documentation, but I am not able to fix it. All I want is to retain the original values with no scaling or anything.
If this helps:
>> max(max(GRID))
ans =
1.5646e+04
>> min(min(GRID))
ans =
1.1119e+03
Suppose we want to create image with such colour depth that will fit to given data.
Data exported to image format are converted to uint8 by default (data range 0-2^8-1).
But Matlab (2011b) can operate with more uintX formats where X stands for X bits per value.
uint8 with span 0-255 (2^8)
uint16 with span 0-65 535 (2^16)
uint32 with span 0-4.29 e 9 (2^32)
uint64 with span 0-1.84 e 19 (2^64)
Code to export data without any loss:
for k = 1:length(basinlist{1})
#some operation that produces GRID
%% Convert GRID to roughest acceptable uint format
GRID=uint16(GRID);
%% Export
imwrite(GRID,filename);
end

Fan Beam reconstruction artifacts in MATLAB

I have a set of pictures on which I need to perform Fan Beam projection and reconstruction by MATLAB. But for these pictures I've got weird artifacts.
Following the documentation on ifanbeam() function, I've written the following code:
ph = phantom(100);
d = 100;
fan_proj = fanbeam(ph,d);
fan_reproj = ifanbeam(fan_proj,d);
imshow(fan_reproj)
And it worked well:
But then i tried to explicitly save the phantom image on the drive (instead of loading it from MATLAB itself), load it from the drive, and perform the same operation.
ph = phantom(100);
imwrite(ph, 'phantom.png');
clear;
ph = imread('phantom.png');
d = 100;
fan_proj = fanbeam(ph,d);
fan_reproj = ifanbeam(fan_proj,d);
imshow(fan_reproj)
And the result was suffering from weird artifacts:
Why does this happen? What exactly changes in the image so the result of this function also changes so dramatically?
The issue is that imshow (by default) expects the input data to have values between 0 and 1. This is true when you first construct the phantom.
ph = phantom(100);
min(ph)
0
max(ph)
1
But when you load it back from the file it will have values between 0 and 255. This is because it was saved and loaded back in as an unsigned 8-bit integer:
ph = imread('phtnom.png');
class(ph)
uint8
min(ph)
0
max(ph)
255
And when you use imshow with the default color scaling it will still be [0,1] causing the extreme contrast that you are seeing.
You can use [] as the second input to imshow to ensure that the full dynamic range of the image is displayed.
imshow(fan_reproj, [])

normalize values for imadjust

I am trying to use imadjust, and in order to do that I have to normalize the values in my image (grayscale image) to 0~1. I have tried the following:
for getting min/max values:
minValue = min(I(:));
maxValue = max(I(:));
than I tried using imadjust in some ways:
Iadjusted = imadjust(I,[lowestValue/highestValue; highestValue/highestValue] ,[0 1]);
Iadjusted = imadjust(I,[lowestValue/255; highestValue/255] ,[]);
Iadjusted = imadjust(I,[double(lowestValue/highestValue); double(highestValue/highestValue)] ,[]);
but none of them worked. Each of them shows error/ shows the original image without any change. When I displayed min/max values the results were right, but when I am trying to display to normalization it always shows 0 or 1. What am I doing wrong?
In MATLAB images are stored using uint8 by default, therefore in [0 1] you can only have two integer number (i.e. 0 and 1). To do what you want between and get an image with range [0, 1] you have to use doubles.
Therefore if you want to use imadjust:
I = double(I)/255;
J = imadjust(I,[min(I(:)); max(I(:))],[0.0; 1.0]);
(Imadjust with doubles wants everything to be between 0 and 1. This is true in general for images expressed with doubles).
This function adjusts a signal (can be image) to the range [0,1]
function normsig = normalize(sig)
sig = double(sig);
normsig = (sig-min(sig(:))) / (max(sig(:))-min(sig(:))) ;
end
usage for an image signal:
img = imread('xxxx.jpg','jpg');
figure; imshow(img);
normalizedimg = normalize(img);
figure; imshow(normalizedimg);

How do I write an image to a file

I am particularly stuck in this case
I = imread('liftingbody.png');
S = qtdecomp(I,.27);
blocks = repmat(uint8(0),size(S));
for dim = [512 256 128 64 32 16 8 4 2 1];
numblocks = length(find(S==dim));
if (numblocks > 0)
values = repmat(uint8(1),[dim dim numblocks]);
values(2:dim,2:dim,:) = 0;
blocks = qtsetblk(blocks,S,dim,values);
end
end
blocks(end,1:end) = 1;
blocks(1:end,end) = 1;
imshow(I), figure, imshow(blocks,[])
( The example above is from the MATLAB help )
If I try to write the image i.e blocks using imwrite(blocks) then the whole image appears to be black. This happens for any input images. But I want to write exactly the output that imshow shows here. Can anyone help ?
You created blocks as a uint8 matrix. By convention, MATLAB and Image Processing Toolbox treat a uint8 grayscale as having a range of values from 0 to 255. That is, 0 is black and 255 is white. So your blocks matrix, which contains only 0s and 1s, would normally be displayed as black and almost-black.
When you displayed blocks using:
imshow(blocks,[])
You used the "auto-ranging" syntax of imshow, which displays the minimum value of blocks as black and the maximum value of blocks as white.
But then when you saved blocks using imwrite, it made the normal assumption of 0 as black and 255 as white.
Try initializing blocks as a logical matrix instead, like this:
blocks = logical(size(S));
MATLAB and Image Processing Toolbox treat a logical matrix as a binary image and will display 0 as black and 1 and white. If you pass a logical matrix to imwrite, it will create a 1-bit-depth binary image file.
a generic answer is to normalize the image to be in the range for imwrite(blocks):
imwrite((blocks-min(blocks))/(max(blocks)-min(blocks)))