merge/average multiple layers weighted by alpha

Questions and postings pertaining to the usage of ImageMagick regardless of the interface. This includes the command-line utilities, as well as the C and C++ APIs. Usage questions are like "How do I use ImageMagick to create drop shadows?".
Post Reply
User avatar
RoadRacer
Posts: 8
Joined: 2017-05-04T00:48:33-07:00
Authentication code: 1151

merge/average multiple layers weighted by alpha

Post by RoadRacer »

Hello everybody, hopefully I did not overlook something when browsing the forum.
I aim to merge multiple layers weighted by alpha value of each pixel.

What doe’s I mean?

Let’s say I have 3 layers (same size) with semi transparency (alpha gradient), then the opacity should be the factor for the color values.

Example 1:
one pixel has the following RBG and alpha values:
Layer 1: R 158, G 24, B 210, alpha 0.4
Layer 2: R 240, G 0, B 128, alpha 0.1
Layer 3: R 17, G 194, B 96, alpha 0.3

Calculation for red-channel:
158 * 0.4 = 63.2
240 * 0.1 = 24
17 * 0.3 = 5.1
Sum is 92.3, this must be divided by the sum of the alpha values (0.8 ) = 115.375
Same way for green and blue channel, then the output should be: R 115, G 85, B 157, alpha 0.8

Example 2:
another pixel has the following RBG and alpha values:
Layer 1: R 18, G 241, B 185, alpha 0.7
Layer 2: R 192, G 13, B 21, alpha 1.0
Layer 3: R 92, G 120, B 210, alpha 0.4

Calculation for red-channel:
18 * 0.7 = 12.6
192 * 1.0 = 192
92 * 0.4 = 36.8
Sum is 241.4, divided by the sum of the alpha values (2.1) = 114.95…
(Here the sum of alpha values is greater ten 1, logically the result is set to 1.)
Output should be: R 115, G 109, B 112, alpha 1.0

Currently I do read all layers with pixel enumeration and do all that calculation for every pixel of all layers (using PowerShell), write the results into a TXT-File and finally convert this into PNG.
This works very accurate, the result looks how I expect it, but this way is extremely CPU intensive and not applicable for some hundreds or thousands of high resolution layers.

I already tried several -compose, - average, -mean commands, but the result is never what I’m looking for.

Hopefully someone understands what I mean and may have an idea for a more efficient way than calculating every single pixel outside ImageMagick.

Thanks a lot for suggestions!

(Windows 10, ImageMagick 7.0.3 (stand alone))
Windows 10 Pro (64 bit)
ImageMagick 7.0.3 Q16 (64 bit, standalone)
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: merge/average multiple layers weighted by alpha

Post by snibgo »

RoadRacer wrote:I already tried several -compose, - average, -mean commands, but the result is never what I’m looking for.
The "Plus" compose method almost does what you want. Windows syntax:

Code: Select all

%IM%convert ^
  xc:rgba(158,24,210,0.4) ^
  xc:rgba(240,0,128,0.1) ^
  xc:rgba(17,194,96,0.3) ^
  -background rgba(0,0,0,0) ^
  -compose Plus -layers Merge ^
  txt:
This pre-multiplies the channel values by each alpha before adding them, and divides by the sum of the alphas, as required.

However, the sum of the alphas is clamped at 1.0 (even when HDRI and "-define compose:clamp=off" is used). Can you arrange your input data such that the sum of alphas doesn't exceed 1.0?

If you can't do that, then the result from "Plus" can be adjusted by a certain factor when the sum of the alphas exceeds 1.0, but it is a bit messy.
snibgo's IM pages: im.snibgo.com
User avatar
RoadRacer
Posts: 8
Joined: 2017-05-04T00:48:33-07:00
Authentication code: 1151

Re: merge/average multiple layers weighted by alpha

Post by RoadRacer »

The combination of "-compose plus" and "-layers merge" is interesting and looks nice with a few layers, as long as the sum of the alphas is not larger than 1.0.
But the more the sum of alphas exceeds 1.0 (many layers), the brighter the result becomes.

Sorry, but I couldn't arrange that the sum of alphas doesn't exceed 1.0.

Thanks so far.

But, I guess there should be a way with fx-operations, right?
Windows 10 Pro (64 bit)
ImageMagick 7.0.3 Q16 (64 bit, standalone)
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: merge/average multiple layers weighted by alpha

Post by snibgo »

Yes, it could be done with "-fx", but performance would be truly horrid.

Here's a command that does the job. Windows BAT syntax. It needs a version of IM with HDRI. For use with real images, remove the three lines starting with "xc:rgba" and insert your filenames. Don't change anything else. (But do test it!)

Code: Select all

convert ^
  -define compose:clamp=off ^
  xc:rgba(18,241,185,0.7) ^
  xc:rgba(192,13,21,1.0) ^
  xc:rgba(92,120,210,0.4) ^
  ( -clone 0--1 ^
    -background rgba(0,0,0,0) ^
    -compose Plus -layers Merge ^
    +write mpr:ORDPLUS ^
    ( +clone ^
      -alpha Extract ^
      -write mpr:APLUS +delete ^
    ) ^
  ) ^
  ( -clone 0--2 ^
    -alpha extract ^
    -background rgba(0,0,0,0) ^
    -compose Plus -layers Merge ^
    mpr:APLUS ^
    -compose DivideDst -composite ^
    +write mpr:NEWPLUS ^
  ) ^
  -delete 0--1 ^
  mpr:ORDPLUS ^
  mpr:NEWPLUS ^
  -channel RGB ^
  -compose Multiply -composite ^
  +channel ^
  txt:
How does it work? It does a compose plus as before, saving it as ORDPLUS. The alpha value is as required. But when the sum of the alpha exceeds 1.0, the divisor is capped at 1.0, so the colour values are too large.

So we extract the calculated alpha into APLUS. At most this is 1.0. Then we re-calculate it, by extracting the original alphas and adding them (eg making 2.1), and divide this into APLUS (eg making 1.0/2.1 = 0.476) saving this as NEWPLUS.

Then we remove all the images, multiply the ORDPLUS colour channels by NEWPLUS, and that's the required result.
snibgo's IM pages: im.snibgo.com
User avatar
RoadRacer
Posts: 8
Joined: 2017-05-04T00:48:33-07:00
Authentication code: 1151

Re: merge/average multiple layers weighted by alpha

Post by RoadRacer »

Hey Snigbo

That works awesome!
Exactly, what I was looking for.

Thanks a lot! :-)
Windows 10 Pro (64 bit)
ImageMagick 7.0.3 Q16 (64 bit, standalone)
Post Reply