Page 1 of 1

Composite image onto image with transparency, ADD and BLEND not right

Posted: 2018-08-11T22:11:26-07:00
by neekfenwick
PHP 5.6 (yes, I know, it's old)
imagick module 3.4.3 (2018-07-24)
system: Fedora Linux
Linux uberneek.localdomain 4.17.11-100.fc27.x86_64 #1 SMP Mon Jul 30 15:22:33 UTC 2018 x86_64

I have a 'main' image of a kitchen with a roughly rectangular transparency layer, with some faint contents representing the reflection of a window behind the viewer. I'm trying to overlay onto this a mostly solid image to fit into the rectangular space, so that it appears to have the reflection visible in it. This overlay image has perspective distorsion to make it fit into the 3d scene, so there are transparent triangles along the top and bottom edges.

I think my problem is the COMPOSITE_* constant I'm using, currently COMPOSITE_ADD, but I've tried every one I can find (at http://php.net/manual/en/imagick.constants.php) and none seem to achieve the desired effect.

This works fine in The GIMP: https://imgur.com/a/ukDzAV6 (you can see a kind of square pattern over the image of London)

However compositing via Imagick causes colour distorion, presumably where the colour value of pixels in the overlay image are being added to the faint colour values in the transparency area in the main image: https://imgur.com/a/T7SR2nZ

I would think that COMPOSITE_BLEND would be right, but this causes the transparent areas of the overlay image to obsure the main image: https://imgur.com/a/xUnsEwv (see how the bottom-left corner of the London image is overlapping the shiny metal pot ... with COMPOSITE_ADD this effect does not happen)

My source files are:
transparent_splashback.png: https://imgur.com/a/9PRxi2p
img.png: https://imgur.com/a/z1C0PLj

A small test program that demonstrates my approach:

Code: Select all

<?php
// Demonstrates problem overlaying image onto main image so it shows through
// the transparency layer of the main image

// Load the main image
$mainImg = new Imagick();
$mainImg->readImage('transparent_splashback.png');

// Load the overlay image
$overlayImg = new Imagick();
$overlayImg->readImage('img.png');

$compositeX = 317; // top left corner in main image
$compositeY = 234;

// Overlay them
$mainImg->compositeImage($overlayImg, Imagick::COMPOSITE_ADD, $compositeX, $compositeY);

// Return the result as a data stream
$blob = $mainImg->getImageBlob();
file_put_contents('out.png', $blob);
echo "Wrote out to out.png OK.";
I've searched this board and the internet in general but I seem to be doing something quite specific and can't see a solution yet.

Thank you so much for reading! Any ideas would be welcome.

[EDIT: to fix misleading subject]

Re: Composite image onto image with transparency causes rainbow colour distortion

Posted: 2018-08-11T22:45:26-07:00
by neekfenwick
Update: I've a strong feeling I need to create a mask based on the transparency of the main image.. that would give me a mask shaped like the rectangular area but, crucially, with cutouts for the shiny pot on the stove for example. Then I need to crop my overlay image using this mask, to remove bits that would overlay elements on the main image (i.e. the shiny pot). Then COMPOSITE_BLEND would probably do the job beautifully.

So I'm reading http://www.imagemagick.org/discourse-se ... hp?t=19116 and http://www.imagemagick.org/Usage/thumbnails/#mask_paint but it's all pretty hard to get into, and the example tend to use CLI and geometric commands to generate the masks. Perhaps someone more familiar with the pipeline required and the PHP API could help out here?

Re: Composite image onto image with transparency causes rainbow colour distortion

Posted: 2018-08-11T22:52:13-07:00
by snibgo
neekfenwick wrote:This works fine in The GIMP...
Okay, so how did you do it in Gimp?

Re: Composite image onto image with transparency causes rainbow colour distortion

Posted: 2018-08-12T00:05:38-07:00
by neekfenwick
@snibgo I provided a screenshot. Just create two layers and position the smaller image to be overlaid 'underneath' the main image. However, achieving an effect in a graphics package is a different process to doing it via Imagick, e.g. in the first thread I linked to above, http://www.imagemagick.org/discourse-se ... hp?t=19116, he also says he achieved it in Photoshop but was having trouble via the imagemagick CLI.

If your point is "if you can do it in the GIMP so easily it must be easy in Imagick" then I would initially agree with you, yet my simple attempts have failed. GIMP seems to be doing a pretty straightforward "obscure the underlaying image with pixels from the image on top" yet none of the COMPOSITE_* operators I've tried have achieved the same result.

Your comment did make me think perhaps I should start with the overlay image, sized the same size as the main image, and then overlay the main image on top of it i.e. perform the operation in reverse order to what I was doing before, but again this doesn't work, with _ADD I still get the rainbow effect (because the pixel values are still being combined in undesirable way) and _BLEND causes the overlay image's pixels to corrupt bits of the main image I don't want them to (e.g. the shiny pot).

Re: Composite image onto image with transparency causes rainbow colour distortion

Posted: 2018-08-12T07:07:58-07:00
by snibgo
Gimp's "Mode Normal" corresponds to IM's "-compose Over" so if you like the Gimp result, I suggest you use "-compose Over", in the same order as Gimp, with the river scene first then the kitchen photo.

Code: Select all

magick bRdUfVc.png Ymsusb9.png -background None -compose Over -layers Merge +repage out.png
If I used "-composite" the output size would be from the river scene, so "-layers Merge" gives the size required. This also flattens against a background colour, so we set that to "None".

The output seems to be what you get from Gimp. Sorry, I don't know the IMagick commands.

Re: Composite image onto image with transparency causes rainbow colour distortion

Posted: 2018-08-12T22:05:48-07:00
by neekfenwick
Aha! COMPOSITE_OVER does indeed do the trick, if I start with the overlay image, and compose the main image over it. So I start with a different overlay image, this time one that's the same dimensions as the main image (1000x1000 pixels):

img_fullsize.png: https://imgur.com/a/5Jf1dEP

And compose over the top of it the main image (same as in my original post):
transparent_splashback.png: https://imgur.com/a/9PRxi2p

With the code:

Code: Select all

// Load the overlay image
$overlayImg = new Imagick();
$overlayImg->readImage('img-fullsize.png');

// Load the main image
$mainImg = new Imagick();
$mainImg->readImage('transparent_splashback.png');

// Overlay them
$overlayImg->compositeImage($mainImg, Imagick::COMPOSITE_OVER, 0, 0);

// Write out result
$blob = $overlayImg->getImageBlob();
file_put_contents('out.png', $blob);
echo "Wrote out to out.png OK.";
Thanks for your help! Can't believe I didn't try that combination before.

Now I need to go back to my perspective transform code and figure out how to make it retain the original image's size...