PHP Imagick 将 JPG 转换为 PNG 并删除背景作品但并不完美

Posted

技术标签:

【中文标题】PHP Imagick 将 JPG 转换为 PNG 并删除背景作品但并不完美【英文标题】:PHP Imagick convert JPG to PNG and remove background works but not perfect 【发布时间】:2021-07-29 08:14:39 【问题描述】:

有没有办法结合这两个代码和结果来创造完美的东西?另外,我想细化PNG文件的轮廓,使其更美观。

原始文件:


代码 1: 当我需要从实心图像中移除背景(无需移除其中的区域)时,此代码非常有效

<?php

// input_file
$input_file = "100001.jpg";

// $output_file
$output_file = "100001.png";

// Load the image
$imagick = new Imagick(realpath($input_file));

// We replace white background with fuchsia to improve clipping
$imagick->floodFillPaintImage("rgb(255, 0, 255)", 2500, "rgb(255,255,255)", 0 , 0, false);

// We convert fuchsia to transparent
$imagick->paintTransparentImage("rgb(255,0,255)", 0, 10);

// We eliminate empty areas to only leave objects
$imagick->trimImage(0);

// Maximum 500 height but the width can exceed 500 if the original image exceeds 500 somewhere
$imagick->resizeImage(0, 500, Imagick::FILTER_CATROM, 1);

// We scale to a maximum of 500 width or height, take the largest measurement and lower it to 500
$imagick->scaleImage(500, 500, true);

// We export as PNG
$imagick->setImageFormat('png');

// Path to save new image
$imagick->writeImage($output_file);

// We clean cache
$imagick->clear();

// We destroy everything
$imagick->destroy();

?>

输出文件 1:(在这种情况下,软管内部没有被移除)


代码 2: 移除软管内的背景是正确的做法

<?php

// input_file
$input_file = "100001.jpg";

// $output_file
$output_file = "100001.png";

// Load the image
$imagick = new Imagick(realpath($input_file));

$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);

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

// We eliminate empty areas to only leave objects
$imagick->trimImage(0);

// Maximum 500 height but the width can exceed 500 if the original image exceeds 500 somewhere
$imagick->resizeImage(0, 500, Imagick::FILTER_CATROM, 1);

// We export as PNG
$imagick->setImageFormat('png');

// Path to save new image
$imagick->writeImage($output_file);

// We clean cache
$imagick->clear();

// We destroy everything
$imagick->destroy();

?>

输出文件2:如果你注意的话,它也会擦除风扇内部的标志,甚至在右上方的螺丝上(见最后添加的绿色背景图片)


添加了带有绿色背景的图像以发现问题

输出文件 1: 不移除软管内的背景。

输出文件2:错误,去掉TT风扇标志和右上角风扇螺丝

【问题讨论】:

我已经很好地为您寻找了,Imagick 似乎没有办法忽略小区域而只透明填充较大的区域。它只是不知道什么是背景,什么是图像的一部分。 自动执行此操作几乎是不可能的,背景的定义会有所不同,并且会有些错误 输出是有道理的,风扇标志有一些与白色背景相似的白色像素,这只能手动解决,对于不是完全白色但在黑白之间过渡的边缘也是如此 还有一种叫做压缩的东西,如果你要去除背景,你最好把你的初始图像设置为 png 而不是 jpg...如果你很好奇为什么然后 google png vs jpg 【参考方案1】:

您可以制作一个简单的图像加载器并添加动态 div 插入,可以在图像上调整大小以忽略特定区域上的某些 x,y,当您使图像透明时,该区域将被排除。

【讨论】:

以上是关于PHP Imagick 将 JPG 转换为 PNG 并删除背景作品但并不完美的主要内容,如果未能解决你的问题,请参考以下文章

使用PHP Imagick将ICO转换为PNG。

在 PHP 中使用 Imagick 将 svg 转换为 png 时出现奇怪的裁剪问题

在 xampp Windows 上安装 imagick 库扩展?

使用 php Imagick 保留背景调整 PNG 的大小

用php为imagick设置密度参数

使用 PHP 将 PNG 转换为 JPG 并进行压缩?