phpjqueryimagickgdlib

Remove image background is not working properly in php imagick


Hello I try to remove image background using Imagick PHP library but it is not working properly. my code is only working with white background images only. i need to work with any types of background. the final image should with transparent background with object. any solution can be appreciated.

you can refer mycode as below.

$imagick = new \Imagick(realpath('images/abc.JPG')); // $imagick = new \Imagick();

$backgroundColor = "rgb(255, 255, 255)";
$fuzzFactor = 0.1;

// Create a copy of the image, and paint all the pixels that
// are the background color to be transparent
$outlineImagick = clone $imagick;
$outlineImagick->transparentPaintImage(
    $backgroundColor, 0, $fuzzFactor * \Imagick::getQuantum(), false
);

// Copy the input image
$mask = clone $imagick;
// Deactivate the alpha channel if the image has one, as later in the process
// we want the mask alpha to be copied from the colour channel to the src
// alpha channel. If the mask image has an alpha channel, it would be copied
// from that instead of from the colour channel.
$mask->setImageAlphaChannel(\Imagick::ALPHACHANNEL_DEACTIVATE);
//Convert to gray scale to make life simpler
$mask->transformImageColorSpace(\Imagick::COLORSPACE_GRAY);

// DstOut does a "cookie-cutter" it leaves the shape remaining after the
// outlineImagick image, is cut out of the mask.
$mask->compositeImage(
    $outlineImagick,
    \Imagick::COMPOSITE_DSTOUT,
    0, 0
);

// The mask is now black where the objects are in the image and white
// where the background is.
// Negate the image, to have white where the objects are and black for
// the background
$mask->negateImage(false);

$fillPixelHoles = false;

if ($fillPixelHoles == true) {
    // If your image has pixel sized holes in it, you will want to fill them
    // in. This will however also make any acute corners in the image not be
    // transparent.

    // Fill holes - any black pixel that is surrounded by white will become
    // white
    $mask->blurimage(2, 1);
    $mask->whiteThresholdImage("rgb(10, 10, 10)");

    // Thinning - because the previous step made the outline thicker, we
    // attempt to make it thinner by an equivalent amount.
    $mask->blurimage(2, 1);
    $mask->blackThresholdImage("rgb(255, 255, 255)");
}

//Soften the edge of the mask to prevent jaggies on the outline.
$mask->blurimage(2, 2);

// We want the mask to go from full opaque to fully transparent quite quickly to
// avoid having too many semi-transparent pixels. sigmoidalContrastImage does this
// for us. Values to use were determined empirically.
$contrast = 15;
$midpoint = 0.7 * \Imagick::getQuantum();
$mask->sigmoidalContrastImage(true, $contrast, $midpoint);

// Copy the mask into the opacity channel of the original image.
// You are probably done here if you just want the background removed.
$imagick->compositeimage(
    $mask,
    \Imagick::COMPOSITE_COPYOPACITY,
    0, 0
);



// To show that the background has been removed (which is difficult to see
// against a plain white webpage) we paste the image over a checkboard
// so that the edges can be seen.

// Create the check canvas
$canvas = new \Imagick();
$canvas->newPseudoImage(
    $imagick->getImageWidth(),
    $imagick->getImageHeight(),
    "pattern:checkerboard"
);

// Copy the image with the background removed over it.
$canvas->compositeimage($imagick, \Imagick::COMPOSITE_OVER, 0, 0);

//Output the final image
$canvas->setImageFormat('png');
header("Content-Type: image/png");
echo $canvas->getImageBlob();

Solution

  • Instead of using fixed value of color, you can get color from 1st pixel:

    $image->getImagePixelColor(0, 0)