tags:

views:

181

answers:

2

I have a string that is read from a usb apogee camera that is a 12-bit grayscale image with the 12-bits each occupying the lowest 12 bits of 16-bits words. I want to create a 8-bit png from this string by ignoring the lowest 4 bits.

I can convert it to a 16-bit image where the highest 4 bits are always zero using PIL with

import Image

#imageStr is the image string
#imageSize is the image size 

img=Image.fromstring("I", imageSize, imageStr, "raw", "I;16", 0,1)
img.save("MyImage.png", "PNG")

Anyway can I do something similar to create a 8-bit image without completely unpacking the string doing arithmetic and making a new string?

Edit: Wumps comment about converting an image gave me an idea, and I did it by

img = img.point(lambda i: i * 16, "L") #shifts by 4 bits and converts to 8-bit image.

Thanks Wump

+1  A: 

The only way I know how to do it would be:

data = numpy.fromstring(imageStr, numpy.uint16)
data >>= 4 # shift out four bits
data = numpy.array(data, dtype=numpy.uint8)
img = Image.fromarray(data.reshape(imageSize))

In principe, PIL can convert images this way:

img = img.convert("L")

But the problem is that it has no way to reduce the precision to 8 bits (AFAIK), so everything will be clipped to 255 :)

Edit: removed intermediate string conversion, it's going directly from numpy to PIL now

wump
+2  A: 

Wump's comment about converting an image gave me an idea, and I did it by

#shifts by 4 bits and converts to 8-bit image
img = img.point(lambda i: i * 16, "L") 

Thanks Wump

ks