Percentage difference between images: Difference between revisions
(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; |
||
</ |
</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 "-"; |
||
</ |
</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 "-"; |
||
</ |
</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; |
||
</ |
</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); |
||
</ |
</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); |
||
}</ |
}</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; |
||
;;</ |
;;</lang> |
Revision as of 15:44, 3 February 2009
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>
- include <stdlib.h>
- include <math.h>
/* #include "imglib.h" */
- define RED_C 0
- define GREEN_C 1
- define BLUE_C 2
- 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
- directory "+glMLite/"
- load "jpeg_loader.cma"
- 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>