35

Comparing two images to see if they are both the same files is easy: throw the files MD5. But is it possible or even plausible to determine if two images are same by using PHP GD to get the difference of the two images? If we were to get the difference of the two, and it was all white (I'd assume white or even black), then we would now know whether they were both the same photo?

Side note: I'd like to know if it's possible to get two images of equal size to create an onion skin effect: 50% transparency on one and 50% on the other.

2
  • libpuzzle is a PHP extension that can compare images. Commented Dec 18, 2011 at 15:05
  • Do you still need the transparency effect? I answered the title question, but could code the side note too. Commented Sep 4, 2020 at 6:40

5 Answers 5

24

Most of the other answers refer to using various hashing functions. The question explicitly is asking about comparing the contents of the images, not about comparing the files.

This means you end up having to actually understand the contents of the image. In PHP there are two extensions often used for this, ImageMagick and GD.

ImageMagick offers various tools you can use for this, through the PHP ImageMagick extension.

http://www.php.net/manual/en/function.imagick-compareimages.php

Biggest problem is that the documentation for that library is pretty much non-existing, so there will be a lot of trial-and-error involved. The PHP extension is a pretty thin wrapper around the ImageMagick library, so details of how the compareimages() function behaves can be found in the ImageMagick documentation.

Sign up to request clarification or add additional context in comments.

2 Comments

if we're not depended upon a library.... how was that?
Not sure I understand your question, gumuruh? If you don't want to depend on a library, you'd have to write the algorithms to parse + process image by yourself. ImageMagick is open source, so if you have way a lot of time (and are willing to sacrifice efficiency), I guess you could write a PHP-native implementation.
19
$md5image1 = md5(file_get_contents($image1)); $md5image2 = md5(file_get_contents($image2)); if ($md5image1 == $md5image2) { } 

8 Comments

Why not just use md5_file()?
That's really a file compare. Not so much an image compare which is what the question is.
@Jason why not just ($image1 == $image2)
I dont know why, but when comparing 2 identical images for me, md5 is failing and md5_file is working
If you are comparing images produced by different software (or even different libpng versions) then the same image can have different binary representations on disk, so MD5 comparisons will fail.
|
4

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

Comments

0

If you are comparing just two files then hashing data and then comparing is perfect solution. If you are comparing large number of files, then better sort them first based on size and then compare only with same size.

Comments

0

If you are using php 8.1 or higher, you can use https://github.com/sapientpro/image-comparator library for that:

$comparator = new SapientPro\ImageComparator\ImageComparator(); $similarity = $imageComparator->compare('your-images/your-image1.jpg', 'your-images/your-image12.jpg'); echo $similarity; // 82.3 

1 Comment

ImageComparator downscales both images to 8x8 and compares results. So, it's good for similarity, but not for exact matching.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.