Ooer.com by Chris Neale
Convolution Filters In GD

Convolution Filters In GD

Image filters are very useful things to have available. They enable you to take and image, and transform it to be a new work very simply, even automatically in many cases. They're an essential part of any image processing application. But wouldn't it be useful to give your users the ability to filter images with a range of different filter effects automatically when they upload an image? Hell yes.

Convolution filters allow you to do just that. Convolution is a mathematical process in which you multiply a matrix of numbers with a matrix of data to get a single result.


The maths may look complex, but its really just multiplication and addition many times over.

The first step to convolving an image is to open it. This is simply done using the usual image opening functions, usually imagecreatefromjpeg(). Once we have it open we also need to create an output image to draw our results onto. Ideally you will need to create the destination image in true colour mode as the convolution process tends to generate a large number of colours. This means that this image code is unsuitable for use on servers using GD 1.6 or lower.

<?php
$source
= imagecreatefromjpeg($file);
$image = imagecreatetruecolor(imagesx($source), imagesy($source));
?>

An image is made up of 3 or 4 seperate colour channels depending whether or not the image has an alpha transparency layer. In order to convolve an image we have to work on each channel seperately. I will skip over how the different channels are accessed as I have covered it in depth in a previous article.

In order to carry out the convolution we must loop through the pixels that make up the source image one by one convolving the pixel with its neighbours as we go, and drawing the results to our destination image.

<?php
for ($y=1;$y<imagesy($source)-1;$y++) {
for (
$x=1;$x<imagesx($source)-1;$x++) {
//convolution process
}
}
?>

The reason for starting at pixel 1 and ending on pixel imagesx($source)-1 is due to using a 3*3 convolution matrix. We don't want to convolve the pixels at the edges as this will give a messy border.

The next stage of the process is to extract the colour of the pixels we're dealing with. For a 3*3 matrix we need to get the colours of 9 pixels in total, the middle pixel which we're calculating the value for, and its neighbours whose values affect it. There are two ways to do this depending whether the source image is true colour or indexed colour. JPG images are true colour, so we'll use the method for that.
The PHP function imagecolorat() returns an integer representing the colour we need when used on a true colour image. Once we have this number we can extract the seperate channel integers.

<?php
$t1
= imagecolorat($source,$x-1,$y-1);
$p[0]['r'] = ($t1 >> 16) & 0xFF;
$p[0]['g'] = ($t1 >> 8) & 0xFF;
$p[0]['b'] = $t1 & 0xFF;
?>

In this example we are extracting the pixel information for the top left pixel ($t1) of our matrix (-1,-1). $p is an array used to hold the values of the colours. $p[0] equates to the top left, $p[1] to the top middle, and so on. This is the same index as we use for the convolution matrix array, so the code is relatively simple. Each element of the array has 3 sub-elements, 'r', 'g', and 'b', which corresponding to the red, green and blue constituents of the pixel.

Once we have the colours extracted we will need to set up an array and two variables to do the convolution process. The convolution matrix is an array of nine values. These value can be set differently to acheive different effects. In this example we will use a matrix for Gaussian Blurring. Aside from the array we need two more numbers. One is a factor by which we divide the number resulting from the convolution in order to get back to a value we can use as a colour, and the other is a constant we add on at the end if the convolution process can result in a negative value.

<?php
$m
= array(1,2,1,2,4,2,1,2,1);
$f = 16;
$c = 0;
?>

Actually convolving the convolution matrix with the extracted colour information is an easy process. All we have to do is multiply the value in the convolution array with the value in the same position in the colour array, divide by the factor we set up, and add on our constant. We need to do this for each of our three colour channels, and then recombine the channel values and draw the pixel to the destination image.

<?php
$pixel_r
= ((($p[0]['r']*$m[0]) + ($p[1]['r']*$m[1]) + ($p[2]['r']*$m[2]) + ($p[3]['r']*$m[3]) + ($p[4]['r']*$m[4]) + ($p[5]['r']*$m[5]) + ($p[6]['r']*$m[6]) + ($p[7]['r']*$m[7]) + ($p[8]['r']*$m[8]))/$f) + $c;
?>

The example only represents the code required to convolve the red channel.

<?php
$col
= imagecolorallocate($image,$pixel_r,$pixel_g,$pixel_b);
imagesetpixel($image,$x,$y,$col);
?>

Finally, once we have a completed image resource, we output it to the browser.

<?php
header
("Content-Type: image/jpeg");
imageJPEG($image);
?>

There are many different types of convolutions. The output of the code here can be changed dramatically simply by altering the matrix array set up. In this example we have created a Gaussian Blur filter, but the same code can be used to create a smoothing filter, edge detection filters, and even a Lapascian Emboss filter.