Converting Images To The Colour Pallet From The Matrix In PHP

Have you ever noticed the slightly green colouration in the movie The Matrix? The movies are full of different colour pallets, but when inside The Matrix everything gets a slight green colouration.

This is colour pallet is created as a post processing step, using a colour grading algorithm. The original colours of the film are passed through a filter to tweak the colours slightly for the scenes inside the simulation.

In this article we will look at how we can convert a pixel so that it has the green colour grading found in the matrix, and how to use the system on images in PHP.

The filter algorithm works by extracting the red, green, and blue colours from the film and converting them to a scale from 0 to 1. The red channel is then raised to the power of 7/5 and the blue channel is raised to the power of 8/5. The green channel is not altered in this process.

We can represent this process in the following way.

(r, g, b) => (r^7/5, g, b^8/5)

Or, in decimal format, this would be.

r, g, b => (r^1.4, g, b^1.6)

As we are raising a number between 0 and 1 to a power greater than 1 it causes those channels to reduce slightly. All we need to do is run this algorithm on every pixel in the image.

In PHP, we get extract the colour value of a pixel using the imagecolorat() function. This returns an integer value that we can extract the red, green, blue colours from.

$colour = imagecolorat($img, $x, $y);

// Extract the red, green, blue values.
$r = ($colour >> 16) & 0xFF;
$g = ($colour >> 8) & 0xFF;
$b = $colour & 0xFF;

The red, green, and blue values here are on a scale between 0 and 255. This means that before we pass them through the calculation we need to convert them to the range from 0 to 1, which is done by dividing the number by 255.

// Convert the red value from the range 0-255 into the range 0-1.
$r = ($r / 255);
// Increase the value by a power of 1.4.
$r = min(pow($r, 1.4), 1);
// Convert the value back into the rage 0-255.
$r = 255 * ($r);

// Convert the blue value from the range 0-255 into the range 0-1.
$b = ($b / 255);
// Increase the value by a power of 1.6.
$b = min(pow($b, 1.6), 1);
// Convert the value back into the rage 0-255.
$b = 255 * ($b);

We can then set the colour of the same pixel in the new image using the imagecolorallocate() to set the colour and imagesetpixel() to set the pixel to that colour.

// Create the new colour.
$newColour = imagecolorallocate($newImage, $r, $g, $b);

// Set the pixel in the new image.
imagesetpixel($newImage, $x, $y, $newColour);

Rather than show the different colours that this algorithm produces, let's run this on an image so it's clear what happens. Here's a picture of me doing a talk at DrupalCamp Scotland 2024. This is currently my author bio picture so I had it readily at hand.

Phil Norton doing a talk at DrupalCamp Scotland 2025. He is facing towards the right of the image, looking at the off audience who are out of the image.

After running this image through the colour conversion algorithm the image is now of me doing a talk in the constructed reality of The Matrix.

The same image as above, but in this case the greens have been hightened and it appears to have been filmed in The Matrix,

It's certainly green.

By reducing the red and blue the green is enhanced in a particular way, but not much information is lost in the conversion. We still have all of our base colours in place and the only information lost is where red or blue colours are very close to zero as those values will be flattened to zero. 

Putting this all together we get the following function.

/**
 * Transform a JPEG image file into matrix colour scheme.
 *
 * The matrix colour scheme is calculated by taking the red, green and blue
 * values from an image and converting them to the range 0-1. The values are
 * then processed using the formula r^7/5, g, b^8/5 or r^1.4, g, b^1.6 in
 * decimal terms. We then convert that back into the range 0-255 before
 * creating an image using the new colours.
 *
 * The resulting image file is prefixed with "matrix_" and saved to disk. The
 * original file is not changed.
 *
 * @param string $imgfile
 *   The file to transform.
 */
function matrixFilter(string $imgfile) {
    // Load the image into memory.
    $img = imagecreatefromjpeg($imgfile);

    // Get the dimensions of the image.
    $imagex = imagesx($img);
    $imagey = imagesy($img);

    // Create a new image with these dimensions.
    $newImage = imagecreatetruecolor($imagex, $imagey);

    // Loop through all the pixels in the current image.
    for ($x = 0; $x < $imagex; $x++) {
        for ($y = 0; $y < $imagey; $y++) {
            $colour = imagecolorat($img, $x, $y);

            // Extract the red, green, blue values.
            $r = ($colour >> 16) & 0xFF;
            $g = ($colour >> 8) & 0xFF;
            $b = $colour & 0xFF;

            // Convert the red value from the range 0-255 into the range 0-1.
            $r = ($r / 255);
            // Increase the value by a power of 1.4.
            $r = min(pow($r, 1.4), 1);
            // Convert the value back into the rage 0-255.
            $r = 255 * ($r);

            // Convert the blue value from the range 0-255 into the range 0-1.
            $b = ($b / 255);
            // Increase the value by a power of 1.6.
            $b = min(pow($b, 1.6), 1);
            // Convert the value back into the rage 0-255.
            $b = 255 * ($b);

            // Create the new colour.
            $newColour = imagecolorallocate($newImage, $r, $g, $b);
            // Set the pixel in the new image.
            imagesetpixel($newImage, $x, $y, $newColour);
        }
    }

    // Write the new image to disk.
    imagejpeg($newImage, 'matrix_' . $imgfile);

    // Clean up the memory.
    imagedestroy($img);
    imagedestroy($newImage);
}

This function accepts only JPEG images so if you attempt to feed other image formats to it an error will be returned.

Use the function in the following way.

matrixFilter('someimage.jpg');

Feel free to use this on your own image to convert JPEG format images.

One avenue of improvement to this code would be to make this function more generic, so instead of hard coding the colour scaling values in we accept them as parameters and alter the colours accordingly.

Add new comment

The content of this field is kept private and will not be shown publicly.