# A bug and inconsistency in current image arithmetic operations?

Let us start from a single-pixel RGBA image:

i = Image[{{{0., .4, .7, .8}}}, Real, ColorSpace -> "RGB"];


Multiplying by .5 affects every channel including the alpha channel:

ImageData[ImageMultiply[i, .5]]

{{{0., 0.2, 0.35, 0.4}}}


Multiplying by a single-pixel Real image with channel value .5:

ImageData[ImageMultiply[i, Image[{{.5}}, Real]]]

{{{0., 0.2, 0.35, 0.8}}}


... doesn't affect the alpha channel! But why? Isn't this behavior inconsistent with the previous result?

But let us check the addition:

ImageData[ImageAdd[i, .5]]

{{{0.5, 0.9, 1.2, 1.3}}}

{{{0.5, 0.9, 1.2, 1.8}}}


Heh... What??? .8 + .5 == 1.8? This is both inconsistent with the above and obviously has a bug. I've checked this with versions 10.0.1 and 10.1.0 and found that the former returns 1.3 for the alpha channel while the latter returns 1.8.

I'm at loss where is the intended behavior. Should arithmetic operations with images affect alpha channel? And should arithmetic operations between an image and a number affect alpha channel?

• Could it be that both of these are due to the unanticipated use of multiplying and adding images with different colour spaces? That, along with the fact that alpha channels are often treated differently from the others might explain why it's the alpha channel that falls apart. (And it gets weirder -- adding Image[{{.0}}, "Real"] gives {{{0., 0.4, 0.7, 1.8}}}, So apparently, pretty much everything equals 1.8). – aardvark2012 Sep 22 '17 at 11:55
• I guess the conversion of Image[{{x}}] to the RGBA color space gives Image[{{{x, x, x, 1}}}]. That seems a reasonable approach in most contexts, and explains the results. – Simon Woods Sep 22 '17 at 19:02
• @SimonWoods You are exactly right! Trace shows that at first is called ColorConvert[Image[{{x}}], "RGB"] and then ImageInsertTransparency[%, 1]. The same is true for multiplication. – Alexey Popkov Sep 22 '17 at 19:19

The comment by Simon Woods explains both the issues:

I guess the conversion of Image[{{x}}] to the RGBA color space gives Image[{{{x, x, x, 1}}}]. That seems a reasonable approach in most contexts, and explains the results.

Checking with Trace (Mathematica 11.2.0):

Trace[ImageAdd[i, Image[{{.5}}, Real]],
ImageColorSpace | ColorConvert | ImageInsertTransparency] //. {{c__}} :> {c}


The output for ImageMultiply is exactly the same.

What the output means? At first ColorSpaces for both images are determined and then the second one (for which ColorSpace isn't specified) is converted into the color space of the first using ColorConvert:

ColorConvert[Image[{{.5}}, Real], ImageColorSpace[i]]

Image[RawArray["Real64", {{{0.5, 0.5, 0.5}}}], "Real", ColorSpace -> "RGB", Interleaving -> True]


Then using undocumented function ImageInsertTransparency the alpha channel with value 1 is inserted into the output image:

ImageInsertTransparency[%, 1]

Image[RawArray["Real64", {{{0.5, 0.5, 0.5, 1.}}}], "Real", ColorSpace -> "RGB", Interleaving -> True]


As a result a non-transparent RGBA image is obtained from original grayscale one-channel image. With this image both multiplication and addition is performed channel-wise using correspondingly ImageCompositionOperationsDumpimageMultiply and ImageCompositionOperationsDumpimageAdd.

It is interesting that image division is performed by ImageCompositionOperationsDumpimageDivide which has default option "IndeterminateValue"->1. This option is documented on the Docs page for Image under Scope ► Arithmetic & Statistical Operations.

So the bottom line is that arithmetic operations involving images always involve alpha channel, but one should keep in mind that for non-transparent images alpha channel is always assumed to be equal to 1 (starting from Mathematica 10.1.0).