PHP GD的图像重新着色功能太慢了

时间:2015-10-01 02:26:29

标签: php image-processing imagemagick gd imagick

我在PHP中编写了这个函数,用于将图片从一种颜色更改为另一种颜色,我非常喜欢它。对我而言,它看起来非常逼真,并且它似乎很好地考虑了原始图像的亮度。但是,它很慢。使用我正在使用的图像尺寸,重新着色一个图像大约需要23秒。我知道减速带是从每个像素循环开始的,所以我通过Imagick类尝试了一些不同的Imagemagick函数组合,但是我找不到任何组合,我喜欢和我的函数一样多的结果。有没有办法,也许使用C,我可以把它写成Imagemagick的某种插件,甚至通过Imagick类使它可用,所以我不必通过exec()之类的东西来运行它?我也尝试过使用Imagick的PixelIterator,然后查看了fxImage,但是如果不是更糟的话,那些也一样慢。

public function colorize($img, $rgb) {
    imagealphablending($img, true);
    imagesavealpha($img, true);

    // get width and height of image
    $iwidth = imagesx($img);
    $iheight = imagesy($img);

    // loop through each pixel
    for ($y=0; $y<$iheight; $y++) for ($x=0; $x<$iwidth; $x++) {
        // get all original r, g, b, a values of the pixel
        $orgb = imagecolorat($img, $x, $y);
        $oa = ($orgb >> 24) & 0xFF;
        $or = ($orgb >> 16) & 0xFF;
        $og = ($orgb >> 8) & 0xFF;
        $ob = $orgb & 0xFF;

        // add up orginal rgb values and new rgb values
        $total_original = $or + $og + $ob;
        $total_new = $rgb[0] + $rgb[1] + $rgb[2];

        // adjust brightness using average of rgb channels
        $bright = -127 + $total_new/3;
        // take average difference between new color's brightness and old color's brightness, add brightness adjustment to it, and round
        $adjustment = round($bright + ($total_new - $total_original) / -3);

        // set each channel to new color channels, add the adjustment, and make sure the result isn't less than 0 or greater than 255
        $r = max(0,min($adjustment + $rgb[0],255));
        $g = max(0,min($adjustment + $rgb[1],255));
        $b = max(0,min($adjustment + $rgb[2],255));

        // replace original pixel
        $nrgb = imagecolorallocatealpha($img, $r, $g, $b, $oa);
        imagesetpixel($img, $x, $y, $nrgb);
    }
}

2 个答案:

答案 0 :(得分:0)

您可以将所谓的modules添加到ImageMagick中 - 尽管它非常复杂。

首先,您将需要ImageMagick的来源和开发环境 - 例如编译器和make等。

然后,您需要使用配置标志--with-modules=yes构建ImageMagick。

构建模块后,您需要在命令行上实际调用它,或者修改PHP / Perl绑定以执行此操作。实质上,它在命令行中看起来像这样:

convert image.png -process YourModuleName <YourModuleParameters> output.png

有更多信息here - 虽然它是为Windows编写的,但您可以在Linux上使用它 - 我也在Mac OSX上成功构建了模块。

答案 1 :(得分:0)

这是一个更多的建议而不是一个答案,但长期以来一直是评论格式。

(1)ColorMatrix

据我所知,您正在进行的色彩增强实质上是对用户提供的颜色的现有色彩进行调整。这让我想起了Fred's whiteblance脚本,它利用了-color-matrix运算符(或PHP中的Imagick::colorMatrixImage())。

这可以定义为......

 new_red   = (delta) * red +       0 * green +       0 * blue
 new_green =       0 * red + (delta) * green +       0 * blue
 new_blue  =       0 * red +       0 * green + (delta) * blue

目标是计算用户提供的颜色的delta,并直接调整矩阵。

示例从白色计算给定的颜色。

$delta_red   = 0xFF/$rgb[0];
$delta_green = 0xFF/$rgb[1];
$delta_blue  = 0xFF/$rgb[2];
$wand = new Imagick($img);
$wand->colorMatrixImage([$delta_red,            0,           0,
                                  0, $delta_green,           0,
                                  0,            0, $delta_blue]);

(2)远离RGB色彩空间

我想到的另一件事是你的例子中的计算可能只是调整颜色的强度。忽略给定的颜色一分钟,我们可以考虑如何增强YCbCR颜色空间中的图像。如果我们将图像转换为不同的颜色空间,我们可以通过简单地调整亮度通道来应用相同的颜色增强。

$wand = new Imagick('rose:');
// Change colorspace
$wand->setImageColorspace(Imagick::COLORSPACE_YCBCR);

// Get quantum to work with
$qr = $wand->getQuantumRange()['quantumRangeLong'];

// Perform enhancement calculations (hard-coded for example)
$blackPoint = 0.1 * $qr;
$whitePoint = 0.9 * $qr;
$gamma = 1;
$sigmod = 0.001;

$Y = Imagick::CHANNEL_RED; // Red is the first channel, or Y in this colorspace.
// Re-level Y 
$wand->levelImage($blackPoint, $gamma, $whitePoint, $Y);
// Adjust contrast of Y
$wand->sigmoidalContrastImage($sigmod, 1, 1, $Y);

// Put it back RGB
$wand->setImageColorspace(Imagick::COLORSPACE_SRGB);

YCbCr example

希望有所帮助。