Einzelnen Beitrag anzeigen

schwarzerlotus

Registriert seit: 25. Jul 2011
22 Beiträge
 
#1

schnelle getPixel Funktion

  Alt 16. Aug 2011, 09:47
Hallo zusammen,

ich rechne in meinem Projekt eine ganze Menge über Bitmap Bilder hin und her und hab mir deshalb mal ein Test Programm geschrieben, um eine schnelle Variante zu finden ein Bild zu durchlaufen.
Da ich außerdem bei den Berechnungen teilweise auch mehrere Bilder in einer Schleife durchlaufe hätte ich gerne eine getPixel Funktion auf dem Bitmap die mir möglichst ohne zeitlichen Overhead den Wert an der Position gibt und ich mich nicht immer um Scanline und Inc des Pointers kümmern muss.

Zum Testen der Laufzeit gehe ich einmal über das Bild, rechne alle Pixel einer Farbe zusammen und messe dabei die Zeit.

Bei der ersten Variante mit Pointern und Scanline

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  i,j: INTEGER;
  Row: ^TRGBTriple;
  calc: Int64;
  time1, time2, DiffTime : TDateTime;
begin
  calc := 0;
  time1 := time;
  for j := 0 to Image1.Picture.Bitmap.Height-1 do begin
    row := Image1.Picture.Bitmap.Scanline[j];
    for i := 0 to Image1.Picture.Bitmap.Width-1 do begin
      calc := calc + (getColorPixel(row,Red));
      inc (row);
    end;
  end;
  time2 := time;
  DiffTime := ( time2 - time1 ) *60 *60 *24;
  Edit3.Text := Format ( '%2.5f', [DiffTime] );
  Edit1.Text := IntToStr(calc);
end;
benötigt der Algorithmus 0,017 Sekunden.

Nun hab ich mir eine Klasse beschrieben, die von TBitmap ableitet und eine zusätzliche getPixel Funktion zur Verfügung stellt. Damit hier nicht immer mit scanline die Zeile bestimmt werden muss, erzeuge ich mir in der load Methode ein Array of PByteArray mit allen Zeilenpointern.

Delphi-Quellcode:
unit MyBitmap;

interface

uses
  Graphics, SysUtils, types;

type
  TMyBitmap = class(TBitmap)

  private
    bits: array of PByteArray;
  public
    procedure Init();
    function getPixel(x,y:Integer): Byte;
    procedure LoadFromFile(const Filename: string); override;
  end;

implementation

procedure TMyBitmap.Init();
var
  i: Integer;
begin
  self.PixelFormat := pf32bit;
  SetLength(bits, self.Height);
  for i := 0 to self.Height -1 do
  begin
    bits[i] := self.ScanLine[i];
  end;
  Pbase := self.ScanLine[0];
end;

procedure TMyBitmap.LoadFromFile(const Filename: string);
begin
  inherited;
  init;
end;

function TMyBitmap.getPixel(x,y:Integer): Byte;
begin
  result := bits[y][3*x + 2];
end;

end.
Mit dieser Unit benötige ich für das Durchlaufen des Bildes 0,024 Sekunden also im Schnitt 7 ms länger - klingt nicht viel aber bei der Masse an Bilder macht es schon etwas aus.

Ich hab auch die Graphics32 Unit ausprobiert, die jedoch mit durchschnittlich 0,054 noch mehr Zeit benötigt.

Nun frage ich mich ob es eine Möglichkeit gibt das ganze doch so zu optimieren, dass die Berechnung möglichst schnell abläuft ich aber trotzdem komfortabel mit getPixel auf die Werte zugreifen kann und ich mich nicht um das inkrementieren des Pointers kümmern muss.

Habt ihr eine Idee? Liegt der zeitliche Overhead nur am Funktionsaufruf? Da ich mit Delphi 7 arbeite hab ich leider noch kein inline, um das eventuell zu optimieren.

Grüße Maick
  Mit Zitat antworten Zitat