I'm working on a Python tool to convert image data into these color formats:
RGB565
RGBA5551
RGBA4444.
What's the simplest way to achieve this?
I've used the Python Imaging Library (PIL) frequently. So I know how to load an image and obtain each pixel value in RGBA8888 format. And I know how to write all the conversion code manually from that point.
Is there an easier way? Perhaps some type of 'formatter' plugin for PIL?
Does PIL already support some of the formats I'm targeting? I can't ever figure out which formats PIL really supports without digging though all of the source code.
Or is there a better library than PIL to accomplish this in Python?
Any tips would be appreciated. Thanks!
Changing something from 8 to 5 bits is trivial. In 8 bits the value is between 0 and 255, in 5 bits it's between 0 and 31, so all you need to do is divide the value with 8. Or 4 in the case for green in RGB565 mode. Or 16 in RGBA4444 mode as it uses 4 bits per channel, etc.
Edit: Reading through your question again, I think there is a confusion (either with me or you). RGB555 and RGBA4444 etc are not really formats, like GIF or JPG, they are color spaces. That conversion is trivial (see above). What file format you want to save it in later is another question. Most file formats have limited support for color spaces. I think for example that JPEG always saves it in YCbCr (but I could be mistaken), GIF uses a palette (which in turn always is RGB888, I think) etc.
There's a module called Python Colormath which provides a lot of different conversions. Highly recommended.
Numpy is powerful indeed, but to get there and back to PIL requires two memory copies. Have you tried something along the following lines?
im = Image.open('yourimage.png')
im.putdata([yourfunction(r,g,b) for (r,g,b) in im.getdata()])
This is quite fast (especially when you can use a lookup table). I am not familiar with the colour spaces you mention, but as I understand you know the conversion so implementation of yourfunction(r,g,b) should be straight forward.
Also im.convert('RGBA', matrix) might be very powerful as it is super fast in applying a colour transformation through the supplied matrix. However I have never gotten that to do what I wanted it to do... :-/
There is also a module named Grapefruit that let you do conversions between quite a lot of color formats.
I ended up doing the conversions manually as Lennart Regebro suggested.
However, pure Python (iterating over each pixel) turned out to be too slow.
My final solution used PIL to load the image and numpy to operate on (convert) an array of pixels.
Related
I am interested in reading the rgb data of a raw image using python. I would like to analyze the rgb of the RAW image with NO filtering and processing done by the DSLR. How would you recommend proceeding? What library etc.? Storing as a numpy array, if possible would be advantageous, I believe. Using openCV was my initial idea, do you recommend anything else?
Like I said, I want to analyze the image as RAW as possible, hence pre-color filter if possible.
Thank you.
If you have the raw image ("my_picture.raw")? You could totally use OpenCV-Python to look at it.
raw_data = imread('my_picture.raw')
This should give you a numpy array of the pixels that your raw file contains.
Then, you can do some basic operations on the data (accessing pixels, doing object/feature recognition, etc.). There's a ton of detail on their website: https://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_core/py_basic_ops/py_basic_ops.html#basic-ops
If you don't have the raw image, then I'm not sure how to "undo" the processing of the DSLR, or if you can!
You don't have to use OpenCV, necessarily. If you have access to a Matlab license, you should check it out (easier to use IMO). Matlab has a very powerful set of image processing tools.
I'm trying to do something like this. I need to extract the relative light intensity at each point from the image, and I would like to know how to do it.
The first thing that comes to my mind is to convert the image into black-and-white. I've found three different algorithms here. I used my own image as a test to try all three algorithms and the built-in function in the Python Image library image.convert('1'). The first two algorithms give some strange results for the darkened parts (like my hair, eyebrows, etc.); the third algorithm 'luminosity' gives a result very similar to what I get using some image-processing software. While the Python built-in one just gives something ridiculous. I'm not sure which one is the best representation of light intensity, and also I'm not sure if the camera will already do some self-adjustments for different images when the images all have different light orientations.
FWIW, there are 2 versions of PIL. The original one is rather outdated, but there's a new fork called Pillow. Hopefully, you're using Pillow, but to use it effectively you need to be familiar with the Pillow docs.
image.convert('1') is not what you want here: it converts an image to 1 bit black & white, i.e., there are no greys, only pure black and pure white. The correct image mode to use is 'L' (luminance) which gives you an 8 bit greyscale image.
The formula that PIL/Pillow uses to perform this conversion is
L = R * 299/1000 + G * 587/1000 + B * 114/1000
Those coefficients are quite common: eg, they're used by ppmtopgm; IIRC, they've been used since the days of NTSC analog TV. However, they may not be appropriate to other colour spaces (mostly due to issues related to gamma correction). See the Wikipedia article on the YUV colour space & linked articles for a few other coefficient sets.
Of course, it's easy enough to do the conversion with other coefficients, by operating on the pixel tuples returned by getdata, but that will be slower than using the built-in conversion.
Hello all,
I am working on a program which determines the average colony size of yeast from a photograph, and it is working fine with the .bmp images I tested it on. The program uses pygame, and might use PIL later.
However, the camera/software combo we use in my lab will only save 16-bit grayscale tiff's, and pygame does not seem to be able to recognize 16-bit tiff's, only 8-bit. I have been reading up for the last few hours on easy ways around this, but even the Python Imaging Library does not seem to be able to work with 16-bit .tiff's, I've tried and I get "IOError: cannot identify image file".
import Image
img = Image.open("01 WT mm.tif")
My ultimate goal is to have this program be user-friendly and easy to install, so I'm trying to avoid adding additional modules or requiring people to install ImageMagick or something.
Does anyone know a simple workaround to this problem using freeware or pure python? I don't know too much about images: bit-depth manipulation is out of my scope. But I am fairly sure that I don't need all 16 bits, and that probably only around 8 actually have real data anyway. In fact, I once used ImageMagick to try to convert them, and this resulted in an all-white image: I've since read that I should use the command "-auto-levels" because the data does not actually encompass the 16-bit range.
I greatly appreciate your help, and apologize for my lack of knowledge.
P.S.: Does anyone have any tips on how to make my Python program easy for non-programmers to install? Is there a way, for example, to somehow bundle it with Python and pygame so it's only one install? Can this be done for both Windows and Mac? Thank you.
EDIT: I tried to open it in GIMP, and got 3 errors:
1) Incorrect count for field "DateTime" (27, expecting 20); tag trimmed
2) Sorry, can not handle images with 12-bit samples
3) Unsupported layout, no RGBA loader
What does this mean and how do I fit it?
py2exe is the way to go for packaging up your application if you are on a windows system.
Regarding the 16bit tiff issue:
This example http://ubuntuforums.org/showthread.php?t=1483265 shows how to convert for display using PIL.
Now for the unasked portion question: When doing image analysis, you want to maintain the highest dynamic range possible for as long as possible in your image manipulations - you lose less information that way. As you may or may not be aware, PIL provides you with many filters/transforms that would allow you enhance the contrast of an image, even out light levels, or perform edge detection. A future direction you might want to consider is displaying the original image (scaled to 8 bit of course) along side a scaled image that has been processed for edge detection.
Check out http://code.google.com/p/pyimp/wiki/screenshots for some more examples and sample code.
I would look at pylibtiff, which has a pure python tiff reader.
For bundling, your best bet is probably py2exe and py2app.
This is actually a 2 part question:
1) 16 bit image data mangling for Python - I usually use GDAL + Numpy. This might be a bit too much for your requirements, you can use PIL + Numpy instead.
2) Release engineering Python apps can get messy. Depending on how complex your app is you can get away with py2deb, py2app and py2exe. Learning distutils will help too.
Does anyone know a way get the pixel data from a PythonMagick.Image instance without having to write it to disk first?
For instance, I can read in an image using:
import PythonMagick
im = PythonMagick.Image('image.jp2')
I would now like to be able to get the uncompressed image data so that I can use it in something else like NumPy or matplotlib, but I can't seem to find any way to do this. I would just use matplotlib or PIL directly but the image format I'm reading in is JPEG 2000 which is only supported by PythonMagick as far as I know.
Any suggestions?
Disclaimer: I don't have PythonMagick built where I am right now and am no expert, so (1) any or all of the following may be wrong, (2) it will certainly be less specific than you'd like, and (3) if someone else knows better I hope they won't be put off by seeing an answer already here. Anyway:
From a quick look at the code, it looks as if you can read pixel values one by one using the pixelColor method on the Image class. This returns a PythonMagick.Color value, from which you can extract R,G,B components. The underlying C++ library supports reading out lots of pixels at a time using Image::writePixels, which is also present in PythonMagick.Image; but I think the proper use of that method depends on other things that aren't implemented in PythonMagick. That's a pity, because I bet it would have been much much more efficient than reading one pixel at a time.
Alternatively and probably better, it looks as if you can write the contents of the image to a PythonMagick.Blob object in memory, which basically does the same as writing to a file only without the file :-). You can choose what format it should write in, just as you do when writing to a file. There seems to be something called get_blob_data for extracting the contents of a Blob. Something like this:
im = PythonMagick.Image('image.jp2')
blob = PythonMagick.Blob()
im.write(blob, "png")
data = PythonMagick.get_blob_data(blob)
The resulting data is, I think, a Python string whose bytes are the binary representation of the image. (I'm assuming you're using Python 2.x, where the string type is 8-bit. I don't know whether PythonMagick works with 3.x.) I think there are some formats that are basically raw pixel data; try "RGB". You can then extract the contents via lots of struct.unpack or whatever.
I am having an issue with an embedded 64bit Python instance not liking PIL. Before i start exhausting more methods to get a compiled image editor to read the pixels for me (such as ImageMagick) i am hoping perhaps anyone here can think of a purely Python solution that will be comparable in speeds to the compiled counterparts.
Now i am aware that the compiled friends will always be much faster, but i am hoping that because i "just" want to read the alpha of a group of pixels, that perhaps a fast enough pure Python solution can be conjured up. Anyone have any bright ideas?
Though, i have tried PyPNG and that is far too slow, so i'm not expecting any magic solutions. None the less, i had to ask.
Thanks to any replies!
And just for reference, the images i'll be reading will be on average around 512*512 to 2048*2048, and i'll be reading anywhere from one to all of the pixels alpha (multiplied by a few million times, but the values can be stored so reading twice isn't done).
Getting data out of a PNG requires unpacking data and decompressing it. These are likely going to be too slow in Python for your application. One possibility is to start with PyPNG and get rid of anything in it that you don't need. For example, it is probably storing all of the data it reads from the PNG, and some of the slow speed you see may be due to the memory allocations.
When you say PyPNG is too slow, how slow is it? To put it another way, how fast would be fast enough? PyPNG doesn't do anything stupid to make itself slow, but it is written in Python.
Make sure you're using read() to read the image row by row, and make sure you're using row[3::4] to extract the alpha channel. Extracting the alpha channel by using slice notation is no slower than reading the whole image.
I've added some notes to the PyPNG documentation about its speed.