
- Drop me a line! Contact me here.
Black and White in GD
Black and White in GD
One of the more effective methods of image manipulation is to convert a colour image to a black and white, or greyscale, picture. Black and white images can convey emotion and drama brilliantly, so they're great for using in certain styles of websites. Wouldn't it be great to be able to convert an uploaded image to greyscale automatically using PHP?
Converting an image into a different colour space is quite a simple process. As with many image processing scripts we need to open the image to be converted to start off with. We also need to open a blank GD image resource with the same dimensions as the opened image so that we have somewhere to draw to.
We have used the imagecreate() function to create the blank image in this example rather than imagecreatetruecolour(). In creating a black and white image we will only require 256 colours in the destination image, not 16.7million as in a true colour image.
The next stage of the process is to allocate a colour palette. As we need a range of 256 colours its best to create a loop that iterates 256 times creating a colour with each iteration. These colours will be placed into an array for easy access later.
Obviously this loop with produce a palette of colours from black through to white. You don't have to stick with standard greys though, it would be simple to produce a range of any colours.
The next part of the process is to scan through the pixels of the source image one by one and convert them to a greyscale colour, and write that colour to the destination image. This is done by scanning the rows pixel by pixel and using some standard colour extraction code.
The code that we need to concern ourselves with is that greyscale() function that takes the $r, $g, and $b values, does something to them, and returns a value between 0 and 255 that corresponds to the level of grey the pixel should be set to in the destination image.
The simplest form of greyscale() function is to pick one of the RGB values and just return it. This will extract the red, green or blue channel from the source image and output a greyscale image based upon it.
In this example we're returning the value of the blue channel. While this method of building a greyscale image does work, it is not ideal. Images are made up of all three channels, and using just one will almost always result in large amounts of detail being lost.
Converting an image into a different colour space is quite a simple process. As with many image processing scripts we need to open the image to be converted to start off with. We also need to open a blank GD image resource with the same dimensions as the opened image so that we have somewhere to draw to.
<?php
$source = imagecreatefromjpeg($file);
$image = imagecreate(imagesx($source),imagesy($source));
?>
We have used the imagecreate() function to create the blank image in this example rather than imagecreatetruecolour(). In creating a black and white image we will only require 256 colours in the destination image, not 16.7million as in a true colour image.
The next stage of the process is to allocate a colour palette. As we need a range of 256 colours its best to create a loop that iterates 256 times creating a colour with each iteration. These colours will be placed into an array for easy access later.
<?php
for ($i=0;$i<256;$i++) {
$palette[$i] = imagecolorallocate($image,$i,$i,$i);
}
?>
Obviously this loop with produce a palette of colours from black through to white. You don't have to stick with standard greys though, it would be simple to produce a range of any colours.
The next part of the process is to scan through the pixels of the source image one by one and convert them to a greyscale colour, and write that colour to the destination image. This is done by scanning the rows pixel by pixel and using some standard colour extraction code.
<?php
for ($y=1;$y<imagesy($source);$y++) {
for ($x=1;$x<imagesx($source);$x++) {
$rgb = imagecolorat($source,$x-1,$y-1);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
//Convert to greyscale
$g = greyscale($r,$g,$b);
imagesetpixel($image,$x,$y,$palette[$g]);
}
}
?>
The code that we need to concern ourselves with is that greyscale() function that takes the $r, $g, and $b values, does something to them, and returns a value between 0 and 255 that corresponds to the level of grey the pixel should be set to in the destination image.
The simplest form of greyscale() function is to pick one of the RGB values and just return it. This will extract the red, green or blue channel from the source image and output a greyscale image based upon it.
<?php
function greyscale($r,$g,$b) { return $b; }
?>
In this example we're returning the value of the blue channel. While this method of building a greyscale image does work, it is not ideal. Images are made up of all three channels, and using just one will almost always result in large amounts of detail being lost.
An alternative method of creating a black ad white image is to use the variance, or brightness, of the colours. The brightness channel will have the highest value, so all we need do is find the highest value and return it.
This method is better than the first function as it produces a result nearer to the original image. In the first method high values in a channel that we were not using didn't affect the final image at all, while in this version all three channels are used, so high values in any channel can have an affect.
Of course, this still isn't quite perfect.
The next method of colour to black and white conversion takes an average value of all the colours in the source image and uses this as the output value.
This is a small improvement for some images, but in images with wildly varying colour the result tends to appear washed out and dull.
When the human eye looks at things it doesn't see all colours in the same way. The eye is less sensitive to green hues then it is to red, and less to red than it is to blue. Therefore to covert to black and white in a way that properly maintains the difference between colours in the original image as it does in the destination image we need to use a function that considers the values of the input colours.
The final method of greyscale conversion is based around the NTSC RGB YIQ colour space conversion algorithm. Using a set of ratios we take part of the red, green and blue channels and combine them to use as our value.
These ratio values are predefined as part of the YIQ algorithm.

<?php
function greyscale($r,$g,$b) {
return max($r,$g,$b);
}
?>
This method is better than the first function as it produces a result nearer to the original image. In the first method high values in a channel that we were not using didn't affect the final image at all, while in this version all three channels are used, so high values in any channel can have an affect.
Of course, this still isn't quite perfect.
The next method of colour to black and white conversion takes an average value of all the colours in the source image and uses this as the output value.
<?php
function greyscale($r,$g,$b) {
return ($r+$g+$b)/3;
}
?>
This is a small improvement for some images, but in images with wildly varying colour the result tends to appear washed out and dull.
When the human eye looks at things it doesn't see all colours in the same way. The eye is less sensitive to green hues then it is to red, and less to red than it is to blue. Therefore to covert to black and white in a way that properly maintains the difference between colours in the original image as it does in the destination image we need to use a function that considers the values of the input colours.
The final method of greyscale conversion is based around the NTSC RGB YIQ colour space conversion algorithm. Using a set of ratios we take part of the red, green and blue channels and combine them to use as our value.
These ratio values are predefined as part of the YIQ algorithm.
<?php
function greyscale($r,$g,$b) {
return (($r*0.299)+($g*0.587)+($b*0.114));
}
?>

- © Ooer.com Chris Neale 2007
- PHPGD.com
- Powered by PHP
- Database by MySQL
- DB Queries: 3
- DB Time: 0.0539 seconds
