2

I am trying to blur an image and need a faster solution.

This is my current attempt which is much too slow for large images and I do not want to use imagick.

public function blur($filename, $extension, $factor = 20){
    if (strtolower($extension) === "jpg" || strtolower($extension) === "jpeg") $image = imagecreatefromjpeg($filename);
    if (strtolower($extension) === "png") $image = imagecreatefrompng($filename);

    for ($x=1; $x<=$factor; $x++)
       imagefilter($image, IMG_FILTER_GAUSSIAN_BLUR);
    imagejpeg($image, "$filename.blur.$extension");
    imagedestroy($image);

}

Is there a PHP implementation of stackblur or another fast algorithm available?

MeNa
  • 1,467
  • 9
  • 23
Stephan Ahlf
  • 3,310
  • 5
  • 39
  • 68
  • You can use [SimpleImage class](https://github.com/claviska/SimpleImage). But afaik this class also uses the GD Lib and so this filter. – TiMESPLiNTER Nov 28 '13 at 09:20
  • Well it might be a good approach. Will test this one out thanks. – Stephan Ahlf Nov 28 '13 at 09:21
  • 1
    Modern versions of PHP support various image manipulation libraries such as Cairo, GD, Gmagick and ImageMagick. You could try substitutiong one of those, but I doubt the performance would be hugely faster. You might want to consider handing the image generation off to a background job so the main job can complete sooner instead. – GordonM Nov 28 '13 at 09:49

1 Answers1

15

The simple solution is to scale the image down before you apply the blur filter. Here are some examples:

Original image:

Photo of a cat (public domain: Longhair_Tabby_JaJa.jpg from Wikimedia Commons)

20× Gaussian Blur (2.160 seconds):

{
  $start = microtime(true);
  for ($x=0; $x<20; $x++) {
    imagefilter($image, IMG_FILTER_GAUSSIAN_BLUR);
  }
  $end =  microtime(true);
  $howlong = $end - $start;
}

Result of applying Gaussian blur filter 20 times

Combination of scaling and Gaussian blur (0.237 seconds):

{
  $start = microtime(true);

  /* Scale by 25% and apply Gaussian blur */
  $s_img1 = imagecreatetruecolor(160,120);
  imagecopyresampled($s_img1, $image, 0, 0, 0, 0, 160, 120, 640, 480);
  imagefilter($s_img1, IMG_FILTER_GAUSSIAN_BLUR);

  /* Scale result by 200% and blur again */
  $s_img2 = imagecreatetruecolor(320,240);
  imagecopyresampled($s_img2, $s_img1, 0, 0, 0, 0, 320, 240, 160, 120);
  imagedestroy($s_img1);
  imagefilter($s_img2, IMG_FILTER_GAUSSIAN_BLUR);

  /* Scale result back to original size and blur one more time */
  imagecopyresampled($image, $s_img2, 0, 0, 0, 0, 640, 480, 320, 240);
  imagedestroy($s_img2);
  imagefilter($image, IMG_FILTER_GAUSSIAN_BLUR);
  $end =  microtime(true);
  $howlong = $end - $start;
}

Result of applying a combination of image scaling and Gaussian blur

r3mainer
  • 23,981
  • 3
  • 51
  • 88
  • Only problem with that is when you scale it back up the pixels become apparent. I can see them fairly clearly in your example image. If the OP is okay with the "grungy" look than of course that's fine, but it's not such a great solution if they need to maintain the PPI. – GordonM Nov 28 '13 at 12:09
  • @GordonM I see what you mean. I've replace the third image with one that uses 6 iterations of Gaussian blur after scaling back to the original dimensions. For comparison, the original image (2 iterations) is here: [i.stack.imgur.com/XqIMi.jpg](http://i.stack.imgur.com/XqIMi.jpg) – r3mainer Nov 28 '13 at 13:10
  • @GordonM I've found a better way of doing it — if the image is scaled back to its original size in stages, then it only needs one pass of the blur filter at each stage. – r3mainer Nov 28 '13 at 13:29
  • gaussian_blur will still take 5+ seconds for a single pass on large images (3000px by 2000px, for example). Seems canvas + stackblur algorithm is the only open source library solution to do this quickly (though I'm sure stackblur could be made in PHP I'm not smart enough to do it) – sricks Sep 11 '15 at 00:05