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