whereisalext
whereisalext

Reputation: 740

Compositing premultiplied images using ImageMagick

I have two images. One is background with no alpha. The other is a white cloud. The alpha of the cloud image is premultiplied with black. When I composite them the white cloud has black in it, so it looks grey instead of white like it should. I'm doing:

convert -gravity Center bg.tga whitecloud.tga -composite comp.tga

Is there a way to composite premultiplied images in ImageMagick, or does the image have to be non-premultiplied? Can I make a premultiplied image non-premultiplied using ImageMagick?

Update:
Ok, here are the images as TGA for download:

http://acatysmoof.com/posting/problems/imagemagick/premultiplication/bg.tga http://acatysmoof.com/posting/problems/imagemagick/premultiplication/whitecloud.tga http://acatysmoof.com/posting/problems/imagemagick/premultiplication/aftereffects.tga http://acatysmoof.com/posting/problems/imagemagick/premultiplication/imagemagick.tga

and in the same order as jpgs to view in your browser:

bg.jpg whitecloud.jpg aftereffects.jpg imagemagick.jpg

I tried all the modes provided, but none of them create the same result as After Effects.

Upvotes: 3

Views: 1218

Answers (5)

jcupitt
jcupitt

Reputation: 11200

I realise you asked for an imagemagick solution, but if other libraries are possible, libvips supports porter-duff composition with premultiplied alpha.

I made a PNG for your cloud image (this will look odd in a browser since the alpha is premultiplied):

enter image description here

Then ran:

$ vips composite2 bg.jpg white-cloud.png x.png over --premultiplied

To make:

enter image description here

Which I think matches aftereffects.

Here are the docs for the composite operator:

https://www.libvips.org/API/current/libvips-conversion.html#vips-composite

Upvotes: 1

endavid
endavid

Reputation: 1963

The regular alpha blending operation (the Duff-Porter Over operator) does this:

output.rgb = src.rgb * src.a + (1-src.a) * dst.rgb

When the alpha is premultiplied, it just means that the color of the source is already src.rgb * src.a, so you only need to add (1-src.a) * dst.rgb.

That's very quick in a shader. But in ImageMagick seems to get confusing because there doesn't seem to be a direct operator that does that.

However, you can compute it if you break it down in several steps:

# extract alpha channel from cloud
convert whitecloud.tga -auto-orient -alpha extract -colorspace gray alpha.png
# invert alpha channel
convert alpha.jpg -negate alpha-inv.png
# (1-cloud.a) * bg.rgb
composite -compose Multiply alpha-inv.png bg.tga bg-pre.png
# remove alpha channel to obtain cloud.rgb
convert whitecloud.tga -auto-orient -alpha off whitecloud-rgb.png
# cloud.rgb * cloud.a + (1-cloud.a) * bg.rgb
composite -compose plus whitecloud-rgb.png bg-pre.png output.png

Here's the output:

This is the output

For reference, here are a couple of the intermediate images,

  • the alpha channel of the cloud

The alpha channel of the cloud

  • the background multiplied with the inverse of the alpha of the cloud

Background multiplied with the inverse alpha of the cloud

The advantage of splitting it in several steps is that it's easier to debug, in case your image has the wrong alpha channel or something.

Upvotes: 1

fmw42
fmw42

Reputation: 53154

If you want to duplicate the After Effects result, then I believe what you want to do in ImageMagick is the following -- composite the background image with a white image using the cloud as a mask:

convert bg.tga \( -clone 0 -fill white -colorize 100 \) whitecloud.tga -compose over -composite cloud_blue.tga

enter image description here

I have posted a JPG result, but my .tga result is the same.

Upvotes: -1

David Pritchard
David Pritchard

Reputation: 318

Here is an Imagemagick command that does what you want:

convert -gravity Center whitecloud.tga -fx "u/max(u.a, 1/255)" bg.tga +swap -composite -fx "u*u.a" comp.tga

What's happening here?

  1. -fx command #1: Convert whitecloud.tga from premultiplied alpha to "normal". The max() operator is a special case to avoid dividing by zero.
  2. +swap command: Make bg.tga the first image and the revised whitecloud.tga the second.
  3. -composite these two regular, non-premultiplied images.
  4. -fx command #2: take the result, and return to a premultiplied alpha format.

This gives exactly the same result as After Effects.

Note that, as I wrote it, it only works for an opaque bg.tga. You'd need to do some extra work to handle a transparent background image.

Upvotes: 0

Mark Setchell
Mark Setchell

Reputation: 207670

It would be easier if you showed your images, but try adding -compose lighten before -composite in your command, like this:

convert a.tga b.tga -compose lighten -composite out.tga

Basically that will make ImageMagick choose the lighter pixel of the two images at every point.

If that doesn't work, try other blending modes

for b in $(identify -list compose); do 
   convert -label "$b" bg.tga whitecloud.tga -compose $b -composite miff:- 
done | montage - -tile 5x out.png

enter image description here

I am kind of thinking Atop, Dissolve, SrcAtop and SrcOver might be your friends but have a look full-size and see what floats your boat. That would be

convert a.tga b.tga -compose Atop -composite out.tga

Upvotes: 1

Related Questions