AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Multimedia weniger Scanline aufrufe ... Graustufenbild
Thema durchsuchen
Ansicht
Themen-Optionen

weniger Scanline aufrufe ... Graustufenbild

Ein Thema von bernhard_LA · begonnen am 10. Feb 2024 · letzter Beitrag vom 6. Apr 2024
Antwort Antwort
Michael II

Registriert seit: 1. Dez 2012
Ort: CH BE Eriswil
778 Beiträge
 
Delphi 11 Alexandria
 
#1

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 18. Feb 2024, 11:47
Hallo Thomas
geht beides - du müsstest in deinem Code dann halt noch faktor als UInt64 definieren und das kostet ein wenig und shift kannst du nicht als const definieren (shift ist bereits ein Rückgabewert). Wenn man diese Dinge berücksichtigt, dann läuft dein Code in 4.74ms und der vorgeschlagene in 3.42ms pro Million Aufrufe durch. Da man bei Farbmatrizen den Aufruf meistens nur maximal 3 Mal pro Bitmap benötigt ist es egal. Wenn man die Prozedur häufiger aufruft spielt es eine Rolle.

Auch 3.4x ms schnell und etwas schöner ist

Delphi-Quellcode:
procedure intRGB( const dr, dg, db : double; var ir, ig, ib, shift : UInt64 );
const
  hshift = 54;
  faktor = UInt64(1) shl hshift;
begin
  shift := hshift;
  ir := Round(dr * faktor);
  ig := Round(dg * faktor);
  ib := Round(db * faktor);
end;
Michael Gasser
  Mit Zitat antworten Zitat
Benutzerbild von dummzeuch
dummzeuch

Registriert seit: 11. Aug 2012
Ort: Essen
1.735 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#2

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 31. Mär 2024, 14:44
Ich wollte schon die ganze Zeit nochmal das Timing für die Verarbeitung mit und ohne Assign testen, bin aber erst jetzt dazu gekommen:

Getestet wurden jeweils 1000 Durchläufe mit einer 1000x1000 Pixel Bitmap.

Algorithmus 1:
Code:
  fuer alle Pixel
    Lesen eines Pixels aus der Quell-Bitmap
    Schreiben des Pixels in die Ziel-Bitmap.
    Verarbeiten des Pixels in der Ziel-Bitmap
Algorithmus 2:
Code:
  Assign der Quell-Bitmap auf die Ziel-Bitmap
  fuer alle Pixel
    Verarbeiten eines Pixels mittels Pointer in die Ziel-Bitmap
Algorithmus 3:
Code:
  Move der Quell-Bitmap auf die Ziel-Bitmap
  fuer alle Pixel
    Verarbeiten eines Pixels mittels Pointer in die Ziel-Bitmap
Dabei bestand das Verarbeiten des Pixels aus einem Aufruf einer leeren Methode mit var-Parameter

Mono8:
Algorithmus 1: 3,979 ms/Durchlauf
Algorithmus 2: 3,140 ms/Durchlauf
Algorithmus 3: 3,141 ms/Durchlauf

BGR8:
Algorithmus 1: 3,870 ms/Durchlauf
Algorithmus 2: 4,111 ms/Durchlauf
Algorithmus 3: 5,596 ms/Durchlauf

Wobei die Schwankungen bei mehreren Tests im Bereich von ca. +/-50 ms lagen, d.h.:
* Bei Mono8 war mal Algorithmus 2 schneller, mal Algorithmus 3.
* Bei BGR8 war mal Algorithmus 1 schneller, mal lag er mit Algorithmus 2 gleichauf.

Irritierend finde ich, dass Algorithmus 3 bei BGR deutlich langsamer ist. Vielleicht habe ich da ja noch einen Bug eingebaut.

Verwendeter Code:

Mono8:
Delphi-Quellcode:
procedure TBitmap8_FilterPixels1(_SrcBmp, _DstBmp: TBitmap; _Callback: TPixel8FilterCallback);
const
  BytesPerPixel = 1;
var
  x: Integer;
  y: Integer;
  w: Integer;
  h: Integer;
  SrcLine: PByte;
  DstLine: PByte;
  SrcPixel: PByte;
  DstPixel: PByte;
  BytesPerLine: Integer;
begin
  _SrcBmp.PixelFormat := pf8bit;
  w := _SrcBmp.Width;
  h := _SrcBmp.Height;
  _DstBmp.Assign(nil);
  _DstBmp.PixelFormat := pf8bit;
  _DstBmp.Palette := MakeGrayPalette;
  TBitmap_SetSize(_DstBmp, w, h);

  if (h = 0) or (w = 0) then
    Exit; //==>

  BytesPerLine := ((w * 8 * BytesPerPixel + 31) and not 31) div 8;

  SrcLine := _SrcBmp.ScanLine[0];
  DstLine := _DstBmp.ScanLine[0];
  for y := 0 to h - 1 do begin
    SrcPixel := SrcLine;
    DstPixel := DstLine;
    for x := 0 to w - 1 do begin
      DstPixel^ := SrcPixel^;
      _Callback(x, y, DstPixel^);
      Inc(SrcPixel, BytesPerPixel);
      Inc(DstPixel, BytesPerPixel);
    end;
    Dec(SrcLine, BytesPerLine);
    Dec(DstLine, BytesPerLine);
  end;
end;

procedure TBitmap8_FilterPixels2(_SrcBmp, _DstBmp: TBitmap; _Callback: TPixel8FilterCallback);
const
  BytesPerPixel = 1;
var
  x: Integer;
  y: Integer;
  w: Integer;
  h: Integer;
  DstLine: PByte;
  DstPixel: PByte;
  BytesPerLine: Integer;
begin
  _SrcBmp.PixelFormat := pf8bit;
  w := _SrcBmp.Width;
  h := _SrcBmp.Height;
  _DstBmp.Assign(_SrcBmp);
  if (h = 0) or (w = 0) then
    Exit; //==>

  BytesPerLine := ((w * 8 * BytesPerPixel + 31) and not 31) div 8;

  DstLine := _DstBmp.ScanLine[0];
  for y := 0 to h - 1 do begin
    DstPixel := DstLine;
    for x := 0 to w - 1 do begin
      _Callback(x, y, DstPixel^);
      Inc(DstPixel, BytesPerPixel);
    end;
    Dec(DstLine, BytesPerLine);
  end;
end;

procedure TBitmap8_FilterPixels3(_SrcBmp, _DstBmp: TBitmap; _Callback: TPixel8FilterCallback);
const
  BytesPerPixel = 1;
var
  x: Integer;
  y: Integer;
  w: Integer;
  h: Integer;
  SrcBuffer: PByte;
  DstBuffer: PByte;
  DstLine: PByte;
  DstPixel: PByte;
  BytesPerLine: Integer;
begin
  _SrcBmp.PixelFormat := pf8bit;
  w := _SrcBmp.Width;
  h := _SrcBmp.Height;
  _DstBmp.Assign(nil);
  _DstBmp.PixelFormat := pf8bit;
  _DstBmp.Palette := MakeGrayPalette;
  TBitmap_SetSize(_DstBmp, w, h);

  if (h = 0) or (w = 0) then
    Exit; //==>

  BytesPerLine := ((w * 8 * BytesPerPixel + 31) and not 31) div 8;

  SrcBuffer := _SrcBmp.ScanLine[h - 1];
  DstBuffer := _DstBmp.ScanLine[h - 1];
  Move(SrcBuffer^, DstBuffer^, BytesPerLine * h);

  DstLine := AddToPtr(DstBuffer, BytesPerLine * (h - 1));
  for y := 0 to h - 1 do begin
    DstPixel := DstLine;
    for x := 0 to w - 1 do begin
      _Callback(x, y, DstPixel^);
      Inc(DstPixel, BytesPerPixel);
    end;
    Dec(DstLine, BytesPerLine);
  end;
end;
BGR8:
Delphi-Quellcode:
procedure TBitmap24_FilterPixels1(_SrcBmp, _DstBmp: TBitmap; _Callback: TPixel24FilterCallback);
const
  BytesPerPixel = 3;
var
  x: Integer;
  y: Integer;
  w: Integer;
  h: Integer;
  SrcLine: PByte;
  DstLine: PByte;
  SrcPixel: PByte;
  DstPixel: PByte;
  BytesPerLine: Integer;
begin
  _SrcBmp.PixelFormat := pf24bit;
  w := _SrcBmp.Width;
  h := _SrcBmp.Height;

  _DstBmp.PixelFormat := pf24bit;
  TBitmap_SetSize(_DstBmp, w, h);

  if (h = 0) or (w = 0) then
    Exit; //==>

  BytesPerLine := ((w * 8 * BytesPerPixel + 31) and not 31) div 8;

  SrcLine := _SrcBmp.ScanLine[0];
  DstLine := _DstBmp.ScanLine[0];
  for y := 0 to h - 1 do begin
    SrcPixel := SrcLine;
    DstPixel := DstLine;
    for x := 0 to w - 1 do begin
      PdzRgbTriple(DstPixel)^ := PdzRgbTriple(SrcPixel)^;
      _Callback(x, y, PdzRgbTriple(DstPixel)^);
      Inc(SrcPixel, BytesPerPixel);
      Inc(DstPixel, BytesPerPixel);
    end;
    Dec(SrcLine, BytesPerLine);
    Dec(DstLine, BytesPerLine);
  end;
end;

procedure TBitmap24_FilterPixels2(_SrcBmp, _DstBmp: TBitmap; _Callback: TPixel24FilterCallback);
const
  BytesPerPixel = 3;
var
  x: Integer;
  y: Integer;
  w: Integer;
  h: Integer;
  DstLine: PByte;
  DstPixel: PByte;
  BytesPerLine: Integer;
begin
  _SrcBmp.PixelFormat := pf24bit;
  w := _SrcBmp.Width;
  h := _SrcBmp.Height;
  _DstBmp.Assign(_SrcBmp);

  if (h = 0) or (w = 0) then
    Exit; //==>

  BytesPerLine := ((w * 8 * BytesPerPixel + 31) and not 31) div 8;

  DstLine := _DstBmp.ScanLine[0];
  for y := 0 to h - 1 do begin
    DstPixel := DstLine;
    for x := 0 to w - 1 do begin
      _Callback(x, y, PdzRgbTriple(DstPixel)^);
      Inc(DstPixel, BytesPerPixel);
    end;
    Dec(DstLine, BytesPerLine);
  end;
end;

procedure TBitmap24_FilterPixels3(_SrcBmp, _DstBmp: TBitmap; _Callback: TPixel24FilterCallback);
const
  BytesPerPixel = 3;
var
  x: Integer;
  y: Integer;
  w: Integer;
  h: Integer;
  SrcBuffer: PByte;
  DstBuffer: PByte;
  DstLine: PByte;
  DstPixel: PByte;
  BytesPerLine: Integer;
begin
  _SrcBmp.PixelFormat := pf24bit;
  w := _SrcBmp.Width;
  h := _SrcBmp.Height;
  _DstBmp.Assign(nil);
  _DstBmp.PixelFormat := pf24bit;
  TBitmap_SetSize(_DstBmp, w, h);

  if (h = 0) or (w = 0) then
    Exit; //==>

  BytesPerLine := ((w * 8 * BytesPerPixel + 31) and not 31) div 8;

  SrcBuffer := _SrcBmp.ScanLine[h - 1];
  DstBuffer := _DstBmp.ScanLine[h - 1];
  Move(SrcBuffer^, DstBuffer^, BytesPerLine * h);

  DstLine := AddToPtr(DstBuffer, BytesPerLine * (h - 1));
  for y := 0 to h - 1 do begin
    DstPixel := DstLine;
    for x := 0 to w - 1 do begin
      _Callback(x, y, PdzRgbTriple(DstPixel)^);
      Inc(DstPixel, BytesPerPixel);
    end;
    Dec(DstLine, BytesPerLine);
  end;
end;
Compiliert wurde mit Delphi 10.2, alle Optimierung an, Assertions aus.
Mein Rechner ist allerdings nicht gerade der schnellste: Intel Core I5-4590T mit 2 GHz
(ein Fujitsu Esprimo Q920 Mini PC)
Thomas Mueller
  Mit Zitat antworten Zitat
Michael II

Registriert seit: 1. Dez 2012
Ort: CH BE Eriswil
778 Beiträge
 
Delphi 11 Alexandria
 
#3

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 31. Mär 2024, 21:04
Hallo Thomas
ich weiss nicht was du in deiner _Callback tust - wahrscheinlich das in #1 ursprünglich verlangte (?).
Hast du deine Varianten 1,2,3 auf deinem Rechner auch "gegen" den Code aus #20 laufen lassen?
Gruss Michael
Michael Gasser
  Mit Zitat antworten Zitat
Amateurprofi

Registriert seit: 17. Nov 2005
Ort: Hamburg
1.111 Beiträge
 
Delphi XE2 Professional
 
#4

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 1. Apr 2024, 09:03
Ich mache das immer so:
Ich in #13, #20, #25 auch .
Hallo Michael,
sorry, ich hab nicht den ganzen Thread gelesen, nur #30, ansonsten hätte ich mir meinen Kommentar gespart.
Gruß, Klaus
Die Titanic wurde von Profis gebaut,
die Arche Noah von einem Amateur.
... Und dieser Beitrag vom Amateurprofi....
  Mit Zitat antworten Zitat
Benutzerbild von dummzeuch
dummzeuch

Registriert seit: 11. Aug 2012
Ort: Essen
1.735 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#5

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 1. Apr 2024, 09:59
ich weiss nicht was du in deiner _Callback tust - wahrscheinlich das in #1 ursprünglich verlangte (?).
Wie ich schrieb: Nichts.

Dabei bestand das Verarbeiten des Pixels aus einem Aufruf einer leeren Methode mit var-Parameter
Hast du deine Varianten 1,2,3 auf deinem Rechner auch "gegen" den Code aus #20 laufen lassen?
Nein. Ich wollte lediglich diese 3 bzw. 6 Varianten timen. Allerdings ist Algorithmus 3 mit dem Move ziemlich genau das, was auch in #20 steht.
Thomas Mueller

Geändert von dummzeuch ( 1. Apr 2024 um 10:11 Uhr)
  Mit Zitat antworten Zitat
Amateurprofi

Registriert seit: 17. Nov 2005
Ort: Hamburg
1.111 Beiträge
 
Delphi XE2 Professional
 
#6

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 1. Apr 2024, 00:32
Zitat:
Delphi-Quellcode:
 BytesPerLine := ((w * 8 * BytesPerPixel + 31) and not 31) div 8;

  DstLine := _DstBmp.ScanLine[0];
  for y := 0 to h - 1 do begin
    DstPixel := DstLine;
    for x := 0 to w - 1 do begin
      _Callback(x, y, PdzRgbTriple(DstPixel)^);
      Inc(DstPixel, BytesPerPixel);
    end;
    Dec(DstLine, BytesPerLine);
  end;
Hallo Thomas,
mir fiel auf, dass Du die BytesPerLine selbst errechnest.
Ich mache das immer so:
Delphi-Quellcode:
DstLine := _DstBmp.ScanLine[0];
if h>1 then BytesPerLine:=NativeInt(_DstBmp.ScanLine[1]) - NativeInt(DstLine)
   else BytesPerLine:=0;
Und Inc(NativeInt(DstLine), BytesPerLine); Das erspart Überraschungen wenn die Zeilen in der Bitmap dann doch mal umgekehrt gespeichert sind.
Gruß, Klaus
Die Titanic wurde von Profis gebaut,
die Arche Noah von einem Amateur.
... Und dieser Beitrag vom Amateurprofi....
  Mit Zitat antworten Zitat
Michael II

Registriert seit: 1. Dez 2012
Ort: CH BE Eriswil
778 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 1. Apr 2024, 01:11
Ich mache das immer so:
Ich in #13, #20, #25 auch .
Michael Gasser
  Mit Zitat antworten Zitat
Benutzerbild von dummzeuch
dummzeuch

Registriert seit: 11. Aug 2012
Ort: Essen
1.735 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#8

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 1. Apr 2024, 10:11
mir fiel auf, dass Du die BytesPerLine selbst errechnest.
Ich mache das immer so:
Delphi-Quellcode:
DstLine := _DstBmp.ScanLine[0];
if h>1 then BytesPerLine:=NativeInt(_DstBmp.ScanLine[1]) - NativeInt(DstLine)
   else BytesPerLine:=0;
Und Inc(NativeInt(DstLine), BytesPerLine); Das erspart Überraschungen wenn die Zeilen in der Bitmap dann doch mal umgekehrt gespeichert sind.
Ja, in meinem ursprünglichen Code (im ersten Beitrag verlinkt) war das auch noch so, aber das war ein weiterer Aufruf von ScanLine und bei mir geht es um die möglichst effiziente Verarbeitung von 1000en von Bildern.

Ich habe bisher noch keine Bitmap gesehen, die nicht umgedreht gespeichert war (wobei die alle von unseren internen Programmen erzeugt werden, ist also kein Wunder). Und wenn das irgendwann passiert, merkt man das ziemlich schnell, weil es eine Access Violation gibt.
Thomas Mueller
  Mit Zitat antworten Zitat
Michael II

Registriert seit: 1. Dez 2012
Ort: CH BE Eriswil
778 Beiträge
 
Delphi 11 Alexandria
 
#9

AW: weniger Scanline aufrufe ... Graustufenbild

  Alt 6. Apr 2024, 10:50
Wenn es dir um Effizienz geht (deine Scanline "Optimierung"), dann solltest du bei zeitkritischen Anwendungen auf die Callback Funktion verzichten. Damit sparst du viel mehr Nanosekunden .
Und wenn du das nicht willst: In vielen Anwendungsfällen kannst du sicher auf die Weitergabe von x,y an deine Callbackfunktion verzichten.
Ich habe auch rasch gemessen: 1220x753 Bild, 1000 Durchläufe:
0: Ist meine Prozedur von weiter oben, 1,2,3 sind deine (mit Callbackfunkton ohne Parameter x,y).
Du hast geschrieben deine 3 sei ähnlich 0; punkto Speed sind sie es nicht. Der Aufruf der Callbackfunktion bremst natürlich in mehrfacher Hinsicht (Prozessorcache, mehr Code).

64Bit App
i7-13620H @ 2.40GHz Win11 Home
0 : 1.184 sec
1 : 4.827
2 : 3.646
3 : 4.074

i7-11800H @ 2.30GHz Win11 Pro
0 : 1.388
1 : 5.765
2 : 4.309
3 : 4.924

AMD EPYC-Rome, 2350 Mhz WinServer 2022
0 : 2.461
1 : 6.577
2 : 5.283
3 : 6.988

Intel Xeon Cascadelake, 2394 MHz WinServer 2019
0 : 3,333
1 : 11,51
2 : 8,333
3 : 10,16
Michael Gasser

Geändert von Michael II ( 6. Apr 2024 um 16:48 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:39 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz