I have a raw image where each pixel corresponds to a 16 bits unsigned integer. I am trying to read using the PIL Image.fromstring() function as in the following code:
if __name__ == "__main__": if (len(sys.argv) != 4): print 'Error: missing input argument' sys.exit() file = open(sys.argv[1], 'rb') rawData = file.read() file.close() imgSize = (int(sys.argv[2]), int(sys.argv[3])) # Use the PIL raw decoder to read the data. # - the 'F;16' informs the raw decoder that we are reading a little endian, unsigned integer 16 bit data. img = Image.fromstring('L', imgSize, rawData, 'raw', 'F;16') im.save('out.png')
The PIL documentation informs that the first argument of the fromstring() function is 'mode'. However, looking at the documentation and googling I wasn't able to find details about what that argument really means (I believe that it is related to the color space or something like that). Does anyone knows where I can find a more detailed reference about the fromstring() function and what the mode argument means?
The specific documentation is at http://effbot.org/imagingbook/concepts.htm:
Mode
The mode of an image defines the type and depth of a pixel in the image. The current release supports the following standard modes:
- 1 (1-bit pixels, black and white, stored with one pixel per byte)
- L (8-bit pixels, black and white)
- P (8-bit pixels, mapped to any other mode using a colour palette)
- RGB (3x8-bit pixels, true colour)
- RGBA (4x8-bit pixels, true colour with transparency mask)
- CMYK (4x8-bit pixels, colour separation)
- YCbCr (3x8-bit pixels, colour video format)
- I (32-bit signed integer pixels)
- F (32-bit floating point pixels)
PIL also provides limited support for a few special modes, including LA (L with alpha), RGBX (true colour with padding) and RGBa (true colour with premultiplied alpha).
Image.frombuffer(mode, size, data) => image
(New in PIL 1.1.4). Creates an image memory from pixel data in a string or buffer object, using the standard "raw" decoder. For some modes, the image memory will share memory with the original buffer (this means that changes to the original buffer object are reflected in the image). Not all modes can share memory; supported modes include "L", "RGBX", "RGBA", and "CMYK". For other modes, this function behaves like a corresponding call to the fromstring function.
I'm not sure what "L" stands for, but "RGBA" stands for Red-Green-Blue-Alpha, so I presume RGBX is equivalent to RGB (edit: upon testing this isn't the case)? CMYK is Cyan-Magenta-Yellow-Kelvin, which is another type of colorspace. Of course I assume that if you know about PIL you also know about colorspaces. If not, Wikipedia has a great article.
As for what it really means (if that's not enough): pixel values will be encoded differently for each colorspace. In regular RGB you have 3 bytes per pixel - 0-254, 0-254, 0-254. For Alpha you add another byte to each pixel. If you decode an RGB image as RGBA, you'll end out reading the R pixel to the right of the first pixel as your alpha, which means you'll get the G pixel as your R value. This will be magnified depending on how large your image, but it will really make your colors go wonky. Similarly, trying to read a CMYK encoded image as RGB (or RGBA) will make your image look very much not like it's supposed to. For instance, try this with an image:
i = Image.open('image.png') imgSize = i.size rawData = i.tostring() img = Image.fromstring('L', imgSize, rawData) img.save('lmode.png') img = Image.fromstring('RGB', imgSize, rawData) img.save('rgbmode.png') img = Image.fromstring('RGBX', imgSize, rawData) img.save('rgbxmode.jfif') img = Image.fromstring('RGBA', imgSize, rawData) img.save('rgbamode.png') img = Image.fromstring('CMYK', imgSize, rawData) img.save('rgbamode.tiff')
And you'll see what the different modes do - try it with a variety of input images: png with alpha, png without alpha, bmp, gif, and jpeg. It's kinda a fun experiment, actually.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With