Percentage difference between images

From Rosetta Code
Revision as of 02:56, 31 October 2010 by rosettacode>CRGreathouse ({{omit from|PARI/GP}})
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 (use the full-size version of each):

50% quality JPEG 100% quality JPEG

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>

AutoHotkey

Works with: AutoHotkey_L

uses gdip.ahk <lang AutoHotkey>startup() dibSection := getPixels("lenna100.jpg") dibSection2 := getPixels("lenna50.jpg") ; ("File-Lenna100.jpg") pixels := dibSection.pBits pixels2 := dibSection2.pBits z := 0 loop % dibSection.width * dibSection.height * 4 { x := numget(pixels - 1, A_Index, "uchar") y := numget(pixels2 - 1, A_Index, "uchar") z += abs(y - x) } msgbox % z / (dibSection.width * dibSection.height * 3 * 255 / 100 ) ; 1.626 return

CreateDIBSection2(hDC, nW, nH, bpp = 32, ByRef pBits = "") { dib := object() NumPut(VarSetCapacity(bi, 40, 0), bi) NumPut(nW, bi, 4) NumPut(nH, bi, 8) NumPut(bpp, NumPut(1, bi, 12, "UShort"), 0, "Ushort") NumPut(0, bi,16) hbm := DllCall("gdi32\CreateDIBSection", "Uint", hDC, "Uint", &bi, "Uint", 0, "UintP", pBits, "Uint", 0, "Uint", 0)

dib.hbm := hbm dib.pBits := pBits dib.width := nW dib.height := nH dib.bpp := bpp dib.header := header Return dib }


startup() { global disposables disposables := object() disposables.pBitmaps := object() disposables.hBitmaps := object()

If !(disposables.pToken := Gdip_Startup()) { MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system ExitApp }

 OnExit, gdipExit

}


gdipExit: loop % disposables.hBitmaps._maxindex() DllCall("DeleteObject", "Uint", disposables.hBitmaps[A_Index]) Gdip_Shutdown(disposables.pToken) ExitApp

getPixels(imageFile) { global disposables ; hBitmap will be disposed later pBitmapFile1 := Gdip_CreateBitmapFromFile(imageFile) hbmi := Gdip_CreateHBITMAPFromBitmap(pBitmapFile1) width := Gdip_GetImageWidth(pBitmapFile1) height := Gdip_GetImageHeight(pBitmapFile1)

mDCo := DllCall("CreateCompatibleDC", "Uint", 0) mDCi := DllCall("CreateCompatibleDC", "Uint", 0) dibSection := CreateDIBSection2(mDCo, width, height) hBMo := dibSection.hbm

oBM := DllCall("SelectObject", "Uint", mDCo, "Uint", hBMo) iBM := DllCall("SelectObject", "Uint", mDCi, "Uint", hbmi)

DllCall("BitBlt", "Uint", mDCo, "int", 0, "int", 0, "int", width, "int", height, "Uint", mDCi, "int", 0, "int", 0, "Uint", 0x40000000 | 0x00CC0020)

DllCall("SelectObject", "Uint", mDCo, "Uint", oBM) DllCall("ReleaseDC", "Uint", 0, "Uint", mDCi) DllCall("ReleaseDC", "Uint", 0, "Uint", mDCo) Gdip_DisposeImage(pBitmapFile1) DllCall("DeleteObject", "Uint", hBMi) disposables.hBitmaps._insert(hBMo) return dibSection }

  1. Include Gdip.ahk  ; Thanks to tic (Tariq Porter) for his GDI+ Library

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

C++

based upon C version, using Qt 4.4 <lang C++>#include <QImage>

  1. include <cstdlib>
  2. include <QColor>
  3. include <iostream>

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

  if ( argc != 3 ) {
     std::cout << "Call this with imagecompare <file of image 1>" 

<< " <file of image 2>\n" ;

     return 1 ;
  }
  QImage firstImage ( argv[ 1 ] ) ;
  QImage secondImage ( argv[ 2 ] ) ;
  double totaldiff = 0.0 ; //holds the number of different pixels
  int h = firstImage.height( ) ;
  int w = firstImage.width( ) ;
  int hsecond = secondImage.height( ) ;
  int wsecond = secondImage.width( ) ;
  if ( w != wsecond || h != hsecond ) {
     std::cerr << "Error, pictures must have identical dimensions!\n" ;
     return 2 ;
  } 
  for ( int y = 0 ; y < h ; y++ ) {
     uint *firstLine = ( uint* )firstImage.scanLine( y ) ;
     uint *secondLine = ( uint* )secondImage.scanLine( y ) ;
     for ( int x = 0 ; x < w ; x++ ) {

uint pixelFirst = firstLine[ x ] ; int rFirst = qRed( pixelFirst ) ; int gFirst = qGreen( pixelFirst ) ; int bFirst = qBlue( pixelFirst ) ; uint pixelSecond = secondLine[ x ] ; int rSecond = qRed( pixelSecond ) ; int gSecond = qGreen( pixelSecond ) ; int bSecond = qBlue( pixelSecond ) ; totaldiff += abs( rFirst - rSecond ) / 255.0 ; totaldiff += abs( gFirst - gSecond ) / 255.0 ; totaldiff += abs( bFirst -bSecond ) / 255.0 ;

     }
  }
  std::cout << "The difference of the two pictures is " <<
     (totaldiff * 100)  / (w * h * 3)  << " % !\n" ;
  return 0 ;

}</lang>

output on pictures given;

The difference of the two pictures is 1.62559 % !

Common Lisp

This is based upon the C version. Strangely enough, the percentage is 1.77% which is off by about a tenth of a percent.

<lang lisp>(require 'cl-jpeg)

the JPEG library uses simple-vectors to store data. this is insane!

(defun compare-images (file1 file2)

 (declare (optimize (speed 3) (safety 0) (debug 0)))
 (multiple-value-bind (image1 height width) (jpeg:decode-image file1)
   (let ((image2 (jpeg:decode-image file2))) 
     (loop for i of-type (unsigned-byte 8) across (the simple-vector image1)
           for j of-type (unsigned-byte 8) across (the simple-vector image2)
           sum (the fixnum (abs (- i j))) into difference of-type fixnum
           finally (return (coerce (/ difference width height #.(* 3 255))
                                   'double-float))))))
 CL-USER> (* 100 (compare-images "Lenna50.jpg" "Lenna100.jpg"))
 1.774856467652165d0</lang>

E

By dividing only at the end, we work with integers only as the sum and avoid floating-point error from adding small numbers (per-pixel difference) to large ones (sum of differences).

<lang e>def imageDifference(a, b) {

 require(a.width() == b.width())
 require(a.height() == b.height())
 def X := 0..!(a.width())
 def Y := 0..!(a.height())
 
 var sumByteDiff := 0
 for y in Y {
   for x in X {
     def ca := a[x, y]
     def cb := b[x, y]
     sumByteDiff += (ca.rb() - cb.rb()).abs() \
                  + (ca.gb() - cb.gb()).abs() \
                  + (ca.bb() - cb.bb()).abs()
   }
   println(y)
 }
 return sumByteDiff / (255 * 3 * a.width() * a.height())

}

def imageDifferenceTask() {

 println("Read 1...")
 def a := readPPM(<import:java.io.makeFileInputStream>(<file:Lenna50.ppm>))
 println("Read 2...")
 def b := readPPM(<import:java.io.makeFileInputStream>(<file:Lenna100.ppm>))
 println("Compare...")
 def d := imageDifference(a, b)
 println(`${d * 100}% different.`)

}</lang>

The result on the provided images is 1.6255930981604882%.

Forth

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

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.

Haskell

This implementation takes PPMs as input. It uses modules defined in Basic bitmap storage and Write ppm file.

<lang haskell>import Bitmap import Bitmap.Netpbm import Bitmap.RGB

import Control.Monad import Control.Monad.ST import System.Environment (getArgs)

main = do

   [path1, path2] <- getArgs
   image1 <- readNetpbm path1
   image2 <- readNetpbm path2
   diff <- stToIO $ imageDiff image1 image2
   putStrLn $ "Difference: " ++ show (100 * diff) ++ "%"

imageDiff :: Image s RGB -> Image s RGB -> ST s Double imageDiff image1 image2 = do

     i1 <- getPixels image1
     i2 <- getPixels image2
     unless (length i1 == length i2) $
         fail "imageDiff: Images are of different sizes"
     return $
         toEnum (sum $ zipWith minus i1 i2) /
         toEnum (3 * 255 * length i1)
 where (RGB (r1, g1, b1)) `minus` (RGB (r2, g2, b2)) =
           abs (r1 - r2) + abs (g1 - g2) + abs (b1 - b2)</lang>


Mathematica

<lang Mathematica>img50 = ImageData@Import[NotebookDirectory[] <> "Lenna50.jpg"]; img100 = ImageData@Import[NotebookDirectory[] <> "Lenna100.jpg"]; diff = img50 - img100; Print["Total Difference between both Lenas = ",

Total@Abs@Flatten@diff/Times @@ Dimensions@img50*100, "%"]</lang>

Output

Total Difference between both Lenas = 1.62559%


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>

J

<lang j> require 'media/image3'

  'Lenna50.jpg' (+/@,@:|@:- % 2.55 * */@$@])&read_image 'Lenna100.jpg'

1.62559</lang>

OCaml

Library: glMLite

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

PicoLisp

<lang PicoLisp>(call "convert" "Lenna50.jpg" (tmp "Lenna50.ppm")) (call "convert" "Lenna100.jpg" (tmp "Lenna100.ppm"))

(let (Total 0 Diff 0)

  (in (tmp "Lenna50.ppm")
     (in (tmp "Lenna100.ppm")
        (while (rd 1)
           (inc 'Diff
              (*/
                 (abs (- @ (in -1 (rd 1))))
                 1000000
                 255 ) )
           (inc 'Total) ) ) )
  (prinl "Difference is " (format (*/ Diff Total) 4) " percent") )</lang>

Output:

Difference is 1.6256 percent

PureBasic

This program downloads both jpg files, decodes them & saves them in 2D-arrays for simple comparison which part is comparable with the other languages. <lang PureBasic>#URL1="http://rosettacode.org/mw/images/3/3c/Lenna50.jpg"

  1. URL2="http://rosettacode.org/mw/images/b/b6/Lenna100.jpg"

Procedure.s GetTempFileName(basename$="",Extension$=".tmp")

 Protected file$, i
 Repeat: file$=GetTemporaryDirectory()+basename$+"_"+Str(i)+Extension$: i+1
 Until FileSize(file$) = -1 ; E.g. File not found
 ProcedureReturn file$

EndProcedure

Procedure ImageToMatrix(Image,Array P(2))

 Protected Width=ImageWidth(0)-1, Height=ImageHeight(0)-1, x, y
 ; Scaling down Width & Height by -1 to compensate for using 0-based arrays
 Dim P(Width,Height)
 StartDrawing(ImageOutput(Image))
 For x=0 To Width
   For y=0 To Height
     P(x,y)=Point(x,y)
   Next y
 Next x
 StopDrawing()

EndProcedure

Define File1$, File2$, totalDiff, x, y, w, h

Load the pictures from RoettaCode

InitNetwork() File1$=GetTempFileName("",".jpg"): ReceiveHTTPFile(#URL1,File1$) File2$=GetTempFileName("",".jpg"): ReceiveHTTPFile(#URL2,File2$)

Decode the images & clean up temporary files

UseJPEGImageDecoder() LoadImage(0,File1$):LoadImage(1,File2$) DeleteFile(File1$): DeleteFile(File2$)

Make two 2D arrays to hold the data

Dim Pic1(0,0): Dim Pic2(0,0)

Load the image data into the matrixes

ImageToMatrix(0,Pic1()): ImageToMatrix(1,Pic2())

Compare the data

w=ArraySize(pic1()): h=ArraySize(pic1(),2) For x=0 To w

 For y=0 To h
   totalDiff+ Abs(  Red(Pic1(x,y)) -   Red(Pic2(x,y)))
   totalDiff+ Abs(Green(Pic1(x,y)) - Green(Pic2(x,y)))
   totalDiff+ Abs( Blue(Pic1(x,y)) -  Blue(Pic2(x,y)))
 Next y

Next x

MessageRequester("Result","Diff= "+StrD(100*totalDiff/(255*w*h*3),3)+" %")</lang>

Python

You must install the Python Imaging Library to use this example.

Works with: python version 2.x

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

   # for gray-scale jpegs
   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>

REBOL

<lang REBOL>REBOL [ Title: "Percent Image Difference" Author: oofoe Date: 2009-12-31 URL: http://rosettacode.org/wiki/Percentage_of_difference_between_2_images ]

Load from local storage. Un/comment as preferred.
a
load-image %lenna50.jpg
b
load-image %lenna100.jpg
Download from rosettacode.org.

a: load-image http://rosettacode.org/mw/images/3/3c/Lenna50.jpg b: load-image http://rosettacode.org/mw/images/b/b6/Lenna100.jpg

if a/size <> b/size [print "Image dimensions must match." halt]

Compute difference. REBOL has built-in image processing as part of
its GUI package that I can take advantage of here

diff: to-image layout/tight [image a effect [difference b]]

Calculate deviation. I use 'repeat' to rip through the image pixels
(it knows how to deal with images) and sum, then average. Note that
I can treat the image like an array to get number of pixels.

t: 0 repeat p diff [t: t + p/1 + p/2 + p/3] print rejoin ["Difference: " 100 * t / (255 * 3 * length? diff) "%"]

Optional
Since I now have a difference image, I may as well show
it. Use the buttons or keys 'a', 'b' and 'd' to switch between the
various images.

flip: func [ "Change to new image and label." name [word!] "Image to switch to." ][x/text: rejoin ["Image " name] x/image: get name show x]

Because the differences between the images are very small, I enhance
the diff with a high contrast to make the result easier to
see. Comment this out for the "pure" image.

diff: to-image layout/tight [image diff effect [contrast 100]]

view l: layout [ x: image diff across button "a" #"a" [flip 'a] button "b" #"b" [flip 'b] button "difference" #"d" [flip 'diff] ]</lang>

Output:

Difference: 1.62559309816049%

Note that this image has been contrast enhanced to highlight the differences.

Ruby

uses the raster_graphics library <lang ruby>require 'raster_graphics'

class RGBColour

 # the difference between two colours
 def -(a_colour)
   (@red - a_colour.red).abs +
   (@green - a_colour.green).abs +
   (@blue - a_colour.blue).abs
 end

end

class Pixmap

 # the difference between two images
 def -(a_pixmap)
   if @width != a_pixmap.width or @height != a_pixmap.height
     raise ArgumentError, "can't compare images with different sizes"
   end
   sum = 0
   each_pixel {|x,y| sum += self[x,y] - a_pixmap[x,y]}
   Float(sum) / (@width * @height * 255 * 3)
 end

end

lenna50 = Pixmap.open_from_jpeg('Lenna50.jpg') lenna100 = Pixmap.open_from_jpeg('Lenna100.jpg')

puts "difference: %.5f%%" % (100.0 * (lenna50 - lenna100))</lang>

produces:

difference: 1.62559%

Tcl

Library: Tk

This version uses the Img package, but only to provide a convenient JPEG loader; it's utterly unnecessary for the process of actually computing the difference. <lang tcl>package require Tk

proc imageDifference {img1 img2} {

   if {

[image width $img1] != [image width $img2] || [image height $img1] != [image height $img2]

   } then {

return -code error "images are different size"

   }
   set diff 0
   for {set x 0} {$x<[image width $img1]} {incr x} {

for {set y 0} {$y<[image height $img1]} {incr y} { lassign [$img1 get $x $y] r1 g1 b1 lassign [$img2 get $x $y] r2 g2 b2 incr diff [expr {abs($r1-$r2)+abs($g1-$g2)+abs($b1-$b2)}] }

   }
   expr {$diff/double($x*$y*3*255)}

}

  1. Package only used for JPEG loader

package require Img image create photo lenna50 -file lenna50.jpg image create photo lenna100 -file lenna100.jpg puts "difference is [expr {[imageDifference lenna50 lenna100]*100.}]%" exit ;# Need explicit exit here; don't want a GUI</lang> It produces this output:

difference is 1.6255930981604882%

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%