Percentage difference between images

From Rosetta Code
Task
Percentage difference between images
You are encouraged to solve this task according to the task description, using any language you may know.

Compute the percentage of difference between 2 JPEG images of the same size. Alternatively, compare two bitmaps as defined in basic bitmap storage.

Useful for comparing two JPEG images saved with a different compression ratios.

You can use these pictures for testing:

The expected difference for these two images is 1.62125%

Ada

<lang ada> type Count is mod 2**64; </lang> 1-norm distance in the luminance space: <lang ada> function "-" (Left, Right : Luminance) return Count is begin

  if Left > Right then
     return Count (Left) - Count (Right);
  else
     return Count (Right) - Count (Left);
  end if;

end "-"; </lang> 1-norm distance in the color space multiplied to 3: <lang ada> function "-" (Left, Right : Pixel) return Count is begin

  return Left.R - Right.R + Left.G - Left.G + Left.B - Right.B;

end "-"; </lang> Mean of 1-norm distances. Constraint_Error is propagated when images have different size. <lang ada> function Diff (Left, Right : Image) return Float is

  Offs_I : constant Integer := Right'First (1) - Left'First (1);
  Offs_J : constant Integer := Right'First (2) - Left'First (2);
  Sum : Count := 0;

begin

  if Left'Length (1) /= Right'Length (1) or else Left'Length (2) /= Right'Length (2) then
     raise Constraint_Error;
  end if;
  for I in Left'Range (1) loop
     for J in Left'Range (2) loop
        Sum := Sum + (Left (I, J) - Right (I + Offs_I, J + Offs_J));
     end loop;
  end loop;
  return Float (Sum) / (3.0 * Float (Left'Length (1) * Left'Length (2)));

end Diff; </lang> Example of use: <lang ada>

  F1, F2 : File_Type;

begin

  Open (F1, In_File, "city.ppm");
  Open (F2, In_File, "city_emboss.ppm");
  Ada.Text_IO.Put_Line ("Diff" & Float'Image (Diff (Get_PPM (F1), Get_PPM (F2))));
  Close (F1);
  Close (F2);

</lang>

C

The read_image function is from here.

<lang c>#include <stdio.h>

  1. include <stdlib.h>
  2. include <math.h>

/* #include "imglib.h" */

  1. define RED_C 0
  2. define GREEN_C 1
  3. define BLUE_C 2
  4. define GET_PIXEL(IMG, X, Y) ((IMG)->buf[ (Y) * (IMG)->width + (X) ])

int main(int argc, char **argv) {

  image im1, im2;
  double totalDiff = 0.0;
  unsigned int x, y;
  
  if ( argc < 3 )
  {
     fprintf(stderr, "usage:\n%s FILE1 FILE2\n", argv[0]);
     exit(1);
  }
  im1 = read_image(argv[1]);
  if ( im1 == NULL ) exit(1);
  im2 = read_image(argv[2]);
  if ( im2 == NULL ) { free_img(im1); exit(1); }
  if ( (im1->width != im2->width) || (im1->height != im2->height) )
  {
     fprintf(stderr, "width/height of the images must match!\n");
  } else {
  /* BODY: the "real" part! */
     for(x=0; x < im1->width; x++)
     {
        for(y=0; y < im1->width; y++)
        {
          totalDiff += fabs( GET_PIXEL(im1, x, y)[RED_C] - GET_PIXEL(im2, x, y)[RED_C] ) / 255.0;
          totalDiff += fabs( GET_PIXEL(im1, x, y)[GREEN_C] - GET_PIXEL(im2, x, y)[GREEN_C] ) / 255.0;
          totalDiff += fabs( GET_PIXEL(im1, x, y)[BLUE_C] - GET_PIXEL(im2, x, y)[BLUE_C] ) / 255.0;
        }
     }
     printf("%lf\n", 100.0 * totalDiff / (double)(im1->width * im1->height * 3) );
  /* BODY ends */
  }
  free_img(im1);
  free_img(im2);

}</lang>

The output on Lenna is:

1.625587

Forth

: pixel-diff ( pixel1 pixel2 -- n )
  over 255 and over 255 and - abs >r 8 rshift swap 8 rshift
  over 255 and over 255 and - abs >r 8 rshift swap 8 rshift
                            - abs r> + r> + ;
: bdiff ( bmp1 bmp2 -- fdiff )
  2dup bdim rot bdim d<> abort" images not comparable"
  0e               ( F: total diff   )
  dup bdim * >r    ( R: total pixels )
  bdata swap bdata
  r@ 0 do
    over @ over @ pixel-diff 0 d>f f+
    cell+ swap cell+
  loop 2drop
  r> 3 * 255 * 0 d>f f/ ;
: .bdiff ( bmp1 bmp2 -- )
  cr bdiff 100e f* f. ." percent different" ;

Fortran

<lang fortran>program ImageDifference

 use RCImageBasic
 use RCImageIO
 implicit none
 integer, parameter :: input1_u = 20, &
                       input2_u = 21
 type(rgbimage) :: lenna1, lenna2
 real           :: totaldiff


 open(input1_u, file="Lenna100.ppm", action="read")
 open(input2_u, file="Lenna50.ppm", action="read")
 call read_ppm(input1_u, lenna1)
 call read_ppm(input2_u, lenna2)
 close(input1_u)
 close(input2_u)
 totaldiff = sum(  (abs(lenna1%red - lenna2%red) + &
                    abs(lenna1%green - lenna2%green) + &
                    abs(lenna1%blue - lenna2%blue)) / 255.0 )


 print *, 100.0 * totaldiff / (lenna1%width * lenna1%height * 3.0)
 call free_img(lenna1)
 call free_img(lenna2)

end program ImageDifference</lang>

This gives 1.6555154.

MAXScript

<lang maxscript>fn diffImages = ( local img1 = selectBitmap caption:"Select Image 1" local img2 = selectBitmap caption:"Select Image 2" local totalDiff = 0 for i in 0 to (img1.height-1) do ( local img1Row = getPixels img1 [0, i] img1.width local img2Row = getPixels img2 [0, i] img2.width

for j in 1 to img1.width do ( totalDiff += (abs (img1Row[j].r - img2Row[j].r)) / 255.0 totalDiff += (abs (img1Row[j].g - img2Row[j].g)) / 255.0 totalDiff += (abs (img1Row[j].b - img2Row[j].b)) / 255.0 ) ) format "Diff: %\%\n" (totalDiff / ((img1.width * img1.height * 3) as float) * 100) )</lang>

OCaml

<lang ocaml>#! /usr/bin/env ocaml

  1. directory "+glMLite/"
  2. load "jpeg_loader.cma"
  3. load "bigarray.cma"

open Jpeg_loader

let () =

 let img1, width1, height1, col_comp1, color_space1 = load_img (Filename Sys.argv.(1))
 and img2, width2, height2, col_comp2, color_space2 = load_img (Filename Sys.argv.(2)) in
 assert(width1 = width2);
 assert(height1 = height2);
 assert(col_comp1 = col_comp2);  (* number of color components *)
 assert(color_space1 = color_space2);
 let img1 = Bigarray.array3_of_genarray img1
 and img2 = Bigarray.array3_of_genarray img2 in
 let sum = ref 0.0
 and num = ref 0 in
 for x=0 to pred width1 do
   for y=0 to pred height1 do
     for c=0 to pred col_comp1 do
       let v1 = float img1.{x,y,c}
       and v2 = float img2.{x,y,c} in
       let diff = (abs_float (v1 -. v2)) /. 255. in
       sum := diff +. !sum;
       incr num;
     done;
   done;
 done;
 let diff_percent = !sum /. float !num in
 Printf.printf " diff: %f percent\n" diff_percent;
</lang>

Python

<lang python>from itertools import izip import Image

i1 = Image.open("image1.jpg") i2 = Image.open("image2.jpg") assert i1.mode == i2.mode, "Different kinds of images." assert i1.size == i2.size, "Different sizes."

pairs = izip(i1.getdata(), i2.getdata()) if len(i1.getbands()) == 1:

   dif = sum(abs(p1-p2) for p1,p2 in pairs)

else:

   dif = sum(abs(c1-c2) for p1,p2 in pairs for c1,c2 in zip(p1,p2))

ncomponents = i1.size[0] * i1.size[1] * 3 print "Difference (percentage):", (dif / 255.0 * 100) / ncomponents</lang>

Vedit macro language

This implementation compares two BMP images.

<lang vedit> Chdir("|(USER_MACRO)\Rosetta\data") File_Open("Lenna50.bmp", BROWSE)

  1. 10 = Buf_Num // #10 = buffer for 1st image

File_Open("Lenna100.bmp", BROWSE)

  1. 20 = Buf_Num // #20 = buffer for 2nd image

Goto_Pos(10) // offset to pixel data Goto_Pos(Cur_Char + Cur_Char(1)*256) Buf_Switch(#10) Goto_Pos(10) Goto_Pos(Cur_Char + Cur_Char(1)*256)

  1. 15 = 0 // #15 = difference
  2. 16 = 0 // #16 = total number of samples

While(!At_EOF) {

   #11 = Cur_Char; Char
   Buf_Switch(#20)
   #21 = Cur_Char; Char
   #15 += abs(#11-#21)
   #16++
   Buf_Switch(#10)

}

  1. 19 = #15 / (#16*256/100000)

M("Sum of diff: ") NT(#15) M("Total bytes: ") NT(#16) M("Difference: ") NT(#19/1000,LEFT+NOCR) M(".") NT(#19%1000,LEFT+NOCR) M("%\n")

Buf_Switch(#10) Buf_Quit(OK) Buf_Switch(#20) Buf_Quit(OK) </lang>

Output, when comparing the Lenna images that were converted to BMP:

Sum of diff: 3259967
Total bytes: 786432
Difference:  1.619%