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. ?>