0

I am trying to checksum an image, but it takes too long to give a result, tried add values, and Adler-32 but both finishes in a long time (approximately 2 seconds).

Adding values:

Function Checksum_CountryFlag(Img : TPicture):Integer;
var j, k, Checksum : Integer;
begin
Checksum := 0;
For j := 0 to Img.Width do
For k := 0 to Img.Height do
If (((Img.Bitmap.Canvas.Pixels[j,k]) <> 15577344) And ((Img.Bitmap.Canvas.Pixels[j,k]) <> 15311104) And ((Img.Bitmap.Canvas.Pixels[j,k]) <> 3816255) And ((Img.Bitmap.Canvas.Pixels[j,k]) <> 10526623) And ((Img.Bitmap.Canvas.Pixels[j,k]) <> 12303034) And ((Img.Bitmap.Canvas.Pixels[j,k]) <> 9013641)) Then
begin
Checksum := Checksum + Img.Bitmap.Canvas.Pixels[j,k];
end;
Result := Abs(Checksum);
end;

Adler-32:

Function Checksum_Adler32(Img : TPicture):Integer;
var i,a,b,j,k : Integer;
begin
a := 1; b := 0;
For j := 0 to Img.Width do
For k := 0 to Img.Height do
If (((Img.Bitmap.Canvas.Pixels[j,k]) <> 15577344) And ((Img.Bitmap.Canvas.Pixels[j,k]) <> 15311104) And ((Img.Bitmap.Canvas.Pixels[j,k]) <> 3816255) And ((Img.Bitmap.Canvas.Pixels[j,k]) <> 10526623) And ((Img.Bitmap.Canvas.Pixels[j,k]) <> 12303034) And ((Img.Bitmap.Canvas.Pixels[j,k]) <> 9013641)) Then
begin
a := a + Img.Bitmap.Canvas.Pixels[j,k];
b := b + a;
end;
Result := Abs(a) + Abs(b);
end;

As you see, i am trying to avoid some values (technical reasons). Maybe this what makes it takes too long, i don't know, any ideas for improving this algorithm ?

gabr
  • 26,580
  • 9
  • 75
  • 141
Mahmoud
  • 9,729
  • 1
  • 36
  • 47

4 Answers4

6

I have done some correction to make the first version of your code fast:

Function Checksum_CountryFlag(Img : TPicture):Integer;
var j, k, Checksum : Integer;
  Line: PLongInt;
begin
  Checksum := 0;
  Img.Bitmap.PixelFormat:= pf32bit; // just for case
  For k := 0 to Img.Height - 1 do begin      //  !! Height first, -1
    Line:= Img.Bitmap.ScanLine[k];
    For j := 0 to Img.Width - 1 do begin  // !! -1
      If ((Line^ <> 15577344) And (Line^ <> 15311104) And (Line^ <> 3816255)
        And (Line^ <> 10526623) And (Line^ <> 12303034) And (Line^ <> 9013641)) Then
        begin
          Checksum := Checksum + Line^;
        end;
      Inc(Line);
    end;
  end;
  Result := Abs(Checksum);
end;

Updated: It gives different result because I fixed a bug in your code (Height-1), (Width-1). I also changed the loop order (external loop by Height) - it is nessessary to use ScanLine. You must do the same corrections in your code before comparing.

kludg
  • 27,213
  • 5
  • 67
  • 118
2

Unroling parts your loop gives much more performance (lig putting img.bitmap.canvas into a variable outside the loops).
Getting the pixel[j,k] to a local variable before the if also helps alot, and it improves readability of the sourcecode.

But the biggest impact might be using the "Scanline" property and getting all pixels in a line to a local vaiable helps even more (you have to switch the height and the width for loops).

BennyBechDk
  • 934
  • 7
  • 13
2

Hard to be sure without a profiler, but looking at that I'd guess that you're losing a lot of time looking up the reader values for Img.Bitmap.Canvas.Pixels[j,k] repeatedly.

First thing I'd do is save that to a value, like so:

pixel := Img.Bitmap.Canvas.Pixels[j,k];
If ((pixel <> 15577344) And (pixel <> 15311104) And (pixel <> 3816255) And (pixel <> 10526623) And (pixel <> 12303034) And (pixel <> 9013641)) Then

That should speed things up significantly.

Mason Wheeler
  • 82,511
  • 50
  • 270
  • 477
2

Serg' code with corrected (and faster) Pixel value:

Function Checksum_CountryFlag(Img : TPicture):Integer;
var j, k, Checksum : Integer;
  Line: PIntegerArray;
  Pixel : integer;
begin
  Checksum := 0;
  Img.Bitmap.PixelFormat:= pf32bit; // just for case
  For k := 0 to Img.Height - 1 do begin      //  !! Height first, -1
    Line:= Img.Bitmap.ScanLine[k];
    For j := 0 to Img.Width - 1 do begin  // !! -1
      Pixel := Line^[j];
      If ((Pixel <> 15577344) And (Pixel <> 15311104) And (Pixel <> 3816255)
        And (Pixel <> 10526623) And (Pixel <> 12303034) And (Pixel <> 9013641)) Then
        begin
          Checksum := Checksum + Pixel;
        end;
      Inc(Line);
    end;
  end;
  Result := Abs(Checksum);
end;
BennyBechDk
  • 934
  • 7
  • 13