27

I know very little of image processing and even less of the terminology used, so please bear with me.

Basically, I want to merge two images together where one of them will act as a mask. That image looks something like this:
Example
Where the blue and yellow background are both transparent in reality.

This image is being used as a mask for regular photo's. Parts of the photo that 'stick out' of the circle need to be 'cropped' (be made invisible) while the inside remains visible.
So everything that comes in the blue area is invisible, everything in the yellow area is visible.

I honestly have no clue how to go about it so any help would be greatly appreciated!

Edit:
I use the API version of Imagick, not the commandline version

Edit:
To get a feel of what I want to achieve, here is an example.

The input images are thus:
enter image description here
This is the mask image, always the same

enter image description here
This is an example of a picture, dynamic

enter image description here
This is what the end result should look like

iND
  • 2,663
  • 1
  • 16
  • 36
Dennis Haarbrink
  • 3,738
  • 1
  • 27
  • 54

4 Answers4

71

So, finally, this should do what you need:

Original image:

https://i.stack.imgur.com/b7seR.png

Opacity mask:

enter image description here

Overlay:

https://i.stack.imgur.com/3ulkM.png

Output:

enter image description here

The code:

<?php
$base = new Imagick('U0R4F.png');
$mask = new Imagick('mask.png');
$over = new Imagick('3ulkM.png');

// Setting same size for all images
$base->resizeImage(274, 275, Imagick::FILTER_LANCZOS, 1);

// Copy opacity mask
$base->compositeImage($mask, Imagick::COMPOSITE_DSTIN, 0, 0, Imagick::CHANNEL_ALPHA);

// Add overlay
$base->compositeImage($over, Imagick::COMPOSITE_DEFAULT, 0, 0);

$base->writeImage('output.png');
header("Content-Type: image/png");

echo $base;
?>

I hope it's right now! Note: In your example it looks like you downscaled the base image, which I didn't (my goal is just to show how the masking is done).

user703016
  • 37,307
  • 8
  • 87
  • 112
  • This looks promising! I will create a mask image and test this code. – Dennis Haarbrink Jan 04 '12 at 11:17
  • Yeah I guess some scaling should occur. I'm gonna test the new code now. – Dennis Haarbrink Jan 04 '12 at 12:45
  • 1
    Great, this is almost perfect! One problem, any transparancy in the original image is converted to black. Is there a way to preserve the alpha channel? – Dennis Haarbrink Jan 04 '12 at 13:00
  • Thanks so much! This does exactly what is needed. All I need is proper scaling, but I think I can manage that by myself. You deserve the bonus! – Dennis Haarbrink Jan 05 '12 at 07:46
  • 3
    I had to make one little tweak though, add a check whether an image has an alpha channel use a different composition method: `if ($base->getImageMatte()) { $base->compositeImage($mask, Imagick::COMPOSITE_DSTIN, 0, 0, Imagick::CHANNEL_ALPHA); } else { $base->compositeImage($mask, Imagick::COMPOSITE_COPYOPACITY, 0, 0); }` – Dennis Haarbrink Jan 05 '12 at 08:30
  • Please excuse my insistance, but if you do not manually award the reputation bonus to one of these answers before the end of the bounty, then half of it will be lost. Cheers. – user703016 Jan 11 '12 at 00:38
  • I'm sorry, haven't been able to award the bounty and was under the impression that it would get awarded automatically to the selected answer. – Dennis Haarbrink Jan 11 '12 at 08:13
  • I also had to change the lines a little bit to $base->compositeImage($mask, \Imagick::COMPOSITE_DSTIN, 0, 0, \Imagick::CHANNEL_ALPHA); $base->compositeImage($over, \Imagick::COMPOSITE_DEFAULT, 0, 0, \Imagick::CHANNEL_ALPHA); BUT, I cannot get rid of the black background where my mask and overlay are both transparent. – Jason G Jun 03 '15 at 18:02
  • @buttifulbuttefly This is exactly what I want to do, but how do I do it using command line instead of PHP? And batch process it? – kaoscify Jul 14 '15 at 19:19
1

Did you try this solution here as described by : https://stackoverflow.com/a/2351173/1093649 ?

Run this in your server (with the right image names!), and let us know, thanks.

nb : credits go to jspash

Community
  • 1
  • 1
Justin T.
  • 3,643
  • 1
  • 22
  • 43
  • I had already found that one, but it doesn't really do what I want. The net effect of that answer is that the blue and yellow parts in the image stay transparent while the black border displays the 'background' image. – Dennis Haarbrink Jan 04 '12 at 10:25
  • Too bad, can you attach the original images to your post? That way, we can get a better idea to where you are starting from. – Justin T. Jan 04 '12 at 10:37
  • I have updated the question with sample input and output images. – Dennis Haarbrink Jan 04 '12 at 11:05
0

This type of masking is exampled using a number of different techniques in ImageMagick Examples, Thumbnails, Mask and Paint http://www.imagemagick.org/Usage/thumbnails/#mask_paint

Be warned however that the masking and the edges of the overlay image SHOULD NOT MATCH this is important or you may get problems with edge aliasing effects that is best avoided.

Extracting an alpha mask of the ring, can be done using morphology operators to thin it down to a centerline can be used to generate a mask for any random 'ring' shape. ImageMagick Examples, Skeletons by Thinning, and Pruning http://www.imagemagick.org/Usage/morphology/#thinning_skeleton

Anthony Thyssen Web Master for ImageMagick Examples, and Developer for ImageMagick

PS: nice photo from Elfling

anthony
  • 7,696
  • 1
  • 17
  • 11
0

http://www.imagemagick.org/Usage/compose/#dstin should do the trick, but you need to use images with alpha channels (that shouldn't be a problem).

Edit: in PHP you have to pass it (imagick::COMPOSITE_DSTIN) as a parameter in compositeimage. Other filters in Composite Operator Constants may also be useful to you.

Viruzzo
  • 3,025
  • 13
  • 13
  • This doesn't really help. Of course I've found the compose function, but I just don't know how to combine the tools available to create the result I need. – Dennis Haarbrink Jan 04 '12 at 09:52