Reputation: 740
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:
I tried all the modes provided, but none of them create the same result as After Effects.
Upvotes: 3
Views: 1218
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):
Then ran:
$ vips composite2 bg.jpg white-cloud.png x.png over --premultiplied
To make:
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
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:
For reference, here are a couple of the intermediate images,
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
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
I have posted a JPG result, but my .tga result is the same.
Upvotes: -1
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?
-fx
command #1: Convert whitecloud.tga from premultiplied alpha to "normal". The max()
operator is a special case to avoid dividing by zero.+swap
command: Make bg.tga
the first image and the revised whitecloud.tga
the second.-composite
these two regular, non-premultiplied images.-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
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
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