PHP Imagick - 将图像转换为灰度(结果非常糟糕)

4

我正在使用PHP进行图像编辑,由于GD提供的功能较少,因此我切换到了Imagick。

其中一个过程是将图像灰度化。一切都很顺利(在本地的Windows 7上,Imagick 2.2.1-dev 6.5.8-7 Q16),直到我将脚本上传到我的Web托管服务器(Linux,Imagick 3.0.1,6.2.8,2010-10-20,Q16)。

我尝试了更改质量,但没有改善任何内容。

$img->setImageCompression(imagick::COMPRESSION_JPEG); 
$img->setImageCompressionQuality(100);

以下是GD、Imagick和Photoshop的结果: enter image description here

我认为版本3.0.1出了问题。有人可以确认一下吗?

Q1: 是否有其他方法可以使用Imagick将图像转换为灰度?

Q2: 是否可以将GD资源转换为Imagick?这样我就可以使用imagefilter($img, IMG_FILTER_GRAYSCALE);来获取正确的结果,然后使用Imagick输出。

附注:对于Q2,您可能会建议我只使用GD来处理图像。但问题是imagejpeg()不能保存保留分辨率的图像。这实际上是我切换到Imagick的原因。


2
你用什么代码来使用Imagick将图像转换为灰度?你是否使用了 $image->setColorspace(imagick::COLORSPACE_GRAY); 这个函数?同时,可以参考一下这个链接:http://stackoverflow.com/questions/4539307/php-imagicklevelimage-usage?rq=1 - Jeremy C
它是$img->modulateImage(100, 0, 100);,其中参数为(亮度,饱和度,色调)。我相信这是正确的函数使用方式,并且在2.2.1版本中确实可以正常工作。 - user1643156
仅仅因为某个版本可以工作并不意味着它是正确的函数。使用Jeremy提到的方法可以确保你的图片实际上是灰度图像,即使是JPEG文件格式。而你现在所做的只是一个滤镜。编辑:谷歌搜索结果中有三个建议采用Jeremy的方法。 - Christian
看起来这个功能只在6.5.7版本之后才可用,而你的服务器上可能使用的是旧版本。modulateImage应该可以工作,但显然效果不如预期。http://php.net/manual/en/imagick.setcolorspace.php - Jeremy C
@Christian,你看过手册了吗?modulateImage确实是改变亮度、饱和度和色调的函数。为什么不使用它呢?版本2.2.1产生的结果几乎与Photoshop相同。而3.0.1的结果显然是错误的。 - user1643156
@user1643156 modulateImage() 做了比你需要的更多的事情,这使它更容易出现问题(正如你刚刚看到的)。颜色空间的方法更加可靠,因为你告诉 imagick 明确地切换到灰度,而不仅仅是应用随机的颜色滤镜(我的意思是,imagick 知道你的最终结果应该是灰度吗?)。 - Christian
4个回答

3
这是我在php/imagick中制作黑白照片的首选方式:$im = $im->fxImage('intensity'); 这个函数应用于图像,其中intensity等于0.299*红色+0.587*绿色+0.114*蓝色
这个公式基于我们眼睛对不同颜色更敏感的原理,因此与“平淡”灰度图像之间的差异确实天壤之别。
更多详情请参见:

0
function ImagickToGD($imagick){
    $tmpfile = tmpfile();
    $imagick->writeImage($tmpfile);
    return imagecreatefromstring(file_get_contents($tmpfile));
}

请注意,此函数不执行任何清理操作(除了临时文件,PHP会自动清理)。
因此,例如,您的代码应该如下所示:
$img = new Imagick();
// ...
$gd = ImagickToGD($img);
unset($img); // destroy imagick
imagefilter($gd, IMG_FILTER_GRAYSCALE);
imagejpeg($gd, $target_name, 100);
imagedestroy($gd);

另外,我不理解“保留分辨率”的部分。这些操作中没有任何与分辨率相关的内容。我猜你是指压缩?如果你想要完整的质量(即无压缩),只需将压缩值设为100(就像我所做的那样)。

这样可以保持现有的质量,因为打开一个70%质量的图像并以70%的质量保存它实际上会使最终质量降低49%(70%的70%)。


function GDToImagickTo($gd){
    $tmpfile = tmpfile();
    imagepng($tmpfile); // Png is our best image deal:
                        // lossless compression, transparency etc..
    $imagick = new Imagick()
    $imagick->readImage($tmpfile);
    return $imagick;
}

抱歉,我实际上是指 GDToImagick....所以我可以使用 gd 进行灰度处理 -> gd2imagick() -> 然后使用 imagick 输出图像。 - user1643156
我已经更新了答案,加入了你想要的函数。关于 DPI 问题,它可以从客户端进行更改(与压缩不同,后者实际上会破坏图像)。此外,我看到了一些用于更改 DPI 的脚本。你可以始终使用 imagejpg(); $imagick->readImage(); $imagick->setImageResolution(); $imagick->writeImage();(简洁明了)来实现。 - Christian
... imagepng(),imagejpeg()...它们是同一件事情。只要使用这些函数,图像的分辨率将被降低到72dpi,但在显示器上仍然可以清晰地看到。但是当您使用打印机打印时,它只有原始图像的一半大小(72/150)。而且,您不能指望客户知道图像编辑,既没有脚本也没有Photoshop,至少不是我的客户。他们扫描、上传、合并、下载、打印... - user1643156
错误!分辨率只是告诉打印机如何打印图像,图像数据并没有改变。举个例子,拿一台扫描仪扫描相同的图像两次,但分辨率不同;你会发现,两张图像是不同的,因为光栅化图像包含像素,而分辨率只告诉像素在纸上应该看起来多大。因此,高密度图像只是一个放大的图像(即实际图像必须更改)。对于您的图像来说,输入与输出完全相同,这种情况并非如此。 - Christian
总之,JPEG分辨率只是元数据。它不会影响实际图像。分辨率更高的图像需要更大的尺寸(以像素为单位)。当您更改分辨率元数据时,图像保持不变。如果您不更改元数据,则图像仍然保持不变。有关更多信息,请阅读此文(还有许多其他文章可供参考)。 - Christian
显示剩余4条评论

0

ImageMagick和Imagick在这里是完全不同的东西。我谈论的是编程,而不是桌面应用程序... - user1643156

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接