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 将 svg 转换为 png 时出现奇怪的裁剪问题