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