StockBreak
StockBreak

Reputation: 2895

Mask PNG image with black and white mask

I have the following image (please note the transparent background):

enter image description here

I also have a black/white mask of the same size:

enter image description here

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:

enter image description here

Mask:

enter image description here

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):

enter image description here

Upvotes: 2

Views: 2365

Answers (4)

StockBreak
StockBreak

Reputation: 2895

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;
    }
}

Upvotes: 0

fmw42
fmw42

Reputation: 53109

It should work fine in either ImageMagick 6 or ImageMagick 7 using copy_opacity not copy_alpha. This works fine for me:

Input:

enter image description here

Mask:

enter image description here

convert dress.png \( mask.png -negate \) -alpha off -compose copy_opacity -composite result.png


enter image description here

The above command using convert is for ImageMagick 6. If using ImageMagick 7, change convert to magick. Both work for me.

Upvotes: 0

GeeMack
GeeMack

Reputation: 5395

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.

Upvotes: 0

Mark Setchell
Mark Setchell

Reputation: 207540

I think you want this:

magick dress.png \( mask.png -alpha off -negate \) -compose copyalpha -composite result.png

enter image description here

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

Upvotes: 0

Related Questions