According to the Documentation page for ImageCompose
, it uses "standard Duff-Porter compositing operators" with the default being the "over" operator.
However my experiments show that in the recent versions of Mathematica (up to version 11.2.0) alpha blending in ImageCompose
is implemented incorrectly: the developer has made the most typical and very popular mistake when implementing the Duff-Porter's "over" operator by forgetting to return from pre-multiplied color channel values to the straight color channel values (native for Mathematica's Image
), a proof follows.
Theoretical background
As a reference for correct definition of the standard "A over B" operation we can use the original paper by Thomas Porter and Tom Duff "Compositing Digital Images" (1984) where they give on page 256 the following definition for the case when pre-multiplied (!) colors are used:
$c_O = c_A + c_B (1 - \alpha_A),$
where
$\alpha_A$ is alpha channel value of image A,
$c_A$ and
$c_B$ are pre-multiplied (!) color channel values of images A and B correspondingly, and
$c_O$ is the final pre-multiplied (!!!) color channel value.
The most common mistake when implementing the above definition is to forget that
$c_O$ is pre-multiplied color which must be divided by the new alpha channel value
$\alpha_O$ in order to obtain straight color:
$\alpha_O = \alpha_A + \alpha_B (1 - \alpha_A).$
Note that Porter and Duff [1984] dont provide this last formula, they simply assume pre-multiplied colors. An elaborated and very enlightening discussion on this topic can be found in recent paper
- Glassner, Andrew (2015), "Interpreting Alpha", Journal of Computer Graphics Techniques 4 (2): 3044.
where the last formula is provided as formula (2) on page 33 (thanks to Charles Poynton for the reference!).
Mathematica's implementation
Starting from version 11.1 we can implement the correct definition for the "A over B" operation as follows:
imageCompose[b_Image, a_Image] :=
Module[{alphaA = AlphaChannel@a, alphaB = AlphaChannel@b, alphaO,
cA = RemoveAlphaChannel@a, cB = RemoveAlphaChannel@b},
alphaO = 1 - (1 - alphaA) (1 - alphaB);
SetAlphaChannel[(alphaA*cA + (1 - alphaA) alphaB*cB)/alphaO, alphaO]]
And the incorrect definition (without division by
$\alpha_O$) can be implemented as follows:
imageComposeWrong[b_Image, a_Image] :=
Module[{alphaA = AlphaChannel@a, alphaB = AlphaChannel@b, alphaO,
cA = RemoveAlphaChannel@a, cB = RemoveAlphaChannel@b},
alphaO = 1 - (1 - alphaA) (1 - alphaB);
SetAlphaChannel[alphaA*cA + (1 - alphaA) alphaB*cB, alphaO]]
It is easy to ensure that imageComposeWrong
is equivalent to the current ImageCompose
(with tiny differences due to rounding-off errors):
a = Image[{{{.1, .3, .7, .8}}}, ColorSpace -> "RGB"];
b = Image[{{{.7, .3, .1, .4}}}, ColorSpace -> "RGB"];
ImageData[ImageCompose[a, b]] == ImageData[imageComposeWrong[a, b]]
True
I hope that my report will help to improve Mathematica by fixing the above-described bug in ImageCompose
. Note also that I've checked only the "over" operator, other compositing operators supported by ImageCompose
can also be affected.
P.S. I discuss this issue in more details on Mathematica.SE. It is worth to mention that Overlay
and Graphics
currently use the correct implementation of the OVER compositing operator.
_{Reported to the support as [CASE:3967986].}