Maxwell Grady
Maxwell Grady

Reputation: 316

Reading data from a 16-bit unsigned big endian raw image file in python

I have some images I want to analyze using a python script. They are stored as raw binary data files. They are in the following format. 16-bit unsigned, big endian, 592x600 pixels with a 520 byte header.

When I look at the .dat file in my OS (OS X yosemite) I see that the file is 710,920 bytes

This makes sense as (592 x 600 pixels) * (2 bytes per pixel) = 710,400 bytes. Thus the remainder is the 520 byte header.

I want to write a quick python script to generate an array of the pixel values. i.e. I want to ditch the header of the file and store the rest of the data as an array so that I can use something like PIL to then quickly convert into an image and output a jpg or png.

Just doing something really quick quick:

myfile = open('test.dat', 'rb') 

data = myfile.read()

len(data)

trimdata = data[520:]

len(trimdata)

This gives me the raw data without the header.

From here I am unsure about the easiest way to parse the data into a 592x600 array that I can then use with PIL to export a quick greayscale image.

here is a link to the file incase that helps out: test.dat

Edit: Thanks for all the help - It appears the data was Little Endian not Big Endian after all. Cheers.

Upvotes: 1

Views: 6648

Answers (2)

Mark Ransom
Mark Ransom

Reputation: 308530

PIL should be able to read that data directly, but heck if I can figure out how to do it. It doesn't take too many steps to do it indirectly though.

fmt = '>' + str(592*600) + 'H'
pix = struct.unpack(fmt, trimdata)
scaled_pix = ''.join(chr(p/256) for p in pix)
im = Image.fromstring('L', (592,600), scaled_pix, 'raw')

Edit: It looks like your sample picture is little-endian, not big-endian. Here's some corrected code. I also threw in automatic brightness scaling and gamma correction, since the full 16-bit scale wasn't being used.

fmt = '<' + str(592*600) + 'H'
pix = struct.unpack(fmt, trimdata)
lightest = max(pix)
scaled = ''.join(chr(int((float(p) / lightest)**(1/2.2) * 255)) for p in pix)
im = Image.fromstring('L', (592,600), scaled, 'raw')

enter image description here

Upvotes: 2

Mark Setchell
Mark Setchell

Reputation: 208077

You can convert them to quick JPEGs without writing any Python at all using ImageMagick's convert from the commandline.

Just tell ImageMagick the size and bit depth and data offset and it can make a greyscale JPEG or 16-bit TIFF for you.

Something like this but I do not have my Mac to hand to test:

convert -size 592x600+520 -depth 16 GRAY:image.dat output.jpg

You may need -endian MSB (or LSB) before the first filename too.

I am back at my Mac now, and the command to produce this image is:

convert -size 592x600+520 -depth 16 -endian MSB GRAY:image.dat -auto-level output.jpg

enter image description here

Upvotes: 2

Related Questions