AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Algorithmen, Datenstrukturen und Klassendesign 24-Bit Bitmap um 90 grad drehen - Resourcen-Optimierung

24-Bit Bitmap um 90 grad drehen - Resourcen-Optimierung

Ein Thema von Harry Stahl · begonnen am 18. Okt 2020 · letzter Beitrag vom 23. Okt 2020
Antwort Antwort
Seite 1 von 5  1 23     Letzte » 
Benutzerbild von Harry Stahl
Harry Stahl

Registriert seit: 2. Apr 2004
Ort: Bonn
1.970 Beiträge
 
Delphi 10.4 Sydney
 
#1

24-Bit Bitmap um 90 grad drehen - Resourcen-Optimierung

  Alt 18. Okt 2020, 13:15
Das Thema hatten wir hier zwar schon öfter, aber nicht unter dem Gesichtspunkt, den ich hier ansprechen möchte:

Ich nutze zum drehen von 24 bzw. 32 Bitmaps bislang immer die folgende Routine (aus dem Doberenz-Buch):

Delphi-Quellcode:
procedure Drehe90Rechts (bm: TBitmap);
type
  TMyHelp = array [0..0] of TRGBQuad;
var
  P, Pend : PRGBQuad; x, y, b, h: Integer; RowOut: ^TMyHelp; help: TBitmap;
begin
  Bm.pixelformat := pf32bit;

  help := TBitmap.create;
  help.pixelformat := pf32bit;

  b := bm.height;
  h := bm.width;

  help.SetSize (b, h);
  PEnd := Bm.scanline[bm.height-1];

  for y := 0 to h-1 do begin

    rowout := help.scanline [y];
    p := PEnd;
    inc (p, y);

    for x := 0 to (b-1) do begin
      rowout [x] := p^;
      inc (p, h);
    end;

  end;

  bm.Assign (help);
  help.free;
end;
Ich dachte, OK die nehmen auch für eine 24-Bit-Bitmap eine 32-Bitmap, weil der Compiler die 32-Bits in einem Register direkt kopieren kann. Wenn man sich das in der CPU ansieht, dann stimmt das wohl auch, bei 24 muss er wohl erst 16-Bit und dann noch mal 8 kopieren, dadurch 2 Befehle mehr (siehe anliegenden Screenshot).

Nur: Bei sehr großen Bilder (teste gerade eins im Format 21600 x 10800) braucht er, aber um die 32-Bit-Hilfsbit anzulegen, statt 660 MB bei einer 24 Bit, bei der 32-Bit Bitmap ca. 1 GB zusätzlichen Arbeitsspeicher.

Daher meine Überlegung, statt die Routine mit 32-Bit zu verwenden, bei einer 24-Bit es mit einer 24-Bit routine zu machen.

Delphi-Quellcode:
procedure Drehe90Rechts24 (bm: TBitmap);
type
  TMyHelp = array [0..0] of TRGBTriple;
var
  P, Pend : PRGBTriple; x, y, b, h: Integer; RowOut: ^TMyHelp; help: TBitmap;
begin
  help := TBitmap.create;
  help.pixelformat := pf24bit;

  b := bm.height;
  h := bm.width;

  help.SetSize (b, h);
  PEnd := Bm.scanline[bm.height-1];

  for y := 0 to h-1 do begin

    rowout := help.scanline [y];
    p := PEnd;
    inc (p, y);

    for x := 0 to b-1 do begin
      rowout [x] := p^;
      inc (p, h);
    end;

  end;

  bm.Assign (help);
  help.free;
end;

Leider funktioniert die nicht. Komme leider nicht dahinter warum (es fehlen 1-2 Pixel) und bei Bildgrößen mit ungeraden werten geht es nach dem 2. Drehen ganz schief.

Hat einer eine Idee, wie man es richtig machen könnte?
Miniaturansicht angehängter Grafiken
mem32.png  
  Mit Zitat antworten Zitat
Benutzerbild von Gausi
Gausi

Registriert seit: 17. Jul 2005
697 Beiträge
 
Delphi 10.3 Rio
 
#2

AW: 24-Bit Bitmap um 90 grad drehen - Resourcen-Optimierung

  Alt 18. Okt 2020, 13:50
Vor Ewigkeiten habe ich Bitmaps mal per Hand geparsed und verarbeitet, und bin dabei auf die Eigenart gestoßen, dass jede Zeile in einer Bitmap-Datei ein Vielfaches von 4 Bytes enthalten muss. Bei 32 Bit ist das automatisch der Fall, bei 24Bit hat man ggf. bis zu 3 Füllbytes am Ende jeder Zeile.

Könnte das die Ursache deines Problems sein?
The angels have the phone box.
  Mit Zitat antworten Zitat
Benutzerbild von Harry Stahl
Harry Stahl

Registriert seit: 2. Apr 2004
Ort: Bonn
1.970 Beiträge
 
Delphi 10.4 Sydney
 
#3

AW: 24-Bit Bitmap um 90 grad drehen - Resourcen-Optimierung

  Alt 18. Okt 2020, 14:26
Da hatte ich auch schon dran gedacht, aber keine Idee, wie ich das im Code berücksichtigen sollte...
  Mit Zitat antworten Zitat
Benutzerbild von Harry Stahl
Harry Stahl

Registriert seit: 2. Apr 2004
Ort: Bonn
1.970 Beiträge
 
Delphi 10.4 Sydney
 
#4

AW: 24-Bit Bitmap um 90 grad drehen - Resourcen-Optimierung

  Alt 18. Okt 2020, 16:15
Habe das mit den Füllbytes noch mal aufgegriffen und mache die Höhe oder Breite passend.

Von einem Test-Bitmap mit Breite = 2348 und Höhe= 3181 wird dann aus der Höhe 3184. Wenn ich nun die Bytes des alten Bitmaps in die vergrößerte Bitmap kopiere, wird alles kopiert und ich kann das Bitmap danach auch weiter drehen.

Allerdings: Ich habe eine um 3 Pixel vergrößerte Bitmap. Wenn ich die dann wieder kürze, gibt es aber beim nächsten Mal drehen ein Problem mit der Anzeige.

Wie macht man das wohl richtig?

Delphi-Quellcode:
procedure Drehe90Rechts24 (bm: TBitmap);
type
  TMyHelp = array [0..0] of TRGBTriple;
var
  P, Pend : PRGBTriple; x, y, b, h, oldw, oldh: Integer; RowOut: ^TMyHelp; help: TBitmap;
begin
  help := TBitmap.create;
  help.pixelformat := pf24bit;

  oldw := bm.Width;
  oldh := bm.Height;

  b := bm.height;
  h := bm.width;

  if bm.Width mod 4 <> 0 then
     h := ((bm.Width div 4) * 4) + 4;
   if bm.Height mod 4 <> 0 then
     b := ((bm.Height div 4) * 4) + 4;

  help.SetSize (b, h);
  PEnd := Bm.scanline[bm.height-1];

  for y := 0 to bm.width-1 do begin

    rowout := help.scanline [y];
    p := PEnd;
    inc (p, y);

    for x := 0 to bm.height-1 do begin
      rowout [x] := p^;
      inc (p, bm.Width);
    end;

  end;

  bm.Assign (help);
  //bm.SetSize(oldh, oldw);
  //BitBlt(bm.canvas.handle, 0,0, bm.Width, bm.Height, help.canvas.handle, 0,0, SRCCopy); // funktioniert nur beim 1. drehen
  help.free;
end;
  Mit Zitat antworten Zitat
venice2

Registriert seit: 5. Dez 2019
281 Beiträge
 
Delphi 2010 Architect
 
#5

AW: 24-Bit Bitmap um 90 grad drehen - Resourcen-Optimierung

  Alt 18. Okt 2020, 17:02
Ich kenne solche Probleme nicht.
Liegt wohl daran das ich GDI+ verwende
GdipImageRotateFlip(img, Rotate90FlipNone);
  Mit Zitat antworten Zitat
Amateurprofi

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

AW: 24-Bit Bitmap um 90 grad drehen - Resourcen-Optimierung

  Alt 18. Okt 2020, 17:18
Das Thema hatten wir hier zwar schon öfter, aber nicht unter dem Gesichtspunkt, den ich hier ansprechen möchte:

Ich nutze zum drehen von 24 bzw. 32 Bitmaps bislang immer die folgende Routine (aus dem Doberenz-Buch):

Delphi-Quellcode:
procedure Drehe90Rechts (bm: TBitmap);
type
  TMyHelp = array [0..0] of TRGBQuad;
var
  P, Pend : PRGBQuad; x, y, b, h: Integer; RowOut: ^TMyHelp; help: TBitmap;
begin
  Bm.pixelformat := pf32bit;

  help := TBitmap.create;
  help.pixelformat := pf32bit;

  b := bm.height;
  h := bm.width;

  help.SetSize (b, h);
  PEnd := Bm.scanline[bm.height-1];

  for y := 0 to h-1 do begin

    rowout := help.scanline [y];
    p := PEnd;
    inc (p, y);

    for x := 0 to (b-1) do begin
      rowout [x] := p^;
      inc (p, h);
    end;

  end;

  bm.Assign (help);
  help.free;
end;
Ich dachte, OK die nehmen auch für eine 24-Bit-Bitmap eine 32-Bitmap, weil der Compiler die 32-Bits in einem Register direkt kopieren kann. Wenn man sich das in der CPU ansieht, dann stimmt das wohl auch, bei 24 muss er wohl erst 16-Bit und dann noch mal 8 kopieren, dadurch 2 Befehle mehr (siehe anliegenden Screenshot).

Nur: Bei sehr großen Bilder (teste gerade eins im Format 21600 x 10800) braucht er, aber um die 32-Bit-Hilfsbit anzulegen, statt 660 MB bei einer 24 Bit, bei der 32-Bit Bitmap ca. 1 GB zusätzlichen Arbeitsspeicher.

Daher meine Überlegung, statt die Routine mit 32-Bit zu verwenden, bei einer 24-Bit es mit einer 24-Bit routine zu machen.

Delphi-Quellcode:
procedure Drehe90Rechts24 (bm: TBitmap);
type
  TMyHelp = array [0..0] of TRGBTriple;
var
  P, Pend : PRGBTriple; x, y, b, h: Integer; RowOut: ^TMyHelp; help: TBitmap;
begin
  help := TBitmap.create;
  help.pixelformat := pf24bit;

  b := bm.height;
  h := bm.width;

  help.SetSize (b, h);
  PEnd := Bm.scanline[bm.height-1];

  for y := 0 to h-1 do begin

    rowout := help.scanline [y];
    p := PEnd;
    inc (p, y);

    for x := 0 to b-1 do begin
      rowout [x] := p^;
      inc (p, h);
    end;

  end;

  bm.Assign (help);
  help.free;
end;

Leider funktioniert die nicht. Komme leider nicht dahinter warum (es fehlen 1-2 Pixel) und bei Bildgrößen mit ungeraden werten geht es nach dem 2. Drehen ganz schief.

Hat einer eine Idee, wie man es richtig machen könnte?
Zu Drehe90Rechts24 (bm: TBitmap);


Vor der ersten Schleife wird PEnd auf das erste Pixel der letzten Zeile in BM gestellt
In der Y Schleife wird
1) P = PEnd gesetzt, also auf Pixel[0,letzte Zeile]
2) P um Y erhöht, also auf Pixel[Y,letzte Zeile gestellt]
In der X Schleife wird
1) Pixel P^ nach Help kopiert
2) P um H Pixel erhöht.
Das soll P auf die jeweils nächste Zeile in BM stellen.
Das funktioniert bei 32 Bit-Bitmaps, aber nicht bei 24 Bit, weil hier
der Offset zur nächsten Zeile (in Bytes) nicht Breite*3 ist, sondern immer ein
vielfaches von 4 ist. (Breite*3+3) div 4*4 sollte die Anzahl Bytes je Zeile ergeben.
Workaround:
var Offs:NativeInt;
1) Vor der Y Schleife
PEnd := Bm.scanline[bm.height-1];
Offs := NativeInt(Bm.scanline[bm.height-2])-NativeInt(PEnd);
2) In der X Schleife
Inc (NativeInt(p), Offs); // statt inc (p, h);
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 Harry Stahl
Harry Stahl

Registriert seit: 2. Apr 2004
Ort: Bonn
1.970 Beiträge
 
Delphi 10.4 Sydney
 
#7

AW: 24-Bit Bitmap um 90 grad drehen - Resourcen-Optimierung

  Alt 18. Okt 2020, 17:49
Danke, Du hast mir den Tag gerettet , da knabber ich schon ein paar Stunden dran rum...

Super, so braucht die Drehung "nur" zusätzlichen Arbeitsspeicher von 699 MB, statt 933 MB.
Erstaunlicherweise ist der Vorgang auch etwas schneller, als mit der 32-Bit-Variante (gemessen in der 64-Bit-Programm-Variante meines Programms). Wird wahrscheinlich durch die krass hohe Anzahl der Bytes, die weniger kopiert werden müssen (ca. 300 Mio) bewirkt...
  Mit Zitat antworten Zitat
Benutzerbild von Harry Stahl
Harry Stahl

Registriert seit: 2. Apr 2004
Ort: Bonn
1.970 Beiträge
 
Delphi 10.4 Sydney
 
#8

AW: 24-Bit Bitmap um 90 grad drehen - Resourcen-Optimierung

  Alt 18. Okt 2020, 17:52
Ich kenne solche Probleme nicht.
Liegt wohl daran das ich GDI+ verwende
GdipImageRotateFlip(img, Rotate90FlipNone);
Ist GDI+ denn wirklich schneller?

Hatte mal in der Vergangenheit ein zwei Sachen ausprobiert und war enttäuscht... Schließlich muss man ja immer erst diesen GDI-Kontext erzeugen und das Bild übergeben (was ja wohl auch einiges an Arbeitsspeicher braucht). Wie verhält sich GDI bei so großen Bildern (also die anfangs erwähnten 21600x10800)?
  Mit Zitat antworten Zitat
striderx

Registriert seit: 11. Feb 2007
Ort: Bergisch Gladbach
185 Beiträge
 
Delphi 10.4 Sydney
 
#9

AW: 24-Bit Bitmap um 90 grad drehen - Resourcen-Optimierung

  Alt 18. Okt 2020, 19:14
Ist GDI+ denn wirklich schneller?

Wie verhält sich GDI bei so großen Bildern (also die anfangs erwähnten 21600x10800)?
Schneller kann ich nicht sagen aber m. E. schon recht schnell. Allerdings gibt es für RotateFlip eine Größenbeschränkung. die irgendwo bei 65 Mio Pixel (bei einer 24 Bit-Bitmap) liegt; darüber ist kaum etwas im Netz zu finden. Nett ist auch, dass dann kein Fehler erzeugt wird und einfach nichts passiert.

Das kann man aber wie folgt umgehen:

Delphi-Quellcode:
function GDIPRotateFlipBitmap(ABitmap: tBitmap; Mode: RotateFlipType): Boolean;

var
  BM: tBitmap;
  GR: tGPGraphics;
  AGPBitmap: tGPBitmap;
  AStatus: Status;

begin
  if Mode = RotateNoneFlipNone then begin
     Result := True;
     Exit;
  end;
  
  BM := tBitmap.Create;
  BM.Assign(ABitmap);
  AGPBitmap := tGPBitmap.Create(BM.Handle, 0);
  
  AGPBitmap.RotateFlip(Mode);
  GR := tGPGraphics.Create(ABitmap.Canvas.Handle);
  GR.DrawImage(AGPBitmap, 0, 0);
  AStatus := GR.GetLastStatus;
  
  Result := (AStatus = OK);
  
  AGPBitmap.Free;
  BM.Free;
  GR.Free;
end;
Wie sich das jetzt auf die Geschwindigtkeit auswirkt, muss Du dann mal ausprobieren.
  Mit Zitat antworten Zitat
Benutzerbild von Harry Stahl
Harry Stahl

Registriert seit: 2. Apr 2004
Ort: Bonn
1.970 Beiträge
 
Delphi 10.4 Sydney
 
#10

AW: 24-Bit Bitmap um 90 grad drehen - Resourcen-Optimierung

  Alt 18. Okt 2020, 20:39
Ich habe in meinem Programm eine Performance-Test Anzeige eingebaut (die man aktivieren muss) und habe Deine Funktion mal im Vergleich getestet:

Beide Funktionen sind in etwa gleich schnell. Wobei die GDI-Funktionen offensichtlich nur mit 32-Bit-Dateien funktionieren, hier muss ich also Datei erst in 32-Bit umwandeln, verbrauche dafür also schon mal mehr Arbeitsspeicher. Im Vergleich zu der 24-Bit-Drehung ist "meine" Funktion bei 660 Mio. Pixeln ca. 500 ms schneller (insgesamt hier auf dem PC ca. 6 Sekunden).

Aber man kann (zumindest mit der 64-Bit-Version) auch die 660 bzw. über 900 Mio. Pixel mit der GDI-Funktion benutzen, hier konnte ich keine Einschränkung feststellen.

Ich werde allerdings die Drehfunktion noch (wenn das geht) in eine Funktion mit Workerthreads umgestalten, wo jede CPU einen Teilbereich bearbeitet.

Das bringt echt noch mal Speed: Für die Funktion zur Änderung der Helligkeit habe ich das schon mal gemacht, während die Funktion für das oben erwähnte große Bild bei einer CPU z.B. 1,6 Sekunden braucht, um die Helligkeit zu ändern, geht es mit den Workerthreads (mit TTask) (ja nach Anzahl der CPUS) mit 6 CPUS z.B. in 300 MS. Das ist schon ein spürbarer Unterschied....
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

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 02:59 Uhr.
Powered by vBulletin® Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2020 by Daniel R. Wolf