How to display a .bin image in Matlab? - image

So I'm sure this is an incredibly simple question, but I'm having trouble reading and displaying data from a .bin file. Basically, I have an image (256x256, 8 bits per pixel) that I'm trying to read in and display. While I can get this to work for a .jpg or .tif, I can't get it to work for a .bin file. Here's my code as of now:
file = fopen('image.bin', 'r');
A = fread(file);
imshow(A) %not sure if this is correct...
% imshow(file) doesn't work
% imshow('image.bin') doesn't work either
fclose(file);
Any ideas?

I'm going to assume that your .bin file consists of raw image intensities that are stored in a binary file. Your fread call will simply read the contents of the file into an array, but you need to be careful. By default, the values will be read in as 64-bit double values in MATLAB so what will happen is that a single double value will contain 8 image pixels. As such, what you need to do is modify how the values are being read in with fread. Specifically, you need to do this:
A = fread(file, 256*256, 'uint8=>uint8');
This is saying that you are going to read a total of 256 x 256 image pixels, where the input binary file stores the data in unsigned 8-bit integers. After, the data is read into MATLAB as the same type. Now, what you need to do next is to reshape the array so that it becomes a 256 x 256 image.
However, because fread reads in the data in column-major, each row of this reshaped image would be placed into the columns, and so you need to transpose the reshaped matrix when you're done. Specifically:
A = reshape(A, 256, 256).';
Now, A would be your 256 x 256 image that you are seeking. You can now show this image with imshow(A);.

Related

A proper way to convert 2D Array into RGB or GrayScale image for precision difference

I have a 2D CNN model where I perform a classification task. My images are all coming from a sensor data after conversion.
So, normally, my way is to convert them into images using the following approach
newsize = (9, 1000)
pic = acc_normalized[0]
img = Image.fromarray(np.uint8(pic*255), 'L')
img = img.resize(newsize)
image_path = "Images_Accel"
image_name = "D1." + str(2)
img.save(f"{image_path}/{image_name}.jpeg")
This is what I obtain:
However, their precision is sort of important. For instance, some of the numerical values are like:
117.79348187327987 or 117.76568758022673.
As you see in the above line, their difference is the digits, when I use uint8, it only takes 117 to when converting it into image pixels and it looks the same, right? But, I'd like to make them different. In some cases, the difference is even at the 8th or 10th digit.
So, when I try to use mode F and save them .jpeg in Image.fromarray line it gives me error and says that PIL cannot write mode F to jpeg.
Then, I tried to first convert them RGB like following;
img = Image.fromarray(pic, 'RGB')
I am not including np.float32 just before pic or not multiplying it by 255 as it is. Then, I convert this image to grayscale. This is what I got for RGB image;
After converting RGB into grayscale:
As you see, it seems that there is a critical different between the first pic and the last pic. So, what should be the proper way to use them in 2D CNN classification? or, should I convert them into RGB and choose grayscale in CNN implementation and a channel of 1? My image dimensions 1000x9. I can even change this dimension like 250x36 or 100x90. It doesn't matter too much. By the way, in the CNN network, I am able to get more than 90% test accuracy when I use the first-type of image.
The main problem here is using which image conversion method I'll be able to take into account those precision differences across the pixels. Would you give me some idea?
---- EDIT -----
Using .tiff format I made some quick comparisons.
First of all, my data looks like the following;
So, if I convert this first reading into an image using the following code where I use np.float64 and L gives me a grayscale image;
newsize = (9, 1000)
pic = acc_normalized[0]
img = Image.fromarray(np.float64(pic), 'L')
img = img.resize(newsize)
image_path = "Images_Accel"
image_name = "D1." + str(2)
img.save(f"{image_path}/{image_name}.tiff")
It gives me this image;
Then, the first 15x9 matrix seems like following image; The contradiction is that if you take a closer look at the numerical array, for instance (1,4) member, it's a complete black where the numerical array is equal to 0.4326132099074307. For grayscale images, black means that it's close to 0 cause it makes white if it's close to 1. However, if it's making a row operation, there is another value closer to 0 and I was expecting to see it black at (1,5) location. If it does a column operation, there is again something wrong. As I said, this data has been already normalized and varies within 0 and 1. So, what's the logic that it converts the array into an image? What kind of operation it does?
Secondly, if I first get an RGB image of the data and then convert it into a grayscale image, why I am not having exactly the same image as what I obtained first? Should the image coming from direct grayscale conversion (L method, np.float64) and the one coming from RGB-based (first I get RGB then convert it to grayscale) be the same? There is a difference in black-white pixels in those images. I do not know why we have it.
---- EDIT 2 ----
.tiff image with F mode and np.float32 gives the following;
I don't really understand your question, but you seem to want to store image differences that are less than 1, i.e. less than the resolution of integer values.
To do so, you need to use an image format that can store floats. JPEG, PNG, GIF, TGA and BMP cannot store floats. Instead, use TIFF, EXR or PFM formats which can handle floats.
Alternatively, you can create 16-bit PNG images wherein each pixel can store values in range 0..65535. So, say the maximum difference you wanted to store was 60 you could calculate the difference and multiply it by 1000 and round it to make an integer in range 0..60000 and store as 16-bit PNG.
You could record the scale factor as a comment within the image if it is variable.

JPG sizes not as expected

I have read severel posts like this one claiming that the size of a JPG texture can be calculated as
If each pixel contains 32 bits of information, then
307,200 * 32 = 9,830,400 bits of information
Divide by the 8 bits to become a byte value
9,830,400 / 8 = 1228800 bytes (Or 1.17 Mb)
which totally makes sense since each pixel is represented by a color value. Here comes the weird part:
I have these two JPG files
First JPG
which has the dimensions 242x198 and uses 24-bit color values.
Second JPG
which has the dimensions 3840x2400 and uses 24-bit color values.
Then I tried to calculate the sizes using the technique above and concluded that
The first JPG must have the size 242*198*24 = 1149984 bits = 1149984/8/1000 = 143.7 kb - now the actual file size is 47,6 kb?? So the calculation apparently gives a number above the actual size, why?
The second JPG must have the size 3840*2400*24 = 221184000 = 221184000/8/10000 = 27.6 mb - now the actual file size is 7.33 mb. So the calculation apparently gives a number above the actual size, why?
I have myself managed to draw the first JPG and made sure to export it without compression (JPG 100).
The whole point of JPEGs is that they are compressed to take up less space. If you resave your file as a BMP you'll get the sizes you expect (plus a bit extra for headers and alignment).

saving a very large image in MATLAB

I know that this question has been asked before. But, I could not find a clear answer for it. I have data for a very high resolution colorful image with the size of 50,000 by 60,000 with the data type unit8. I cannot save the entire image by using imwrite. I have gotten the error that says:
"Images must contain fewer than 2^32 - 1 bytes of data"
Is there a way to save the entire image in MATLAB?
right now, I have to break the data into smaller pieces (sub-images) and then use imwrite to write each piece to a png file. The output format of the file is not important.
Your image occupies 8*50000*60000*3 = 7.2000e+10 bytes of data that is 16.7638 times more than MATLAB image size limit. Why no to split it in 20 pieces, save them and then merge them manually? If you split your image into 6 8x50000x3000x3 pieces, they would all fit into 2^32 limit.
I am sure OP has enough aptitude to do this, but I'll explain the procedure anyway. Convert your image into 50000x60000x3 array and do the following:
x = 0:3000:60000;
for i = 1:length(x)-1
imwrite(A(:,x(i)+1:x(i+1),:),strcat('image',num2str(i),'.png'),'png');
end
This would create 20 images for you with names 'image1.png', 'image2.png' and so on. Then, you can merge these images manually using this first google search result. Perhaps, there is some fancier way to do this, but I think this is the easiest one.
Another question has an answer which worked for me: if your image is stored as a double matrix, convert to uint8 with im2uint8(img), then save.

Extra data within image (PPM/PAM/PNM)

Is it possible to store extra data in pixels of a binary PNM file in such a way that it can still be read as an image (hopefully by any decoder, but specifically by ffmpeg)?
I have a simulation that saves its data as PPM currently and I'd like a way to record more than three values per pixel in the file, and yet still be able to use it as an image (obviously only the first three/four values will actually affect the image).
In particle I think the TUPLTYPE of PAM should allow me to do this, but I don't know how make something that's also a readable image from that.
There are two tricks which together can get up to 5 additional bytes per pixel in PAM file.
First trick:
You can try store additional byte of information in alpha channel and then choose to ignore that information in decoder. Enabling alpha channel in PAM is done by adding _APLHA to TUPLTYPE argument, so instead TUPLTYPE RGB you have TUPLTYPE RGB_ALPHA.
Second trick:
You can set MAXVAL in PAM (or equivalent field in PPM and others) to 65535 instead of 255, which means that every pixel will be described by three 16-bit values instead of three 8-bit ones. Now, for these 16-bit values the 8 least significant bits can be used to store information as they do not affect visual properties of image when shown on typical computer screen.
First + second trick:
This gives you additional 3 x 8 = 24 bits for RGB planes and 16 bits in alpha channel. Which means: 5 bytes.
I've not used PNM file format, but I've done this trick with a .bmp file.
Hijack the least significant bit of the image data and stuff it with whatever binary data you want. Nobody will see the difference between a pixel value of a 0 or 1 (00000000 or 00000001), or the the difference between a 254 or 255 (1111110 or 11111111). For every 8 bytes of image data a byte of extra data can be embedded (6 bytes if you use a limited character set). The file viewing software won't know any difference. Any software which could open the file before the encoding, would be able to read it after.
If you want the data to be more covert/hidden, the bits can be stuffed into the image data with a shuffle routine, where the first bit might be location 50, the second in 123, the third in 32... and after locations 0-255 (first 256 bytes if image data) are used (first 32 bytes of extra data), start the shuffle again.

imread altering image in Matlab?

I am having an issue reading a single image of a stacked tiff in using imread. The tiff is 128-by-126. It reads in just fine with ImageJ, but I try reading it into Matlab for some processing and it creates an odd streak in the center of the image. With the origin of the image in the top left, rows 63 and 64 are repeated as rows 65 and 66, and the last two rows of the image, 125 and 126 are cut off. I can tell this is happening by visual comparison of the image displayed in matlab to the image displayed in ImageJ.
If I take the same tiff stack, and save the first frame in ImageJ, I don't have this issue. Even when displaying the outputted matlab image using ImageJ, I see the same issue. However, I would like to automate the process to save images from several tiff stacks as single tiff files, which I can't do in ImageJ, so I turned to Matlab and ran into this issue. I have included my code below. I tried reading the tiff in two different ways and got the same error. It seems to be related to the tiff stack and how matlab reads in the tiffs. I am using Matlab R2012b.
I have included links below to the static ImageJ image I am seeing and the static matlab image I am seeing. I have also included a link for loading the stacked tiff file that is generating these issues for me.
Note: When I have ImageJ output each frame as an individual tiff and I open the first frame from that output in matlab using the same code below, the image is correctly displayed. The error only occurs when reading in the first frame from the image stack in Matlab.
StackOverflow doesn't support embedding TIFF files, but you can view and download them from these links:
Stacked Tiff File - Data I am working with
What the first frame should look like - ImageJ
What I am seeing when loading the first frame in MATLAB
Code Used to Generate the Image
fname='C:\FileLocation\pcd144_012.tif';
im1=imread(fname,1)
imagesc(im1);
axis image; colormap gray;
I tried reading in the image as a tiff object to see if it solved the problem and this didn't work either. The image has two strips, and the last two lines of the first strip are the same as the first two lines of the last strip, which is why the middle lines seem to be repeated. It seems matlab is indexing reading my image in wrong, likely because it is not a square image. Am I just doing something wrong, or does matlab have a bug with respect to reading in non-square tiffs? Any ideas or suggestions for improvement?
First of, I kinda agree with horchler, that is, there is something wrong in your header.
We can easily observe that the StripByteCounts (15872) does not match width*height (128*126). This could be the reason you see the repetition in row 63 - 64 and 65 - 66.
Since the RowPerStrip = 64 and StripOffsets = [8,15880] may indicate that you have a 128*124 graph, Matlab perhaps uses last two rows in the first 64 rows to pad the missing rows at the beginning of the rest of the rows. So the total row can be filled up to 126. Well, this is just my guess for how Matlab handles the disagreement between dimension and ByteCounts.
After all, to your question, imread indeed alters image in Matlab when reading TIFF without issuing any warning. Bad job in imread reading TIFF, Matlab.
After observing your TIFF frames in one of your links, the TIFF seems to actually have image data with dimension 128*126. So if you trust the dimension indicating in the header, you would probably use fread to read the frames in your TIFF instead of using shaky imfread.
fname='pcd144_012.tif';
tiffInfo = imfinfo(fname);
framIndex = 1;
tiffWidth = tiffInfo(framIndex).Width; % image width
tiffHeight = tiffInfo(framIndex).Height; % image height
tiffStartOffset = tiffInfo(framIndex).StripOffsets(1); % Image data offset start point
tiffEndOffset = tiffInfo(framIndex).StripOffsets(2); % Image data offset end point
fid = fopen(fname);
fseek(fid,tiffStartOffset,'bof');
im1 = fread(fid,tiffWidth*tiffHeight,'*uint16'); % We knew this from BitsPerSample
fclose(fid);
im1 = reshape(im1,tiffWidth,tiffHeight); % Reshape the image data array
figure
imagesc(im1);
colormap gray;
axis xy;
axis image;
Now, while this may solve the weird Matlab imread behavior, however, the above result still does not match the picture you showed in your second link. According to the picture in the second link, it has 300 frames but the one you attached in your first link only has 30 frames. Maybe we are all looking at the wrong picture?

Resources