Grayscale Images with GD

In computing, a grayscale or greyscale digital image is an image in which the value of each pixel is a single sample, that is, it carries the full (and only) information about its intensity. Images of this sort are composed exclusively of shades of neutral gray, varying from black at the weakest intensity to white at the strongest.

In PHP, it is easy enough to do. First we want to create two image resources. First we need our original image so we can map its color. Second we need to create an image which will become our grayscale image.

<?php
//change this to your image location
$original = @imagecreatefrompng("/home/john/Documents/colorized.png")
    or die("Cannot Initialize new GD image stream");

$im = @imagecreate(imagesx($original), imagesy($original))
    or die("Cannot Initialize new GD image stream");

Next we want to create our color pallet. Since we our goal is a gray image,we will only use shades of black and white. Colorized images are generally within the RGB color space. Meaning each pixel is composed of red, green, and blue light which allows you to reproduce a broad array of colors. White is represented as 255,255,255 and black is represented as 0,0,0. Therefore, all gray shades are represented as x,x,x. So we thus create our pallet:

<?php
for ($i = 0; $i <= 255; $i++) {
    $palette[$i] = imagecolorallocate($im, $i, $i, $i);
}

Next we want to create a function to convert from the RGB color space to some color space that only represents the pixels intensity. The YIQ is the best color space for this since the Y represents the luma of the pixel. The numbers I use in the function below comes from the Y component: YIQ – Wikipedia, the free encyclopedia

<?php
function grayscale($r, $g, $b) {
    return 0.299*$r + 0.587*$g + 0.114*$b;
}

Now we actually need to get the RGB values of each pixel so we can convert if. To do this, we iterate over the entire image (so large images will take some time), and place the transformed pixel onto the new image we wish to create.

<?php
for($x = 0; $x < imagesx($original); $x++) {
    for($y = 0; $y < imagesy($original); $y++) {
        $rgb = imagecolorat($original, $x, $y);
        $r = ($rgb >> 16) & 0xFF;
        $g = ($rgb >> 8) & 0xFF;
        $b = $rgb & 0xFF;
        imagesetpixel($im, $x, $y, $palette[grayscale($r, $g, $b)]);
    }
}

Now all that is left is to set the header and create the image. The final code is below.

<?php
header("Content-type: image/png");

$original = @imagecreatefrompng("/home/john/Documents/colorized.png")
    or die("Cannot Initialize new GD image stream");

$im = @imagecreate(imagesx($original), imagesy($original))
    or die("Cannot Initialize new GD image stream");

for ($i = 0; $i <= 255; $i++) {
    $palette[$i] = imagecolorallocate($im, $i, $i, $i);
}

function grayscale($r, $g, $b) {
    return 0.299*$r + 0.587*$g + 0.114*$b;
}

for($x = 0; $x < imagesx($original); $x++) {
    for($y = 0; $y < imagesy($original); $y++) {
        $rgb = imagecolorat($original, $x, $y);
        $r = ($rgb >> 16) & 0xFF;
        $g = ($rgb >> 8) & 0xFF;
        $b = $rgb & 0xFF;
        imagesetpixel($im, $x, $y, $palette[grayscale($r, $g, $b)]);
    }
}

imagepng($im);
imagedestroy($im);
?>

Attached is an example of a colorized image (left) and the same image using the above code (right)

Related posts:

  1. Getting to know GD Create dynamic userbars with GD Introduction: Have you ever been on aim and received a message from one of your...
  2. HTML with Swing Components One useful feature of Swing GUI’s many people overlook is the ability to use simple HTML tags within swing components....

Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Notify me of followup comments via e-mail. You can also subscribe without commenting.


2 Responses to “Grayscale Images with GD”

  1. Rob

    The 0.199 multiplier for the red should be 0.299

    Other than that, well done.

    Reply |

    • John

      Thanks for pointing that out. I changed the code to reflect the proper numbers.

      Reply |