Hi, Currently, imread doesn't properly handle palette images since PIL palette images can't be converted directly to numpy arrays. Well, you can convert it, but the output is garbage since the array values correspond to the image palette, which you don't have access. Flattening the image seems to be an OK work around, but if the image had a color palette, this information is lost. Also, this work around requires you to know that an image is in palette mode before calling imread. Below is a short patch that checks if an image is in palette mode; if it is, grayscale images are converted to luminance mode and color images are converted to RGB. I'm not sure if these conversions are appropriate, but at least it's an improvement. I hope this is helpful to somebody. Cheers, -Tony P.S. `palette_is_grayscale` is a convoluted function to check whether the palette is grayscale. PIL may provide a simpler check; if so, I couldn't find it. P.P.S. The following link has examples of palette images if you want to test: http://homepages.inf.ed.ac.uk/rbf/HIPR2/libfce.htm (NOTE: the thumbnails are actually not palette images, but the linked images are) ~~~~~~~ diff --git a/scikits/image/io/pil_imread.py b/scikits/image/io/ pil_imread.py index 421f45c..946d00c 100644 --- a/scikits/image/io/pil_imread.py +++ b/scikits/image/io/pil_imread.py @@ -34,6 +34,34 @@ def imread(fname, flatten=False, dtype=None): " instructions.") im = Image.open(fname) + if im.mode == 'P': + if palette_is_grayscale(im): + im = im.convert('L') + else: + im = im.convert('RGB') if flatten and not im.mode in ('1', 'L', 'I', 'F', 'I;16', 'I; 16L', 'I;16B'): im = im.convert('F') return np.array(im, dtype=dtype) + + +def palette_is_grayscale(pil_image): + """Return True if PIL image is grayscale. + + Parameters + ---------- + pil_image : PIL image + PIL Image that is in Palette mode. + + Returns + ------- + is_grayscale : bool + True if all colors in image palette are gray. + """ + assert pil_image.mode == 'P' + # get palette as an array with R, G, B columns + palette = np.asarray(pil_image.getpalette()).reshape((256, 3)) + # Not all palette colors are used; unused colors have junk values. + start, stop = pil_image.getextrema() + valid_palette = palette[start:stop] + # Image is grayscale if channel differences (R - G and G - B) are all zero. + return np.allclose(np.diff(valid_palette), 0)
Hi Tony, On Wed, Oct 28, 2009 at 10:36 PM, Tony S Yu <tsyu80@gmail.com> wrote:
Hi,
Currently, imread doesn't properly handle palette images since PIL palette images can't be converted directly to numpy arrays. Well, you can convert it, but the output is garbage since the array values correspond to the image palette, which you don't have access.
Flattening the image seems to be an OK work around, but if the image had a color palette, this information is lost. Also, this work around requires you to know that an image is in palette mode before calling imread.
Below is a short patch that checks if an image is in palette mode; if it is, grayscale images are converted to luminance mode and color images are converted to RGB. I'm not sure if these conversions are appropriate, but at least it's an improvement.
I hope this is helpful to somebody. Cheers,
This looks like a useful addition to me. The images on the page you linked to can not be included I think (copyright), so could you generate two small palette images (one rgb, one grey, 10x10 pixels) for use in a test? (or ideally, write the test:)) Also, I see you are already using git, so next time could you push your changes to github as described here http://stefanv.github.com/scikits.image/contribute.html#development-process, that would make it a bit faster to test. Thanks, Ralf
Hi Ralf, Thanks for the feedback. On Oct 30, 2009, at 11:31 AM, Ralf Gommers wrote:
The images on the page you linked to can not be included I think (copyright), so could you generate two small palette images (one rgb, one grey, 10x10 pixels) for use in a test? (or ideally, write the test:))
I couldn't easily find any palette images that weren't copyrighted; it never occurred to me just create them. Thanks.
Also, I see you are already using git, so next time could you push your changes to github as described here http://stefanv.github.com/scikits.image/contribute.html#development-process , that would make it a bit faster to test.
I was afraid I'd have to learn git. ;) I added the changes in three commits to: http://github.com/tonysyu/scikits.image The first commit just adds the images, the second adds palette image handling + a test, and the third adds an additional test. I wasn't sure how to test imread. I ended up checking that imread returns a 2D array for the grayscale palette image and a 3D array for the color palette image. Another possibility is to test the values of the array, but that seems fragile. The last commit adds a test of the function `palette_is_gray`. Unfortunately, the test is a bit ugly. First, I had to add an import of PIL in the test, since palette_is_gray works specifically on PIL palette images. Second, I had to add `palette_is_grayscale` to __all__ in pil_imread so that I could use the function in my test. (Python documentation suggests that __all__ only affects ``from <> import *``, but it seemed to prevent ``from scikits.image.io import palette_is_grayscale``.) Let me know what you think of the tests. Also, should I do a pull request? Best, -Tony
Hi Tony, On Sat, Oct 31, 2009 at 5:36 PM, Tony S Yu <tsyu80@gmail.com> wrote:
Hi Ralf,
Thanks for the feedback.
On Oct 30, 2009, at 11:31 AM, Ralf Gommers wrote:
The images on the page you linked to can not be included I think (copyright), so could you generate two small palette images (one rgb, one grey, 10x10 pixels) for use in a test? (or ideally, write the test:))
I couldn't easily find any palette images that weren't copyrighted; it never occurred to me just create them. Thanks.
You're welcome. In addition to avoiding copyright issues, it is nice to have very small images. Otherwise the size of the scikit would be completely dominated by lots of large test images after a while.
Also, I see you are already using git, so next time could you push your changes to github as described here http://stefanv.github.com/scikits.image/contribute.html#development-process, that would make it a bit faster to test.
I was afraid I'd have to learn git. ;)
I trust it wasn't too painful, thanks for doing it.
I added the changes in three commits to: http://github.com/tonysyu/scikits.image The first commit just adds the images, the second adds palette image handling + a test, and the third adds an additional test.
I wasn't sure how to test imread. I ended up checking that imread returns a 2D array for the grayscale palette image and a 3D array for the color palette image. Another possibility is to test the values of the array, but that seems fragile.
This looks fine to me. Testing values would be good as well, and if you do it with assert_array_almost_equal from numpy.testing it should not be fragile.
The last commit adds a test of the function `palette_is_gray`. Unfortunately, the test is a bit ugly. First, I had to add an import of PIL in the test, since palette_is_gray works specifically on PIL palette images. Second, I had to add `palette_is_grayscale` to __all__ in pil_imread so that I could use the function in my test. (Python documentation suggests that __all__ only affects ``from <> import *``, but it seemed to prevent ``from scikits.image.io import palette_is_grayscale``.)
The PIL import is fine, but the try-except block is unnecessary since that is already done in imread.
Adding to __all__ is not necessary, you can import it from io.pil_imread. I did notice that other imread tests fail already if PIL is not available. For this we do need an @pil_skip decorator I think.
Let me know what you think of the tests. Also, should I do a pull request?
Looks good overall. I made some minor changes reflecting the comments I made above: http://github.com/rgommers/scikits.image/commit/a6ad7415d7a43185cea898d3454e... If you are happy with those, you can pull my palette branch over and send Stefan a pull request. Cheers, Ralf
On Oct 31, 2009, at 1:48 PM, Ralf Gommers wrote:
The last commit adds a test of the function `palette_is_gray`. Unfortunately, the test is a bit ugly. First, I had to add an import of PIL in the test, since palette_is_gray works specifically on PIL palette images. Second, I had to add `palette_is_grayscale` to __all__ in pil_imread so that I could use the function in my test. (Python documentation suggests that __all__ only affects ``from <> import *``, but it seemed to prevent ``from scikits.image.io import palette_is_grayscale``.)
The PIL import is fine, but the try-except block is unnecessary since that is already done in imread.
Adding to __all__ is not necessary, you can import it from io.pil_imread.
Ahh, of course.
I did notice that other imread tests fail already if PIL is not available. For this we do need an @pil_skip decorator I think.
Let me know what you think of the tests. Also, should I do a pull request?
Looks good overall. I made some minor changes reflecting the comments I made above: http://github.com/rgommers/scikits.image/commit/a6ad7415d7a43185cea898d3454e...
If you are happy with those, you can pull my palette branch over and send Stefan a pull request.
The changes look good. Thanks! Pull request sent. Thanks, -Tony
2009/10/31 Tony S Yu <tsyu80@gmail.com>:
Looks good overall. I made some minor changes reflecting the comments I made above: http://github.com/rgommers/scikits.image/commit/a6ad7415d7a43185cea898d3454e...
If you are happy with those, you can pull my palette branch over and send Stefan a pull request.
The changes look good. Thanks! Pull request sent.
Thanks, Tony! I merged your changes into the master branch. Cheers Stéfan
participants (3)
-
Ralf Gommers
-
Stéfan van der Walt
-
Tony S Yu