Percentage difference between images: Difference between revisions

From Rosetta Code
Content added Content deleted
(Ada solution added)
No edit summary
Line 11: Line 11:


=={{header|Ada}}==
=={{header|Ada}}==
<ada>
<lang ada>
type Count is mod 2**64;
type Count is mod 2**64;
</ada>
</lang>
[http://en.wikipedia.org/wiki/Distance 1-norm distance] in the luminance space:
[http://en.wikipedia.org/wiki/Distance 1-norm distance] in the luminance space:
<ada>
<lang ada>
function "-" (Left, Right : Luminance) return Count is
function "-" (Left, Right : Luminance) return Count is
begin
begin
Line 24: Line 24:
end if;
end if;
end "-";
end "-";
</ada>
</lang>
1-norm distance in the color space multiplied to 3:
1-norm distance in the color space multiplied to 3:
<ada>
<lang ada>
function "-" (Left, Right : Pixel) return Count is
function "-" (Left, Right : Pixel) return Count is
begin
begin
return Left.R - Right.R + Left.G - Left.G + Left.B - Right.B;
return Left.R - Right.R + Left.G - Left.G + Left.B - Right.B;
end "-";
end "-";
</ada>
</lang>
Mean of 1-norm distances. Constraint_Error is propagated when images have different size.
Mean of 1-norm distances. Constraint_Error is propagated when images have different size.
<ada>
<lang ada>
function Diff (Left, Right : Image) return Float is
function Diff (Left, Right : Image) return Float is
Offs_I : constant Integer := Right'First (1) - Left'First (1);
Offs_I : constant Integer := Right'First (1) - Left'First (1);
Line 49: Line 49:
return Float (Sum) / (3.0 * Float (Left'Length (1) * Left'Length (2)));
return Float (Sum) / (3.0 * Float (Left'Length (1) * Left'Length (2)));
end Diff;
end Diff;
</ada>
</lang>
Example of use:
Example of use:
<ada>
<lang ada>
F1, F2 : File_Type;
F1, F2 : File_Type;
begin
begin
Line 59: Line 59:
Close (F1);
Close (F1);
Close (F2);
Close (F2);
</ada>
</lang>
=={{header|C}}==
=={{header|C}}==


The <tt>read_image</tt> function is from [[Read image file through a pipe|here]].
The <tt>read_image</tt> function is from [[Read image file through a pipe|here]].


<c>#include <stdio.h>
<lang c>#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <math.h>
#include <math.h>
Line 108: Line 108:
free_img(im1);
free_img(im1);
free_img(im2);
free_img(im2);
}</c>
}</lang>


The output on Lenna is:
The output on Lenna is:
Line 160: Line 160:
=={{header|OCaml}}==
=={{header|OCaml}}==


<ocaml>#! /usr/bin/env ocaml
<lang ocaml>#! /usr/bin/env ocaml
#directory "+glMLite/"
#directory "+glMLite/"
#load "jpeg_loader.cma"
#load "jpeg_loader.cma"
Line 195: Line 195:
let diff_percent = !sum /. float !num in
let diff_percent = !sum /. float !num in
Printf.printf " diff: %f percent\n" diff_percent;
Printf.printf " diff: %f percent\n" diff_percent;
;;</ocaml>
;;</lang>

Revision as of 15:44, 3 February 2009

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" ;

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)
)

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>