Converting raw bytes to image - python

I have a file that contains a 240x320 image but its byte format I opened it in a hex editor and got what something like an array 16 columns 4800 raw.
Im completely new to this thats why im facing trouble I have tried using a python script but it gave an error on line 17, in data = columnvector[0][i]:
IndexError: list index out of range.
I have tried a java code but that was an error as well, I wanted to try some c# codes but none of the codes i found explains how i can feed my file to the code. This is the python code
import csv
import sys
import binascii
csv.field_size_limit(500 * 1024 * 1024)
columnvector = []
with open('T1.csv', 'r') as csvfile:
csvreader = csv.reader(csvfile,delimiter=' ', quotechar='|')
for row in csvreader:
columnvector.append(row)
headers =['42','4D','36','84','03','00','00','00','00','00','36','00','00','00','28','00','00','00',
'40','01','00','00','F0','00','00','00','01','00','18','00','00','00','00','00','00','84','03','00','C5','00',
'00','00','C5','00','00','00','00','00','00','00','00','00','00','00']
hexArray=[]
for i in range(0,76800):
data = columnvector[0][i]
hexArray.extend([data,data,data])
with open('T1.txt', 'wb') as f:
f.write(binascii.unhexlify(''.join(headers)))
f.write(binascii.unhexlify(''.join(hexArray)))
I want to convert the file to an image using any method I honestly don't care what method to use just as long as it gets the job done.
this is some the files
https://github.com/Mu-A/OV7670-files/tree/Help

You can make the binary data into images without writing any Python, just use ImageMagick in the Terminal. It is included in most Linux distros and is available for macOS and Windows.
If your image is 320x240 it should be:
320 * 240 bytes long if single channel (greyscale), or
320 * 240 * 3 if 3-channel RGB.
As your images are 76800, I am assuming they are greyscale.
So, in Terminal, to make that raw data into a JPEG, use:
magick -depth 8 -size 320x240 gray:T1 result.jpg
or, if you are using version 6 of ImageMagick, use:
convert -depth 8 -size 320x240 gray:T1 result.jpg
If you want a PNG with automatic contrast-stretch, use:
magick -depth 8 -size 320x240 gray:T1 -auto-level result.png
Unfortunately none of your images come out to anything sensible. Here is T1, for example:
The histograms do look somewhat sensible though:
I think you have something fundamentally wrong so I would try reverting to first principles to debug it. I would shine a torch into, or point the camera at a window and save a picture called bright.dat and then cover the lens with a black card and take another image called dark.dat. Then I would plot a histogram of the data and see if the bright one was at the rightmost end and the dark one was at the leftmost end. Make a histogram like this:
magick -depth 8 -size 320x240 Gray:bright.dat histogram:brightHist.png
and:
magick -depth 8 -size 320x240 Gray:dark.dat histogram:darkHist.png

for i in range(0,76800):
is a hardcoded value, and because columnvector[0][i] does not have that many values, you get that IndexError: list index out of range.
Consider why you need to set your range from 0-76800 or if the value can be dynamically sourced from len() of something.

Another simple way to make an image from a binary file is to convert it to a NetPBM image.
As your file is 320x240 and 8-bit binary greyscale, you just need to make a header with that information in it and append your binary file:
printf "P5\n320 240\n255\n" > image.pgm
cat T1 >> image.pgm
You can now open image.pgm with feh, Photoshop, GIMP or many other image viewers.

Related

How to read .img files in python?

I have an image in format .img and I want to open it in python. How can I do it?
I have an interference pattern in *.img format and I need to process it. I tried to open it using GDAL, but I have an error:
ERROR 4: `frame_064_0000.img' not recognized as a supported file format.
If your image is 1,024 x 1,024 pixels, that would make 1048576 bytes, if the data are 8-bit. But your file is 2097268 bytes, which is just a bit more than double the expected size, so I guessed your data are 16-bit, i.e. 2 bytes per pixel. That means there are 2097268-(2*1024*1024), i.e. 116 bytes of other junk in the file. Folks normally store that extra stuff at the start of the file. So, I just took the last 2097152 bytes of your file and assumed that was a 16-bit greyscale image at 1024x1024.
You can do it at the command-line in Terminal with ImageMagick like this:
magick -depth 16 -size 1024x1024+116 gray:frame_064_0000.img -auto-level result.png
In Python, you could open the file, seek backwards 2097152 bytes from the end of the file and read that into a 1024x1024 np.array of uint16.
That will look something like this:
import numpy as np
from PIL import Image
filename = 'frame_064_0000.img'
# set width and height
w, h = 1024, 1024
with open(filename, 'rb') as f:
# Seek backwards from end of file by 2 bytes per pixel
f.seek(-w*h*2, 2)
img = np.fromfile(f, dtype=np.uint16).reshape((h,w))
# Save as PNG, and retain 16-bit resolution
Image.fromarray(img).save('result.png')
# Alternative to line above - save as JPEG, but lose 16-bit resolution
Image.fromarray((img>>8).astype(np.uint8)).save('result.jpg')

Replace white coloured rows in image using python

I am trying to trim parts of the image where a complete row of Image doesn't have anything except white color.
I tried using matplot lib
convert image into matrix and saw if (r,g,b) = (0,0,0) or (1,1,1) and removed entire row in image if every (r,g,b) is of above kind in the row
matrix looks like [ [ [r,g,b], [r,g,b]....] ],...., [ [r,g,b], [r,g,b]....] ] ]
i achieved my requirement but i am running this for around 500 images and it is taking 30 minutes around. Can i do it in better ways?
and the required image should be like
Edit-1 :
tried with trim method from wand package
with wand_img(filename=path) as i:
# i.trim(color=Color('white'))
# i.trim(color=Color('white'))
i.trim()
i.trim()
i.save(filename='output.png')
but not working for the following type of images
You could use ImageMagick which is installed on most Linux distros and is available for macOS and Windows.
To trim one image, start a Terminal (or Command Prompt on Windows) and run:
magick input.png -fuzz 20% -trim result.png
That will give you this - though I added a black border so you can make out the extent of it:
If you have lots to do, you can do them in parallel with GNU Parallel like this:
parallel -X magick mogrify -trim ::: *png
I made 1,000 copies of your image and did the whole lot in 4 seconds on a MacBook Pro.
If you don't have GNU Parallel, you can do 1,000 images in 12 seconds like this:
magick mogrify -trim *png
If you want to do it with Python, you could try something like this:
#!/usr/bin/env python3
from PIL import Image, ImageChops
# Load image and convert to greyscale
im = Image.open('image.png').convert('L')
# Invert image and find bounding box
bbox = ImageChops.invert(im).getbbox()
# Debug
print(*bbox)
# Crop and save
result = im.crop(bbox)
result.save('result.png')
It gives the same output as the ImageMagick version. I would suggest you use a threading tool to do lots in parallel for best performance.
The sequential version takes 65 seconds for 1,000 images and the multi-processing version takes 14 seconds for 1,000 images.
Using two trims in Imagemagick 6.9.10.25 Q16 Mac OSX Sierra works fine for me. Your image has a black bar on the right hand side. The first trim will remove that. The second trim will remove the remaining excess white. You may need to add some fuzz (tolerance) amount for the trim. But I did not need it.
Input:
convert img.png -trim +write tmp1.png -trim result.png
Result of first trim (tmp1.png):
Final Result after second trim:
ADDITION:
Looking at the docs for Python Wand:
trim(*args, **kwargs)
Remove solid border from image. Uses top left pixel as a guide by default, or you can also specify the color to remove.
Parameters:
color (Color) – the border color to remove. if it’s omitted top left pixel is used by default
fuzz (numbers.Integral) – Defines how much tolerance is acceptable to consider two colors as the same.
You will need to specify color=black for the first trim, since this version of trim uses the top left corner for trimming. Command line Imagemagick looks at all corners. If that fails, then add some fuzz value.

How to convert all bytes files under the folder into images

import numpy
from PIL import Image
import binascii
def getMatrixfrom_bin(filename,width):
with open(filename, 'rb') as f:
content = f.read()
...
return fh
filename = "path\bin_filename(1)"
im = Image.fromarray(getMatrixfrom_bin(filename,512))
//getMatrixfrom_bin () is a function that generates a matrix from the binary bytes
im.save("path\bin_filename(1).png")
The code above can only generate a picture at a time, now I need to convert all the binary files under the path to images, how should I do?
If you are on a decent (i.e. Unix/Linux/macOS) platform, you can convert all your binary files to PNG images in parallel without writing any Python, if you use GNU Parallel and ImageMagick which are installed on most Linux distros and are available for macOS via homebrew.
So, the command to convert all files ending in .bin into PNG images, in parallel would be:
parallel 's=$(wc -c < {}); w=512; ((h=s/w)); convert -depth 8 -size ${w}x${h} gray:{} {.}.png' ::: *bin
That is a bit scary if you are not accustomed to it, so I'll break it down. Basically it is running "some stuff" in parallel for all files ending in .bin, so look again and it is:
parallel 'some stuff' ::: *.bin
What is the "some stuff"? Well, note that {} is short-hand for the file we are currently processing, so it is doing this:
s=$(wc -c < {}) # s=total bytes in current file, i.e. s=filesize
w=512 # w=image width
((h=s/w)) # h=s/w, i.e. h=height in pixels of current file
convert ...
The last line, the one starting convert is calling ImageMagick telling it your image depth is 8 bits, and the dimensions in pixels are WxH, it is then reading the current file into an image and saving it as a new image ending in PNG instead of the original extension. Easy!
Of course, if you knew the width was 500 pixels and the height was 400 pixels, life would be even easier:
parallel 'convert -depth 8 -size 500x400 gray:{} {.}.png' ::: *bin

Read .img medical image without header in python

I have a radiograph .img file without the header file. However, the researchers who have published the file have given this information about it
High resolution (2048 × 2048 matrix size, 0.175mm pixel size)
Wide density range (12-bit, 4096 gray scale)
Universal image format (no header, big-endian raw data)
I am trying to open the file using Python but unable to do so. Could someone suggest any method to read this image file?
I found some radiograph images, like yours, by downloading the JSRT database. I have tested the following code on the first image of this database: JPCLN001.IMG.
import matplotlib.pyplot as plt
import numpy as np
# Parameters.
input_filename = "JPCLN001.IMG"
shape = (2048, 2048) # matrix size
dtype = np.dtype('>u2') # big-endian unsigned integer (16bit)
output_filename = "JPCLN001.PNG"
# Reading.
fid = open(input_filename, 'rb')
data = np.fromfile(fid, dtype)
image = data.reshape(shape)
# Display.
plt.imshow(image, cmap = "gray")
plt.savefig(output_filename)
plt.show()
It produces an output file JPCLN001.PNG which looks like this:
I hope I have answered to your question.
Happy coding!
Just in case anybody else is looking at these images and wants to convert them in batches, or outside of Python and without needing any programming knowledge... you can convert them pretty readily at the command line in Terminal with ImageMagick (which is installed on most Linux distros anyway, and available for OS X and Windows) like this:
convert -size 2048x2048 -depth 16 -endian MSB -normalize gray:JPCLN130.IMG -compress lzw result.tif
which makes them into compressed 16-bit TIF files that can be viewed in any application. They also then take up half the space on disk without loss of quality since I specified LZW compression.
Likewise, if you want 16-bit PNG files, you can use:
convert -size 2048x2048 -depth 16 -endian MSB -normalize gray:JPCLN130.IMG result.png

Why saving as pdf with PIL creates a grey zone around fonts

I want to convert a pdf file to png to manipulate within Python, and the save it back as a pdf, but in the process a grey zone gets created around the fonts (my image is a simple black and white typed document). It's very faint, a bit hard to see on a screen, but when printed it becomes fairly visible.
Here's the specific command I use:
PDF to PNG (in greyscale, super-sampling to preserve image quality):
convert -density 500 -alpha off file_in.pdf -scale 1700x2200 -bordercolor black -border 1x1 -fuzz 20% -trim +repage -colorspace Gray -depth 4 file_out.png
within Python
import Image
img = Image.open('file_out.png')
img.save('file_out2.pdf')
I also tried converting pdf to png with Ghostscript:
gs -sDEVICE=png16m -sOutputFile=file.png -dNOPAUSE -dBATCH -r300 file_out.pdf
with the save result.
Here's part of what
identify -verbose file.png
gives for the ImageMagick png :
Format: PNG (Portable Network Graphics)
Class: PseudoClass
Geometry: 1700x2200+0+0
Resolution: 500x500
Print size: 3.4x4.4
Units: Undefined
Type: Grayscale
Base type: Grayscale
Endianess: Undefined
Colorspace: Gray
Depth: 8/4-bit
Channel depth:
gray: 4-bit
Anyone have a solution? or at least an explanation?
Edit:
I found that using '-sample 1700x2200' instead of '-scale 1700x2200' fixed the grey around the fonts, but then the thin lines almost disappear and the font suffers from aliasing...
The pdf format is basically a vector format that can also include bitmapped ("raster") images.
If the original pdf contains a scanned document, it will usually only contain a bitmapped image (often in tiff or jpeg format) and then converting it to png is fine (if you stick to the original resolution of the image).
But if the original contains vector graphics (including text strings), converting those to a bitmap will generally introduce sampling errors. To avoid those, you canuse 1-bit color depth ("black-and-white" format) and a resolution that at least matches the printer. This will produce quite a large file png file, though. Using the tiff format might yield a smaller file. The "tiff-inside-pdf" format is something you see often when large drawings are scanned. According to ImageMagick's identify program, such a tiff file looks something like this:
Format: TIFF (Tagged Image File Format)
Class: DirectClass
Geometry: 13231x9355+0+0
Resolution: 400x400
Print size: 33.0775x23.3875
Units: PixelsPerInch
Type: Bilevel
Base type: Bilevel
Endianess: MSB
Colorspace: Gray
Depth: 1-bit
Channel depth:
gray: 1-bit
Dispite the huge size, the tiff file is only 144 kb. The tiff2pdf program (part of the tiff package) can convert these to nice and small pdf files.
But the best way to preserve the document's format is to edit the pdf file itself, instead of converting it to another format.
There is a Python module for manipulating pdf documents; PyPDF2. But since you don't specifiy what you want to do with the document, it is impossible to say if this can do what you want. There is also ReportLab, but that's more for generating pdf files. If you have the cairo library installed on your system, pycairo is a less heavyweight option to generate pdf documents.
An excellent utility in general for manipulating pdf files is pdftk (written in java).
Edit: Sampling in grayscale will always introduce sampling artefacts. These are not errors in themselves, just a consequence of the sampling process.
Decompiling the pdf file into PostScript as Ben Jackson mentions can be done. There are a couple of utilities that can help you with that; pdftops from the poppler-utils package, and pdf2ps that comes with ghostscript. In my experience, pdftops tends to produce better usable output.
But I haven't found a good way to automate this process. Below is a fragment from the Numpy User Guide decompiled with pdftops:
(At)
[7.192997
0
2.769603
0] Tj
-314 TJm
(the)
[2.769603
0
4.9813
0
4.423394
0] Tj
-313 TJm
(core)
[4.423394
0
4.9813
0
3.317546
0
4.423394
0] Tj
-314 TJm
(of)
[4.9813
0
3.317546
0] Tj
-313 TJm
(the)
[2.769603
0
4.9813
0
4.423394
0] Tj
-314 TJm
(NumPy)
[7.192997
0
4.9813
0
7.750903
0
5.539206
0
4.9813
0] Tj
-314 TJm
(package,)
[4.9813
0
4.423394
0
4.423394
0
4.9813
0
4.423394
0
4.9813
0
4.423394
0
2.49065
0] Tj
-329 TJm
This produces the sentence "At the core of the Numpy package," So if you look into the PostScript file for anything between (), you'll get the strings.
So changing individual words or removing short pieces is not that hard;
Find the correct word(s) in the decompiled PostScript.
Edit them (and the surrounding parameters!)
Re-compile to pdf (with ghostscript).
But you would have to look into the beginning of the document and see what the functions Tj and TJm do. If you want to replace text, you'll have to remove them and put in new text and code with the correct parameters for Tj and TJm. This requires an understanding of PostScript. And if you are replacing a sentence, you usually cannot replace it with a longer sentence; there will not be enough space...
Therefore it is generally advisable to try and get the original application to change the output.
Is there no way to get a good sampling in greyscale? What I want to do is open the file with PIL, to add some text and overlay an image
A PDF is a compressed PostScript document (plus metadata). PostScript is a programming language. If you use pdf2ps you can then add code to the PostScript to draw over any existing parts of the PDF. Then convert back with pdf2ps.
Here's another question that deals with that idea directly: Is it possible in Ghostscript to add watermark to every page in PDF

Categories