Compare 2 images in php

Viewed 68591

Comparing 2 images to see if they are both the same files are easy, threw the files MD5, but is it possible or even plausible to determine if 2 images are same by using PHP GD to get the difference of the two images. If we where to get the difference of the two, and it was all white (id assume white or even black), then we would now know its both the same photo?

Also side note: id like to know if its possible to get 2 images of equal size to create an onion skin effect, 50% transparency on 1 and 50% on the other.

8 Answers

A similar question was asked on this Stackoverflow thread and I had developed something for my own use. Posting it here so that it may help others.

It takes two (or more images) and gives you options about checking the difference between them. Options like resolution to use, and strictness.

I wrote a more comprehensive blogpost on it as well.

I coded a kind of Mean Square Error comparing method, using GD Graphics Library already included in PHP.

I was concerned about time, so I included some options such as:

But seeing the results, if you are doing bulk operations, perhaps the best is to hardcode the options to avoid the overhead of the conditional lines.

This is the code, with some test and a benchmark:

<?php
define('FILENAME1','./image1.png'); 
define('FILENAME2','./image2.png');    
define('OUTEXT','png'); //Output extension
    
/**
 * Calculate an arbitrary metric of difference between images
 * 
 * @param resource(gd) $img1 First image
 * @param resource(gd) $img2 Second image
 * @param int $resX Scaled width resolution
 * @param int $resY Scaled height resolution
 * @param int $pow Mean square error if 2, but could be another power
 * @param string $channel RGB channel or 'all' for perceived luminance
 *
 * @return float the calculated metric
 */
function diff($img1,$img2,$resX=false,$resY=false,$pow='2',$channel='all'){ 
    //Scaling to image 1 size for default
    if(!$resX||!$resY){     
        $resX=imagesx($img1); //width
        $resY=imagesy($img2); //height
    }
    //Use imagescale() function to scale the images 
    $thumb1=imagescale($img1,$resX,$resY);
    $thumb2=imagescale($img2,$resX,$resY);
    //Sum of errors
    $sum=0;
    for($x=0;$x<$resX;++$x){
        for($y=0;$y<$resY;++$y){
            //Read pixel bytes
            $bytes1=imagecolorat($thumb1,$x,$y);
            $bytes2=imagecolorat($thumb2,$x,$y);
            //Split the channel values from bytes
            $colors1=imagecolorsforindex($thumb1,$bytes1);
            $colors2=imagecolorsforindex($thumb2,$bytes2);
            //Choose image channel
            if($channel=='all'){
                //Perceived luminance
                $value1=sqrt(0.2126*$colors1['red']**2+0.7152*$colors1['green']**2+ 0.0722*$colors1['blue']**2);
                $value2=sqrt(0.2126*$colors2['red']**2+0.7152*$colors2['green']**2+ 0.0722*$colors2['blue']**2);
            }else{
                //RGB channel
                $value1=$colors1[$channel];
                $value2=$colors2[$channel];
            }
            $sum+=abs($value1-$value2)**$pow;           
        }
    }
    //Return mean of the error sum
    return $sum/($resX*$resY);
}

//Show image in HTML
function imgdraw($imgobj){      
    //Choose function
    $image="image".OUTEXT;
    //Capture the image data stream     
    ob_start();     
    $image($imgobj);        
    $data = ob_get_clean();     
    //Create and HTML img
    echo '<img src="data:image/png;base64,'.base64_encode($data).'" />';
}

//Load an image
function loadimg($filename){
    //Get filename extension
    $ext=substr($filename,strrpos($filename,'.')+1);
    //Create image object
    $imagecreate="imagecreatefrom$ext";
    return $imagecreate($filename);
}

//Test 
$img1=loadimg(FILENAME1);
$img2=loadimg(FILENAME2);
if( !$img1 || !$img2){
    //Problem reading the files
    die("Error loading image files");
}else{
    imgdraw($img1);
    imgdraw($img2);
}

//Times for 133x144 pixels png images
echo "<p>original size MSE perceived luminance: ".diff($img1,$img2)."</p>";
//time: 0.2281 seconds.
echo "<p>original size MSE green channel: ".diff($img1,$img2,false,false,2,'green')."</p>";
//time: 0.1364 seconds.
echo "<p>original size linear perceived luminance: ".diff($img1,$img2,false,false,1)."</p>";
//time: 0.1920 seconds.
echo "<p>original size linear green channel: ".diff($img1,$img2,false,false,1,'green')."</p>";
//time: 0.1351 seconds.
echo "<p>64x64 MSE perceived luminance: ".diff($img1,$img2,64,64)."</p>";
//time: 0.0431 seconds.
echo "<p>64x64 MSE green channel: ".diff($img1,$img2,64,64,2,'green')."</p>";
//time: 0.0293 seconds.
echo "<p>64x64 linear perceived luminance: ".diff($img1,$img2,64,64,1)."</p>";
//time: 0.0423 seconds.
echo "<p>64x64 linear green channel: ".diff($img1,$img2,64,64,1,'green')."</p>";
//time: 0.0293 seconds.
echo "<p>16x16 MSE perceived luminance: ".diff($img1,$img2,16,16)."</p>";
//time: 0.0028 seconds.
echo "<p>16x16 MSE green channel: ".diff($img1,$img2,16,16,2,'green')."</p>";
//time: 0.0027 seconds.
echo "<p>16x16 linear perceived luminance: ".diff($img1,$img2,16,16,1)."</p>";
//time: 0.0027 seconds.
echo "<p>16x16 linear green channel: ".diff($img1,$img2,16,16,1,'green')."</p>";
//time: 0.0018 seconds.
?>
Related