Honouring the alpha attribute when creating composite images. #1955

Merged
merged 4 commits into from May 13, 2013

Conversation

Projects
None yet
3 participants
Contributor

Westacular commented Apr 27, 2013

I noticed some problems with the drawing of Images onto axes. Specifically, when option_image_nocomposite() is False and a single composite image is created (which seems to be the default for most backends), the alpha attribute of the Image objects was being ignored in the compositing process.

I've fixed that by multiplying the alpha component of each pixel with the attribute of the image, if set, during the process of compositing/blending the images together.

I've set up a test for this, as well, but getting the correct results from it depends on the changes from #1868.

In the process of testing this, I discovered that for output formats other than PNG, the Cairo backend was entirely failing to render images. I fixed that issue, however, a problem still remains: the Cairo image blending algorithms assume that pixel values are premultiplied by their alpha components, which is not currently being done in the process of converting image buffers for use by Cairo. For non-opaque images where rgb values exceed the alpha value, the result can be pretty weird and psychedelic. I can take a crack at fixing this, but it's a more involved change, and given that previously images weren't working at all for Cairo, it's perhaps better saved for a separate pull request.

Owner

mdboom commented Apr 29, 2013

👍 I agree we can save the Cairo fix for later. It looks as it the test images were perhaps not committed.

Contributor

Westacular commented May 4, 2013

I've rebased/squashed this (with the formerly forgotten test images) and the Travis build is passing now.

Owner

mdboom commented May 6, 2013

👍

@pelson pelson and 2 others commented on an outdated diff May 7, 2013

src/_image.cpp
@@ -823,6 +825,16 @@
Image* thisim = static_cast<Image*>(tup[0].ptr());
ox = (long)Py::Int(tup[1]);
oy = (long)Py::Int(tup[2]);
+ if (tup[3].ptr() == Py_None)
@pelson

pelson May 7, 2013

Member

I'm not sure about this - does it not set an IndexError? (http://docs.python.org/2/c-api/tuple.html#PyTuple_GetItem)
I wonder if we'd be better checking the tuple's size?

@mdboom

mdboom May 7, 2013

Owner

Yeah, I think I agree. To maintain backward compatibility, maybe do:

if (tup.size() <= 2 || tup[3].ptr() == Py_None)
@Westacular

Westacular May 8, 2013

Contributor

OK. Everything that calls this in the codebase (all … 2 instances) was updated with the added parameter, but I'd forgotten the possibility that user code might call this.

@pelson pelson and 1 other commented on an outdated diff May 7, 2013

lib/matplotlib/tests/test_image.py
@@ -235,6 +235,26 @@ def test_image_composite_background():
ax.set_axis_bgcolor((1, 0, 0, 0.5))
ax.set_xlim([0, 12])
+@image_comparison(baseline_images=['image_composite_alpha'], remove_text=True)
+def test_image_composite_alpha():
+ """
+ Tests that the alpha value is recognized and correctly applied in the
+ process of compositing images together.
+ """
+ fig = plt.figure()
+ ax = fig.add_subplot(111)
+ arr = np.arange(12).reshape(4, 3)
+ ax.imshow(arr, extent=[0, 2, 15, 0], alpha=0.25)
+ ax.imshow(arr, extent=[4, 6, 15, 0], alpha=0.5)
@pelson

pelson May 7, 2013

Member

What would happen if this image was RGBA? Would the alpha value still have any effect?

@Westacular

Westacular May 8, 2013

Contributor

The image's alpha channel would be multiplied by the alpha value. So, an image with alphas ranging from 0.2 to 0.8 combined with alpha=0.5 would effectively be treated like an image with alphas in the 0.1 to 0.4 range. This seems reasonable, and it's already the way the backends that don't require this compositing behave.

But now that you point it out, this test case should probably involve that. I'll update it.

pelson merged commit 3e9f4a6 into matplotlib:master May 13, 2013

1 check failed

default The Travis CI build could not complete due to an error
Details
Member

pelson commented May 13, 2013

Another fantastic piece of work @Westacular. Cheers!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment