Imagick: compose with mask - php

I try to recreate a script that uses the ImageMagick command "convert" to compose an image. But I want to do the same in PHP using Imagick (version 6.6.2-10).
The command is as follows:
convert A1.mpc A3.mpc A4.mpc -channel rgba -alpha on -virtual-pixel background -background none -define compose:args=312x26.6776 -compose displace -composite out.mpc
I found out that the parameters stand for the following:
convert {background} {overlay} [{mask}] [-compose {method}] -composite {result}
The PHP Imagick gives me a compose method, but without a mask parameter: http://www.php.net/manual/en/imagick.compositeimage.php
I found another question and tries this (but does not result in the same image):
// load images
$a1 = new Imagick('a1.png');
$a3 = new Imagick('a3.png');
$a4 = new Imagick('a4.png');
// mask the overlay
$a1->compositeImage($a4, Imagick::COMPOSITE_DSTIN, 0, 0, Imagick::CHANNEL_ALPHA);
// compose overlay to background
$a1->setImageVirtualPixelMethod(Imagick::VIRTUALPIXELMETHOD_BACKGROUND);
$a1->setImageBackgroundColor(new ImagickPixel('none'));
$a1->setOption('compose:args', '312x26.6776');
$a1->compositeImage($a3, Imagick::COMPOSITE_DISPLACE, 0, 0);
So my question is: is this the right way to compose an image using a mask? Or what's wrong here?
To help visualizing what I want to do, here are some input images:
input image a1 (background):
input image a3 (overlay):
input image a4 (mask):
What I want the result to be:
What my php code creates:
Thanks in advance!
Michael

try using compositeImage method and Imagick::COMPOSITE_COPYOPACITY

Try this code:
// x-displacement
$a3->setImageArtifact('compose:args', "312x0");
$a1->compositeImage($a3, Imagick::COMPOSITE_DISPLACE, 0, 0);
// y-displacement
$a4->setImageArtifact('compose:args', "0x26.6776");
$a1->compositeImage($a4, Imagick::COMPOSITE_DISPLACE, 0, 0);

After struggling with this I finally found a way how to do it properly with PHP-Imagick.
// merge x-displacement and y-displacement into one displacement-map
$displaceMask = new Imagick();
$displaceMask->addImage($a3);
$displaceMask->addImage($a4);
$displaceMask->addImage($a4);
$displaceMask->flattenImages();
$displaceMask = $displaceMask->combineImages(Imagick::CHANNEL_ALL);
$displaceMask->setImageArtifact('compose:args', '312x26.6776');
$a1->compositeImage($displaceMask, Imagick::COMPOSITE_DISPLACE, 0, 0);
Resources that I used:
https://github.com/mkoppanen/imagick/issues/49
https://www.imagemagick.org/discourse-server/viewtopic.php?f=3&t=26323
Merging RGB channels back into a single image with ImageMagick (php)
https://imagemagick.org/script/command-line-options.php#combine

I do not know if this will help, but I processed your images in ImageMagick 6.9.10.62 and 6.9.10.5 Q16 Mac OSX with the same result as shown below.
So if there is an issue, it is likely with Imagick.
What was your exact version of 6.9.10.x?
convert img.png \
\( dx.png dy.png dy.png -combine \) \
-define compose:args=312x26.6776 -compose displace -composite \
result.png
I notice that if the same image dx is combined for dy, then I get a result similar to your bad result. That might mean that either the addImage or the flattenImage or the combineImage is not working correctly in your new Imagick.
convert img.png \
\( dx.png dx.png dy.png -combine \) \
-define compose:args=312x26.6776 -compose displace -composite \
result2.png
Check your code to be sure you do not have a typo using $a3, $a3, and either $a3 or $a4 for your addImage.
For a test, try PHP
exec("convert img.png \( dx.png dy.png dy.png -combine \) -define compose:args=312x26.6776 -compose displace -composite result.png")

Related

Mask PNG image with black and white mask

I have the following image (please note the transparent background):
I also have a black/white mask of the same size:
I would like to "crop" the dress and get just the portion of the first image contained in the black circle. I tried many different methods but they didn't work or are too slow:
1) ImageMagick (command line) <== which command can I use to achieve this? I tried multiply and copyopacity but they didn't work
2) WideImage is working: $maskedImage = $source->applyMask($mask); but it takes more than 12 seconds.
I am interested in a ImageMagick solution if possible.
EDIT
The provided solutions work fine if the mask is smaller than the original image and if the original image is simple. With these source image and mask the result is "smeared":
Source:
Mask:
Command:
convert source.png \( mask.png -negate \) -alpha off -compose copy_opacity -composite result.png
Result (I added a grey background instead of the transparent one in order to show the wrong white):
I think you want this:
magick dress.png \( mask.png -alpha off -negate \) -compose copyalpha -composite result.png
Or, if you dislike parentheses, load the mask and sort out your alpha channel first, then load the dress, then +swap the order before compositing:
magick mask.png -alpha off -negate dress.png +swap -compose copyalpha -composite result.png
Your version of ImageMagick appears to be too old to include the "copyalpha" compose operator. Here's another way to get your result...
convert dress.png \( circle.png -negate \) \
\( -clone 0 -transparent red +transparent red \) -insert 0 -composite result.png
That reads in your main image, then reads in your mask image and negates it, then creates a transparent layer and moves it to the first position in the list with "-insert". ImageMagick's default handling of "-composite" with three input images is to use the third image, now the one with the black circle, as an alpha mask. You still have to "-negate" that mask, or make a new mask with the black and white inverted.
The method used there to create the transparent canvas is to read in one of the other images inside parentheses, change everything red to transparent, then change everything not red to transparent. That results in an entirely transparent canvas to use as the first image, the destination image, in the composite list.
It should work fine in either ImageMagick 6 or ImageMagick 7 using copy_opacity not copy_alpha. This works fine for me:
Input:
Mask:
convert dress.png \( mask.png -negate \) -alpha off -compose copy_opacity -composite result.png
The above command using convert is for ImageMagick 6. If using ImageMagick 7, change convert to magick. Both work for me.
At the end of the day I kept using WideImage which is quite slow but works well. This is the class I use to mask images:
<?php
namespace AppBundle\Service\Import;
use WideImage\WideImage;
class ImageMasker
{
/**
* #var string
*/
private $tempDirectory;
public function __construct(string $tempDirectory)
{
$this->tempDirectory = $tempDirectory;
}
/**
* #param string $sourcePath
* #param string $maskPath
*/
public function mask($sourcePath, $maskPath)
{
$source = WideImage::load($sourcePath);
$mask = WideImage::load($maskPath);
$tempFilename = uniqid().'.png';
$tempPath = rtrim($this->tempDirectory, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.$tempFilename;
// applies the mask and saves the file
$maskedImage = $source->applyMask($mask);
$maskedImage->saveToFile($tempPath);
return $tempPath;
}
}

Reduce image colors based on colorlookup table excluding transparent

I'm trying to reduce the number of colors in the image below using -remap in imagemagick.
olympic-logo.png
colortable.png which consists of this two color A12E64, FF0000
Using the following code:
convert olympic-logo.png +dither -remap colortable.png olympic-logo-remap.png
Output:
olympic-logo-remap.png
Expected Output:
olympic-logo-expected.png
Is there a way to ignore transparent area so It won't get mapped to get the expected output?
Thanks and more power.
You can put a copy of the original image to one side before doing what you already did and then restore the alpha from that afterwards like this:
convert rings.png -write MPR:orig +dither -remap colortable.png MPR:orig -compose copyalpha -composite result.png
where MPR: is a "Memory Program Register", i.e. a named lump of RAM.
Your input image does not have a constant background color. It is mostly black with a large white border. You can see that if you turn alpha off:
convert olympic-logo.png -alpha off aoff.png
So you can modify Mark Setchell's command by adding -background black -alpha background to it.
convert xc:"#A12E64" xc:"#FF0000" +append colortable.png
convert olympic-logo.png -background black -alpha background -write MPR:orig +dither -remap colortable.png MPR:orig -compose copy_opacity -composite result.png
Does this now work for you? If not, try making the background all white.

How to make fade edges in image magic?

I want to create faded edges image effect using imagemagic commands. Please help me for a command to make effect as like http://postimg.org/image/h51e4twyp/
Start with Doge
curl -o doge.jpg http://i0.kym-cdn.com/photos/images/newsfeed/000/581/296/c09.jpg
Next, blur the edges.
convert doge.jpg -alpha set -virtual-pixel transparent -channel A -morphology Distance Euclidean:1,20\! +channel doge.png
You will need to output it as a .png
Imagemagick documentation
Edit: The above example is for ImageMagick v6.
For IMv7 try:
convert doge.jpg \( +clone -alpha extract -virtual-pixel black -gamma 2 +level 0,100 -white-threshold 99 -morphology Distance Euclidean:1,200! -sigmoidal-contrast 3,0% \) -compose CopyOpacity -composite doge_im7.png

Crop image on angle

I'm currently looking for a way to crop an image, but on an angle.
I don't think I can just rotate the image first as the script is supplied with specific x,y coordinates of each corner.
So if you can imaging this, image is uploaded, 1280x720.
Along with the image it's supplied with x,x coordinates for the crop zone.
However the top left and top right coordinates will not have the same y position.
Heres an examples
Before
After
Any ideas ?
You'll still need to use trigonometry methods to rotate the image, but you can mimic a crop-at-an-angle by mixing opacity copying and trimming.
First. Create an Image Mask
If all the points are giving to you, and the image size is defined, simply draw the area that needs to be extract
WIDTH=819
HEIGHT=616
TOP_LEFT=669,117
TOP_RIGHT=784,155
BOTTOM_LEFT=544,495
BOTTOM_RIGHT=659,534
convert -size $WIDTHx$HEIGHT xc:black -fill white -stroke white \
-draw "polyline $TOP_LEFT $TOP_RIGHT $BOTTOM_RIGHT $BOTTOM_LEFT" \
mask.png
Masking and Background Removal
This method of masking will turn off the alpha-channel and set the background to transparent. When we compose the two images, the resulting image will only display what's within the area we defined in the mask. (note: you may need to adjust the -background to white, or transparent.)
convert source.jpg mask.png -alpha Off -compose CopyOpacity \
-composite -background transparent copyOpacity.png
Calculate Degree to Rotate
If you have two points on a square angle, you should be able to follow the atan method. Most language will have an atan2 function. Other trigonometry questions "Rotating a rectangle" & "How to calculate the angle between two points relative to the horizontal axis?"
DELTA_Y=$(($HEIGHT-155-534))
DELTA_X=$((784-659))
DEGREE=`awk "BEGIN { pi=4.0*atan2(1.0,1.0)+90; print atan2($DELTA_Y,$DELTA_X)*180/pi; }"`
convert copyOpacity.png -rotate $DEGREE -trim final.png
Luckily, you can do everything in one step.
#!/bin/bash
WIDTH=819
HEIGHT=616
TOP_LEFT=669,117
TOP_RIGHT=784,155
BOTTOM_LEFT=544,495
BOTTOM_RIGHT=659,534
DELTA_Y=$(($HEIGHT-155-534))
DELTA_X=$((784-659))
DEGREE=`awk "BEGIN { pi=4.0*atan2(1.0,1.0)+90; print atan2($DELTA_Y,$DELTA_X)*180/pi; }"`
convert source.jpg \( -size $WIDTHx$HEIGHT xc:black -fill white -stroke white \
-draw "polyline $TOP_LEFT $TOP_RIGHT $BOTTOM_RIGHT $BOTTOM_LEFT" \) \
-alpha Off -compose CopyOpacity -composite \
-background transparent -rotate $DEGREE -trim \
final.png

Removing red eye from an Image on the client side using Jquery

I have the following html code rendered on my client's browser:
<div id="Div">
<img src="myImage.jpg" id="myImage"/>
</div>
This particular image is uploaded by the user and then displayed here.
I need to allow my user to remove any red-eye from this image. I would like to do it without any postback ( I'm using CodeIgniter at the back ). Are there any available libraries for this in JQuery (or plain Javascript) ? If not what could be a good approach ?
There is a lot of things that go on in red eye removal
A. Eye Detection
B. Red Eye Region Mapping
C. Fill Color
D. Fuzz
E. Opaque
My advice
If not a JOB for Jquery and even PHP would not remove red eye effectively
Likely Solution
Get a Jquery area selection script where users can select their red eyes them self ( With this you would be able to get the region (X1 , Y1 , X2 , Y2 , Height , Width ) example http://odyniec.net/projects/imgareaselect/
Have a simple Color Picker where they can select replacement color ??? Default can be black
Send request to imagemagick using exec in PHP for the red eye removal
You can not output your image ...
EDIT 1
I was able to help you get a ready command line tool for this JOB
http://www.fmwconcepts.com/imagemagick/index.php
http://www.fmwconcepts.com/imagemagick/redeye/index.php
Basic Concept
A. Create a desaturate copy of the input image
B. Perform a fuzzy floodfill to create a mask image
C. Composite the original with the desaturated image using the mask image
D. Apply a morphologic close operation to fill in the specular hole in the mask
and then create a difference operation to create a new mask of just the hole
E. Apply the new mask to composite the previous result with a full lightness,
zero saturation version of the original image
Sample Process
convert -quiet -regard-warnings "$infile" +repage "$tmpA1"
convert $tmpA1 -modulate $light,$sat,100 $tmpA2
proc=""
for ((i=0; i<np; i++)); do
proc="$proc matte ${pairArray[i]} floodfill"
done
convert $tmpA5 -fuzz $fuzz% -fill none -draw "$proc" \
-fill "rgba(255,255,255,1)" +opaque "rgba(0,0,0,0)" \
-fill "rgba(0,0,0,1)" -opaque "rgba(0,0,0,0)" \
-alpha off -negate $tmpA3
if [ "$dilate" = 0 ]; then
dilation=""
else
dilation="-morphology dilate disk:$dilate"
fi
convert $tmpA1 $tmpA2 $tmpA3 -compose over -composite $tmpA2
convert $tmpA3 \( +clone -morphology close disk:$rad $dilation \) \
-compose difference -composite -auto-level \
-negate -threshold 0 -negate $tmpA4
convert $tmpA2 \( $tmpA1 -modulate 100,0,100 \) $tmpA4 \
-compose over -composite $outfile
I hope this helps
Thanks
:)

Categories