Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Geht das noch schneller? - Bitmap-Verrechnung (https://www.delphipraxis.net/182859-geht-das-noch-schneller-bitmap-verrechnung.html)

Harry Stahl 22. Nov 2014 02:00

Geht das noch schneller? - Bitmap-Verrechnung
 
Mit dieser Funktion wird eine 32-Bitmap - unter Berücksichtigung der Transparenz auf einen Konstanten Untergrund (die Hintergrund-Bitmap) gemalt.

Mal abgesehen von Parallel-Berechnung mit TParallel (was ich schon erledigt habe, hier die einfache Version, um die Funktion leichter nachvollziehen zu können), kann man das noch irgendwie schneller berechnen?

Delphi-Quellcode:
// Setz vorraus, dass die Bitmaps die gleiche Größe haben!!!
procedure Draw32BitToBitmapold(const BitOben: TBitmap; BitUnten: TBitmap);
var
  h,w,i: Integer;
  RGBA_Unten, RGBA_Oben: pRGBALine;
begin
  For h := 0 to BitUnten.Height-1 do begin
    RGBA_Unten := BitUnten.ScanLine[h];
    RGBA_Oben := BitOben.ScanLine[h];

    For w:= 0 to BitUnten.Width-1 do begin
      if RGBA_Oben^[w].rgbReserved = 0 then begin
        // unten bleibt
      end else begin
        i := Round (RGBA_Unten^[w].rgbBlue - ((RGBA_Unten^[w].rgbBlue - RGBA_Oben^[w].rgbBlue) / 255 * RGBA_Oben^[w].rgbReserved));
        if i < 0 then RGBA_Unten^[w].rgbBlue := 0 else if i > 255 then RGBA_Unten^[w].rgbBlue := 255 else RGBA_Unten^[w].rgbBlue := i;

        i := Round (RGBA_Unten^[w].rgbGreen - ((RGBA_Unten^[w].rgbGreen - RGBA_Oben^[w].rgbGreen) / 255 *  RGBA_Oben^[w].rgbReserved));
        if i < 0 then RGBA_Unten^[w].rgbGreen := 0 else if i > 255 then RGBA_Unten^[w].rgbGreen := 255 else RGBA_Unten^[w].rgbGreen := i;

        i := Round (RGBA_Unten^[w].rgbRed - ((RGBA_Unten^[w].rgbRed - RGBA_Oben^[w].rgbRed) / 255 * RGBA_Oben^[w].rgbReserved));
        if i < 0 then RGBA_Unten^[w].rgbRed := 0 else if i > 255 then RGBA_Unten^[w].rgbRed := 255 else RGBA_Unten^[w].rgbRed := i;

        RGBA_Unten^[w].rgbReserved := 255;
      end;
   end;
  end;
end;

hstreicher 22. Nov 2014 08:21

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
schneller wird es wenn man die Formeln umbau so dass mit Integer anstatt Floats gerechnet wird,

und die geschachtelten Abfragen so umstellen dass das wahrscheinlich häuftigste Ergebnis zuerst abgeprüft wird
um den 2. Vergleich zu vermeiden

Harry Stahl 22. Nov 2014 08:52

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Mhh, wenn ich integer verwende, wird es ungenau. Aber wäre vielleicht akeptabel, wenn es nur um Anzeige eines Ergebnisses geht ( im Unterschied zu einem konkret weiterverwendbaren Ergebnis).

Das wahrscheinlichste Ergebis ist, dass der Wert zwischen 0 und 255 liegt, aber das muss ich zuvor durch Überprüfung sicherstellen, komme da also nicht dran vorbei...

Bernhard Geyer 22. Nov 2014 09:10

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Hast du eigentlich schon mal mit AQTime geprüft?

Ich vermute wenn du für RGBA_Unten^[w] und Co. Lokale Variablen verwendest wird es auch schneller

himitsu 22. Nov 2014 09:38

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Parallele Berechnung mehrerer Bytes = Streaming-Funktionen ala 3DNow!, MMX, SSE, AVX, FMA :stupid:

Da kann man "gleichzeitig", in einem Thread, mit 128 Bit (z.B. 8 Byte) oder gar 256 Bit rechnen, also mit mindestens 2 Color-Dingern (a 4 Bytes) in einem Rutsch.

Harry Stahl 22. Nov 2014 10:37

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
@ Berhard: Klar, AQTime (Prof) ist mein ständiger Begleiter.

Lokale Variablen zu verwenden, bringt im vorliegenden Fall leider nichts, weil die Zuweisung an die lokalen Variablen in der Summe länger braucht (ca. 30%), als der Zugriff auf den Speicher:

Delphi-Quellcode:
procedure Draw32BitToBitmapNew(const BitOben: TBitmap; BitUnten: TBitmap);
var
   h,w,i: Integer;
   rublue, rugreen, rured, rureserved,
   roblue, rogreen, rored, roreserved: Byte;
   RGBA_Unten, RGBA_Oben: pRGBALine;
begin
   For h := 0 to BitUnten.Height-1 do begin
     RGBA_Unten := BitUnten.ScanLine[h];
     RGBA_Oben := BitOben.ScanLine[h];

     For w:= 0 to BitUnten.Width-1 do begin
       if RGBA_Oben^[w].rgbReserved = 0 then begin
         // unten bleibt
       end else begin
         rublue := RGBA_Unten^[w].rgbBlue;
         rugreen := RGBA_Unten^[w].rgbGreen;
         rured := RGBA_Unten^[w].rgbred;
         rureserved := RGBA_Unten^[w].rgbreserved;

         roblue := RGBA_Oben^[w].rgbBlue;
         rogreen := RGBA_Oben^[w].rgbGreen;
         rored := RGBA_Oben^[w].rgbred;
         roreserved := RGBA_Oben^[w].rgbreserved;

         i := Round (ruBlue - ((ruBlue - roBlue) / 255 * roReserved));
         if i < 0 then RGBA_Unten^[w].rgbBlue := 0 else if i > 255 then RGBA_Unten^[w].rgbBlue := 255 else RGBA_Unten^[w].rgbBlue := i;

         i := Round (ruGreen - ((ruGreen - roGreen) / 255 * roReserved));
         if i < 0 then RGBA_Unten^[w].rgbGreen := 0 else if i > 255 then RGBA_Unten^[w].rgbGreen := 255 else RGBA_Unten^[w].rgbGreen := i;

         i := Round (ruRed - ((ruRed - roRed) / 255 * roReserved));
         if i < 0 then RGBA_Unten^[w].rgbRed := 0 else if i > 255 then RGBA_Unten^[w].rgbRed := 255 else RGBA_Unten^[w].rgbRed := i;

         RGBA_Unten^[w].rgbReserved := 255;
       end;
    end;
   end;
end;

Harry Stahl 22. Nov 2014 10:38

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
@himitsu:

MMX,SSE Streaming-Funktionen: Noch nie verwendet. Wie nutzt man das?
Muss ich Assembler verwenden? Gibt es Beispiele für Bitmap-Verwendung?

mensch72 22. Nov 2014 10:51

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
man nehme einfach "MULDIV" für solche Berechnungen in Integer ohne Genauigkeitsverlust.

aus: i := Round (RGBA_Unten^[w].rgbBlue - ((RGBA_Unten^[w].rgbBlue - RGBA_Oben^[w].rgbBlue) / 255 * RGBA_Oben^[w].rgbReserved));
wird dann: i := RGBA_Unten^[w].rgbBlue - MulDiv(RGBA_Unten^[w].rgbBlue - RGBA_Oben^[w].rgbBlue, RGBA_Oben^[w].rgbReserved, 255);

Mit Zusatzvariable und nur einer Dereferenzierung am Schleifenanfang, also "col:=RGBA_Unten^[w]" und dann nur mit "col.rgbXXX" rechnen wird es nochmal schneller.
Die hier oft verwendete "255" finde ich nicht ganz so dolle, denn 0..255 sind 256 Werte, also setze man doch lieber alle "0..255" Werte mit 256 ins Verhältnis, dann gibt es auch keine Resultate > 255... :)

Ansonsten rechne ich das lieber komplett auf Speicherarrays und verwende simple Indexzugriffe auf vor berechnete Wertetabellen(statt ständiges "MulDiv" von zwei "8Bit" Werten) sowie das Ganze möglichst als vorzeichenlose Ganzzahlarithmetik, das ist noch schneller und damit sind dann auch so Sachen wie SSEx für weiter Filteroperationen und andere Spielereien möglich. Das führt aber hier zuweit. Einen Blick in die SourceCodes von optimierten Grafiklibs würde ich da empfehlen.

himitsu 22. Nov 2014 11:19

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Ob es dafür bereits fertige Bibliotheken gibt, weiß ich nicht, aber am Ende kommt es auf Assembler hinaus, da Pascal das natürlich nicht direkt unterstützt (ob du das nunb schreibst, oder jemand anderes)

Ich war mal vor Jahren auf die Idee gekommen, die Operationen in einem Record zu kapseln (Record Operatoren und Methoden), aber da ich selber keinen Anwendungsfall und nicht wirklich Zeit hatte .......

Bezüglich des MulDiv:
Jupp, solange du bei Integer-Operationen bleibst, sollte es etwas schneller gehen.
Bezüglich dem (Auf)Runden kann man einfach bissl was Aufaddieren, vor dem Dividieren.

Harry Stahl 22. Nov 2014 11:24

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Also, nur statt "/" ein div zu nehmen und das round wegzulassen (also nur mit Integer zu rechnen), benötigt ca. 30% mehr Zeit.

Mit MultiDiv zu arbeiten, dauert gar direkt 100% länger.

Aber die anderen beschriebenen Ansätze werde ich auch mal versuchen.

Harry Stahl 22. Nov 2014 11:34

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Selbst dieser Versuch, einen lokalen TRGBQuad zu verwenden (cu- und co-Variablen), führt bei 5 Durchläufen, bei einem Bitmap von ca. 3500x2500 Pixel zu 300 MS mehr Zeit:

Delphi-Quellcode:
procedure Draw32BitToBitmapNew(const BitOben: TBitmap; BitUnten: TBitmap);
var
   h,w,i: Integer;
   RGBA_Unten, RGBA_Oben: pRGBALine;
   cu, co : TRGBQuad;
begin
   For h := 0 to BitUnten.Height-1 do begin
     RGBA_Unten := BitUnten.ScanLine[h];
     RGBA_Oben := BitOben.ScanLine[h];

     For w:= 0 to BitUnten.Width-1 do begin
       if RGBA_Oben^[w].rgbReserved = 0 then begin
         // unten bleibt
       end else begin
         cu := RGBA_Unten^[w];
         co := RGBA_Oben^[w];

         i := Round (cu.rgbBlue - ((cu.rgbBlue - co.rgbBlue) / 255 * co.rgbReserved));
         if i < 0 then RGBA_Unten^[w].rgbBlue := 0 else if i > 255 then RGBA_Unten^[w].rgbBlue := 255 else RGBA_Unten^[w].rgbBlue := i;

         i := Round (cu.rgbGreen - ((cu.rgbGreen - RGBA_Oben^[w].rgbGreen) / 255 * co.rgbReserved));
         if i < 0 then RGBA_Unten^[w].rgbGreen := 0 else if i > 255 then RGBA_Unten^[w].rgbGreen := 255 else RGBA_Unten^[w].rgbGreen := i;

         i := Round (cu.rgbRed - ((cu.rgbRed - co.rgbRed) / 255 * co.rgbReserved));
         if i < 0 then RGBA_Unten^[w].rgbRed := 0 else if i > 255 then RGBA_Unten^[w].rgbRed := 255 else RGBA_Unten^[w].rgbRed := i;

         RGBA_Unten^[w].rgbReserved := 255;
       end;
    end;
   end;
end;

Harry Stahl 22. Nov 2014 11:48

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Zitat:

Zitat von mensch72 (Beitrag 1280733)
Die hier oft verwendete "255" finde ich nicht ganz so dolle, denn 0..255 sind 256 Werte, also setze man doch lieber alle "0..255" Werte mit 256 ins Verhältnis, dann gibt es auch keine Resultate > 255... :)

Was meinst Du hiermit genau?

Ich vermute mal, eine x in 0..255 Prüfung braucht mehr Zeit und ich weiß dann immer noch nicht, ob x evtl. kleiner als 0 (dann schwarz) oder größer 255 ist (dann weiß).

Jens01 22. Nov 2014 11:50

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Schon mal bei/mit Graphics32 versucht?!

himitsu 22. Nov 2014 12:00

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
länger:

Ist ein bissl erschreckend, aber liegt auch an deiner Speicherverwaltung. (zuviele ungünstig liegende Variablen)
Integer-Operationen werden in den CPU-Registern (EAX usw.) durchgeführt.
Die Fließkommaoperationen in den FPU-Registern, wobei EAX und Co. frei bleibt.

Das Selbe würde dann auch bei den Streaming-Registern auftreten.

Und warum eigentlich ständig
Delphi-Quellcode:
RGBA_Unten^[w]
und nicht Anfangs mal in eine Variable?

mensch72 22. Nov 2014 12:21

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Ich verwende "/256" statt "/255".

MulDiv ist live wegen der internen multiplen 32Bit über Int64 Logik Langsamer als aktuelle FPU Nutzung, aber mit ging es ums erkennen des Prinzips!

wenn aus "Round (RGBA_Unten^[w].rgbBlue - ((RGBA_Unten^[w].rgbBlue - RGBA_Oben^[w].rgbBlue) / 255 * RGBA_Oben^[w].rgbReserved));"
besser "RGBA_Unten^[w].rgbBlue - ((RGBA_Unten^[w].rgbBlue - RGBA_Oben^[w].rgbBlue) * RGBA_Oben^[w].rgbReserved) div 255; //<div 256> oder besser <shr 8>;" wird...
also geht das auch in 32Bit(Integer) ohne Muldiv völlig ohne Genauigkeitsverlust, weil eben ohne Informationsverlust erst multipliziert und dann dividiert wird.

Nochmal im Detail:
- du hast zwei 8Bit (Farb)Werte, die können multipliziert max. einen 16Bit Wert ergeben(0.65535), welcher Locker in eine 32 Bit passt
- ein "SHR 8" ist minimal schneller wie ein "DIV 256"
- mit glatten 2er Potenzen zu rechnen schadet nie

Also:
Du hast 2 Farbwerte welche du multiplizierst und fix wieder durch 255teislt(oder 256 bzw. um 8 rechts schiebst)... das geht, ist aber per möglicher Tabelle 1 aus 65536(2^16) im Indexbereich von 0.65535 mit vor berechneten Einträgen am schnellsten:

RelColResult:=RelColTable[(ColValueA shl 8)+ColValueB];
("RelColTable" sein ein Array 0..65535 of BYTE)



(Ich rechne das irgendwie anders, deshalb erschließt sich mir der Sinn deine nachfolgenden Abfrage aus ">255" nicht, denn mir fällt kein Wertepaar der 2 Ausgangsfarben ein, wo das Ergebnis >255 sein kann... Nur weil Round auch "aufrundet" passiert dir das eventuell... Ich denke wenn du Round durch Floor ersetzt kannst du dir das "if" sparen und Kommafarbwerte gibt es bei 8Bit 0.255 eh nicht :) )

Harry Stahl 22. Nov 2014 12:42

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
wenn ich Round durch Floor ersetze, dauert es 3 mal so lang...

Harry Stahl 22. Nov 2014 13:08

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Ich glaube, Du könntest Recht haben, mit der Vermutung, dass es eigentlich nie größer als 255 werden kann, da ja von einem Ausgangswert, der nie größer als 255 sein kann, immer etwas abgezogen wird. Also muss man in der Tat nur den <0 Fall berücksichtigen.

Auch /256 statt /255 müsste richtig sein, da es ja um die Anzahl der möglichen Farbabstufungen geht.

Super!!

Das umgesetzt werden laut AQTime pro Aufruf der Funktion ca. 20 MS gespart:-D

Das Ding sieht jetzt also so aus:

Delphi-Quellcode:
procedure Draw32BitToBitmapNew(const BitOben: TBitmap; BitUnten: TBitmap);
var
   h,w,i: Integer;
   RGBA_Unten, RGBA_Oben: pRGBALine;
begin
    for h := 0 to BitUnten.Height-1 do begin
     RGBA_Unten := BitUnten.ScanLine[h];
     RGBA_Oben := BitOben.ScanLine[h];

     For w:= 0 to BitUnten.Width-1 do begin
       if RGBA_Oben^[w].rgbReserved = 0 then begin
         // unten bleibt
       end else begin
         i := Round (RGBA_Unten^[w].rgbBlue - ((RGBA_Unten^[w].rgbBlue - RGBA_Oben^[w].rgbBlue) / 256 * RGBA_Oben^[w].rgbReserved));
         if i < 0 then RGBA_Unten^[w].rgbBlue := 0 else RGBA_Unten^[w].rgbBlue := i;

         i := Round (RGBA_Unten^[w].rgbGreen - ((RGBA_Unten^[w].rgbGreen - RGBA_Oben^[w].rgbGreen) / 256 * RGBA_Oben^[w].rgbReserved));
         if i < 0 then RGBA_Unten^[w].rgbGreen := 0 else RGBA_Unten^[w].rgbGreen := i;

         i := Round (RGBA_Unten^[w].rgbRed - ((RGBA_Unten^[w].rgbRed - RGBA_Oben^[w].rgbRed) / 256 * RGBA_Oben^[w].rgbReserved));
         if i < 0 then RGBA_Unten^[w].rgbRed := 0 else RGBA_Unten^[w].rgbRed := i;

         RGBA_Unten^[w].rgbReserved := 255;
       end;
    end;
   end;
end;

Harry Stahl 22. Nov 2014 14:03

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Jetzt noch mal Ergebnisse bei Parallelisierung des ganzen mit TParallel:

Auf 2-Kern-Rechner von ca. 300 MS auf 150
Auf 4-Kern-Rechner von ca. 300 MS auf 100
Auf 6-Kern-Rechner von ca. 300 MS auf 56

Also fast 6 mal so schnell!!

Jetzt lohnt sich das mit den Kernen so richtig, insbesondere bei den rechenintensiven Grafikbearbeitungsaufgaben eine echt hilfreiche Sache.

Also was das angeht, bringt XE7 voll den Turbo!!:thumb:

Mein nächster Entwicklungsrechner wird also mit mindestens 6 Kernen kommen...

mensch72 22. Nov 2014 16:23

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Eine Bitte:
mach dir mal für mich die Mühe und "messe" die Zeiten noch für diese 2 Varianten:

i := RGBA_Unten^[w].rgbBlue - (((Int(RGBA_Unten^[w].rgbBlue - RGBA_Oben^[w].rgbBlue) * Int(RGBA_Oben^[w].rgbReserved)) div 256);
und
i := RGBA_Unten^[w].rgbBlue - (((Int(RGBA_Unten^[w].rgbBlue - RGBA_Oben^[w].rgbBlue) * Int(RGBA_Oben^[w].rgbReserved)) shr 8);

(für je alle 3 Farben halt)

Das wird genauso exakt und "müsste" schneller sein... Das "div 256" und "shr 8" könnte sogar der Compiler optimieren, wenn es keinen Unterschied machen sollte.

Bin gespannt auf deine Ergebnisse:)

Harry Stahl 22. Nov 2014 16:32

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Mache ich doch gerne. Rückmeldung zu Variante 1+2:

E2015: Operator ist auf diesen Operandentyp nicht anwendbar.

mensch72 22. Nov 2014 16:37

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Sorry, der "Sicherheits-Cast" muss Integer(...) und nicht int(xxx) heißen!

also
i := RGBA_Unten^[w].rgbBlue - (((Integer(RGBA_Unten^[w].rgbBlue - RGBA_Oben^[w].rgbBlue) * Integer(RGBA_Oben^[w].rgbReserved)) div 256);
und
i := RGBA_Unten^[w].rgbBlue - (((Integer(RGBA_Unten^[w].rgbBlue - RGBA_Oben^[w].rgbBlue) * Integer(RGBA_Oben^[w].rgbReserved)) shr 8);

(ich sollte nicht so viel C++ programmieren;) )

Harry Stahl 22. Nov 2014 16:57

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Liste der Anhänge anzeigen (Anzahl: 2)
Die Variante mit SHR ist compilierbar, ist auch schneller, aber das Ergebnis ist falsch, siehe anliegende Screenshots.

Das habe ich von Dir da verwendet:

Delphi-Quellcode:
procedure Draw32BitToBitmapNew(const BitOben: TBitmap; BitUnten: TBitmap);
var
   h,w,i: Integer;
   RGBA_Unten, RGBA_Oben: pRGBALine;
begin
    for h := 0 to BitUnten.Height-1 do begin
     RGBA_Unten := BitUnten.ScanLine[h];
     RGBA_Oben := BitOben.ScanLine[h];

     For w:= 0 to BitUnten.Width-1 do begin
       if RGBA_Oben^[w].rgbReserved = 0 then begin
         // unten bleibt
       end else begin
         i := RGBA_Unten^[w].rgbBlue - (((Integer(RGBA_Unten^[w].rgbBlue - RGBA_Oben^[w].rgbBlue) * Integer(RGBA_Oben^[w].rgbReserved)) shr 8));
         if i < 0 then RGBA_Unten^[w].rgbBlue := 0 else RGBA_Unten^[w].rgbBlue := i;

         i := RGBA_Unten^[w].rgbGreen - (((Integer(RGBA_Unten^[w].rgbGreen - RGBA_Oben^[w].rgbGreen) * Integer(RGBA_Oben^[w].rgbReserved)) shr 8));
         if i < 0 then RGBA_Unten^[w].rgbGreen := 0 else RGBA_Unten^[w].rgbGreen := i;
         
         i := RGBA_Unten^[w].rgbred - (((Integer(RGBA_Unten^[w].rgbred - RGBA_Oben^[w].rgbred) * Integer(RGBA_Oben^[w].rgbReserved)) shr 8));
         if i < 0 then RGBA_Unten^[w].rgbRed := 0 else RGBA_Unten^[w].rgbRed := i;

         RGBA_Unten^[w].rgbReserved := 255;
       end;
    end;
   end;
end;

Harry Stahl 22. Nov 2014 17:02

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Und die erste Variante ist nach wie vor nicht kompilierbar. Zwar akzeptiert der Compiler die erste Zeile, bei der zweiten sagt er aber "E2014: Anweisung erforderlich aber Ausdruck vom Typ Integer gefunden"

mensch72 22. Nov 2014 17:20

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Wenn der Compiler sagt, das da Irgendwo kein Integer ist funktioniert das mit "shr 8" nicht... morgen werfe ich ml kurz mein Delphi an und finde das "Syntax" Problem... muss ja meine Pascalsyntax "schulen".

Auch macht SHR Mist, bei negativen Zahlen... ich tippe es mal komplett als "unsigned int" ähhh "cardinal"... muss aber erst noch verstehen, "warum" du aktuell den Weg über negative werte gehst... meine Routine welche ich irgendwo habe macht die Größenprüfung irgendwie vor der Differenz und bearbeitet mit angepasster Folgelogik dann nur positive Werte...

Setze doch mal einen Breakpunkt auf den Zweig "wenn kleiner 0" und schreibe gib mir mal die Farb und Trasparenz-Werte als Beispiel. Konstruieren kann ich mir das auch, aber möchte mal deine Zahlen in meine Routine stecken.

Medium 22. Nov 2014 17:39

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Bei so vielen Operationen mit Bitmaps würde ich auch recht schnell zur schon erwähnten Graphics32 greifen. Insbesondere die Überblendungsoperationen sind da extrem flott umgesetzt, genaue Zahlen habe ich aber nicht an der Hand zum vergleichen. Parallel-Processing macht die von Hause aus zwar nicht, ließe sich aber bestimmt auf kleinen Umwegen auch machen. Wenn es dann überhaupt noch nötig ist.

Harry Stahl 22. Nov 2014 17:45

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Liste der Anhänge anzeigen (Anzahl: 2)
Ich habe mal die Bilder was kleiner gemacht, damit ich sie noch in die Form integrieren kann (im Original sind sie ca. jeweils 30 MB groß, da weigert sich Delphi) und das Testprojekt mal hier hochgeladen.

Auf dem Screenshot kann man sehen: Alt gibt die Zeit für die Ursprungs-Procedure vor. Optimiert ist das, wo wir uns gerade bemühen (im Source jetzt gleich mit "Alt") und Par ist die Bearbeitung in Parallel.

Zeige "Ergebnis" zeigt das Ergebnis einer der 3 Berechnungsmethoden an, und Prüft bei Optimiert und Parallel, ob das Ergebnis gleich ist mit der Ursprungsfunktion.

Zur Info: Der Hintergrund ist ein Farbverlauf, das obere Bitmap ist in den Streifen Teiltransparent.

jfheins 22. Nov 2014 19:07

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Hast du es mal ohne die Prüfung auf i < 0 probiert? Der Fall sollte ja eigentlich nicht vorkommen

Ansonsten habe ich noch Vorschläge:
1. Termumformung, sollte aber eigentlich nicht schneller sein. Ist aber imho etwas verständlicher
Delphi-Quellcode:
RGBA_Unten^[w].rgbBlue := Cardinal((255 - RGBA_Oben^[w].rgbReserved) * RGBA_Unten^[w].rgbBlue + RGBA_Oben^[w].rgbReserved * RGBA_Oben^[w].rgbBlue) shr 8;
etc. für die anderen Farben.

2. Nimm mal nicht immer die gleiche Variable i, sondern drei verschiedene Variablen. Dann können die drei Zeilen parallel ablaufen.
3. Fall die if-Abfrage doch nötig sein sollte, schreibe sowas:
Delphi-Quellcode:
RGBA_Unten^[w].rgbBlue := i and (not i shr 24)
Effekt: Wenn der Wert negativ wird, dann wird das obere Byte des ints aus einsen bestehen. Durch das bitweise and wird der Wert zu 0. Du vermeidest aber das if, das auf Maschinenebene möglicherweise teuer ist.

4. Sagt wir "premultiplied alpha" etwas? Klingt erstmal komisch, ist aber eigentlich die sinnvollere Variante. Würde deinen Rechenaufwand auch hier reduzieren, aber deine Bilddaten müssten dafür natürlich angepasst werden.

samso 23. Nov 2014 07:18

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Ich habe einige sehr einfache Änderungen vorgenommen. Bei mir benötigt der Algorithmus dann nur noch die halbe Zeit. Das Ergebnis ist nicht identisch mit dem alten Algorithmus. Die Ursache liegt meiner Meinung nach im Floatingpoint-Rundungsalgorithmus begründet. Das Bild sieht aber nicht offensichtlich falsch aus.
Delphi-Quellcode:
procedure Draw32BitToBitmapSamso(const BitOben: TBitmap; BitUnten: TBitmap);
var
   h, w, i: Integer;
   RGBA_Unten, RGBA_Oben: PRGBQuad;
begin
    for h := 0 to BitUnten.Height-1 do begin
     RGBA_Unten := BitUnten.ScanLine[h];
     RGBA_Oben := BitOben.ScanLine[h];

     For w:= 0 to BitUnten.Width-1 do begin
       if RGBA_Oben^.rgbReserved = 0 then begin
         // unten bleibt
       end else begin
         i := RGBA_Unten^.rgbBlue - (RGBA_Unten^.rgbBlue - RGBA_Oben^.rgbBlue) * RGBA_Oben^.rgbReserved div 256;
         if i < 0 then RGBA_Unten^.rgbBlue := 0 else RGBA_Unten^.rgbBlue := i;

         i := RGBA_Unten^.rgbGreen - (RGBA_Unten^.rgbGreen - RGBA_Oben^.rgbGreen) * RGBA_Oben^.rgbReserved div 256;
         if i < 0 then RGBA_Unten^.rgbGreen := 0 else RGBA_Unten^.rgbGreen := i;

         i := RGBA_Unten^.rgbRed - (RGBA_Unten^.rgbRed - RGBA_Oben^.rgbRed) * RGBA_Oben^.rgbReserved div 256;
         if i < 0 then RGBA_Unten^.rgbRed := 0 else RGBA_Unten^.rgbRed := i;

         RGBA_Unten^.rgbReserved := 255;
       end;
       inc(RGBA_Unten); inc(RGBA_Oben);
    end;
   end;
end;

Harry Stahl 23. Nov 2014 12:50

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Erst mal vielen Dank an Euch fürs mit überlegen, ich finde es echt spannend, hier die anderen Ansätze mal zu sehen. Jede der zuletzt genannten Varianten war immer ein weniger schneller als die Ausgangsfunktion.

Ich habe jetzt einfach mal bei ImageEn nachgesehen, die ich hier lizenziert habe, wie die das machen. Da ist das Bild zwar auch geringfügig unterschiedlich als meine Ausgangsfunktion, aber vielleicht war meine ja auch nicht korrekt.

Jedenfalls in Anlehnung an die ImageEn-Lösung kann man das hier so machen ist das ist dann mit 71 MS die bislang schnellste Lösung und toppt sogar die Parallel-Lösung. Da ist dann irgendwann anscheinend der Zeitbedarf für das Management des Threading größer, als der Zeitgewinn durch den Einsatz mehrerer Kerne. Insofern muss man sich genau ansehen, wann man die Parallelisierung einsetzt. Besserer Code geht also meistens doch noch vor Parallel-Bearbeitung. Wahrscheinlich lohnt sich die Parallelisierung eher bei Prozessen, die eh schon etwas länger dauern.

Delphi-Quellcode:
// Setz vorraus, dass die Bitmaps die gleiche Größe haben!!!
procedure Draw32BitToBitmap(const BitOben: TBitmap; BitUnten: TBitmap);
var
  h,w,i: Integer;
  RGBA_Unten, RGBA_Oben: pRGBALine;
begin
  For h := 0 to BitUnten.Height-1 do begin
    RGBA_Unten := BitUnten.ScanLine[h];
    RGBA_Oben := BitOben.ScanLine[h];

    For w:= 0 to BitUnten.Width-1 do begin
      if RGBA_Oben^[w].rgbReserved = 0 then begin
        // unten bleibt
      end else begin
        (* Das war die Ausgangslösung
        i := Round (RGBA_Unten^[w].rgbBlue - ((RGBA_Unten^[w].rgbBlue - RGBA_Oben^[w].rgbBlue) / 255 * RGBA_Oben^[w].rgbReserved));
        if i < 0 then RGBA_Unten^[w].rgbBlue := 0 else if i > 255 then RGBA_Unten^[w].rgbBlue := 255 else RGBA_Unten^[w].rgbBlue := i;

        i := Round (RGBA_Unten^[w].rgbGreen - ((RGBA_Unten^[w].rgbGreen - RGBA_Oben^[w].rgbGreen) / 255 *  RGBA_Oben^[w].rgbReserved));
        if i < 0 then RGBA_Unten^[w].rgbGreen := 0 else if i > 255 then RGBA_Unten^[w].rgbGreen := 255 else RGBA_Unten^[w].rgbGreen := i;

        i := Round (RGBA_Unten^[w].rgbRed - ((RGBA_Unten^[w].rgbRed - RGBA_Oben^[w].rgbRed) / 255 * RGBA_Oben^[w].rgbReserved));
        if i < 0 then RGBA_Unten^[w].rgbRed := 0 else if i > 255 then RGBA_Unten^[w].rgbRed := 255 else RGBA_Unten^[w].rgbRed := i;
        *)

        RGBA_Unten^[w].rgbred := (RGBA_Oben^[w].rgbReserved * (RGBA_Oben^[w].rgbred - RGBA_Unten^[w].rgbred) shr 8 + RGBA_Unten^[w].rgbred);
        RGBA_Unten^[w].rgbGreen := (RGBA_Oben^[w].rgbReserved * (RGBA_Oben^[w].rgbgreen - RGBA_Unten^[w].rgbGreen) shr 8 + RGBA_Unten^[w].rgbGreen);
        RGBA_Unten^[w].rgbBlue := (RGBA_Oben^[w].rgbReserved * (RGBA_Oben^[w].rgbBlue - RGBA_Unten^[w].rgbBlue) shr 8 + RGBA_Unten^[w].rgbBlue);

        RGBA_Unten^[w].rgbReserved := 255;
      end;
   end;
  end;
end;

mensch72 23. Nov 2014 13:46

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
super... das war eigentlich exakt das was ich dir gerade als "Berechnungslösung" vorschlagen wollte, denn auch wenn ich das vor Jahren woanders her kopiert habe... das sieht einfach schön klar aus:)

Ich würde aber eine zusätzliche Sicherheitsklammerung einführen, damit auch wirklich erst multipliziert wird und erst dann dividiert(shr 8) wird... das sollte genauer sein, wenn hier bicht absichtlich mit den BitUmschlag im Shift gerechnet wird.

RGBA_Unten^[w].rgbred := ((RGBA_Oben^[w].rgbReserved * (RGBA_Oben^[w].rgbred - RGBA_Unten^[w].rgbred)) shr 8 + RGBA_Unten^[w].rgbred);
RGBA_Unten^[w].rgbGreen := ((RGBA_Oben^[w].rgbReserved * (RGBA_Oben^[w].rgbgreen - RGBA_Unten^[w].rgbGreen)) shr 8 + RGBA_Unten^[w].rgbGreen);
RGBA_Unten^[w].rgbBlue := ((RGBA_Oben^[w].rgbReserved * (RGBA_Oben^[w].rgbBlue - RGBA_Unten^[w].rgbBlue)) shr 8 + RGBA_Unten^[w].rgbBlue);

Einen Versuch wäre es wert:)

Dejan Vu 23. Nov 2014 16:04

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Zitat:

Zitat von mensch72 (Beitrag 1280834)
Ich würde aber eine zusätzliche Sicherheitsklammerung einführen, damit auch wirklich erst multipliziert wird und erst dann dividiert(shr 8) wird...

Wie kann ich mir das vorstellen? Ohne Sicherheitsklammerung wird erst multipliziert und dann dividiert, aber *mit* Sicherheits(!)klammerung wird wirklich erst multipliziert und erst dann dividiert, richtig? Woran erkennt man den Unterschied? Ist das eine Ergebnis richtig, aber das andere voll korrekt?

Im Ernst: Mit Sicherheitsklammerung wird ein Programm nicht besser, nur der WTF-Faktor* erhöht sich. Nun ist es aber gerade erstrebenswert, den WTF-Faktor auf 0 zu setzen.

(*) WTF-Faktor: WTF-Shouts / LoC.

PS: Muldiv hat eingebaute Sicherheitsklammerung.

mensch72 23. Nov 2014 17:19

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
=> solange alles es in der Wertebereich der Operatoren passt, bei Ganzzahl-Arithmetik IMMER erst "vergrößern" (also addieren oder multiplizieren oder "shl") und dann verkleinern(also subtrahieren, dividieren oder "shr")

=> weil Pascal hier nicht immer das mach was ich will oder ich auch oft zu nur faul zum Nachzudenken, was der Kompiler draus macht, gebe ich es lieber vor), klammere da lieber einmal zuviel wie zu wenig, außerdem merkt so ein anderer welcher das liest, das man hier besonderen Wert auf die Rechenreihefolge gelegt hat und kommt nicht auf die Idee, weil's eventuell schöner "aussieht" aus "100 * 128 div 256" etwa "128 div 256 * 100" zu machen... mit "WTF" hat dies also nix zu tun!

=> Mein Vertrauen in die math. & logische Hierarchie der Operatoren von Pascal ist leider etwas getrübt, denn wenn man von C/C++ kommt ist das in Pascal bei AND & OR ständig nötige Klammern, weil hier kein "And vor Or" gilt sehr lästig... für mich echt vergleichbar dem wenn der Compiler nicht Punkt vor Strich rechnen könnte... daher klammere ich zur Sicherheit in Pascal eben da wo es mir drauf ankommt noch etwas mehr wie in C/C++.


Hier im Fall wird es nicht "richtiger", sondern WorstCase falsch, auch wenn mathematisch oder mit Fließkomma es an sich hier völlig egal ist ob man erst multipliziert oder erst dividiert.

Bei Ganzzahl-Arithmetik spielt es eben doch eine Rolle, denn wir haben in diesem Fall einen begrenzten Rechenwertebereich von 32Bit, jeder Operator hat einen Wertebereich von zum Glück nur 8Bit, das heißt dann hier im Detail für ein mathematisch eigentlich identisches Beispiel:

128 div 256 * 100 = !0! weil (128 div 256) * 100 = !0!
aber
128*100 div 256 = !50! weil (128*100) div 256 = !50!

Und da finde ich die sicherheitsgeklammerte Schreibweise sehr sinnvoll, weil wenn das keine kurzen Zahlen sondern lange Variablennamen in einer Kette von Operatoren sind, erschließt sich ohne Klammern die Konsequenz falscher Rechenreihenfolge nicht mehr jedem Codebetrachter sofort.

Dejan Vu 23. Nov 2014 18:23

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Es wird von links nach rechts ausgewertet, da werden keine Klammern benötigt. So einfach kann die Sinnlosigkeit der 'Sicherheitsklammern' zusammenfassen. Der Compiler macht das so. Genau so. Jedes mal. Bei C(++) mögen deine Sicherheitsklammern ja sinnvoll sein, aber bei Delphi nicht.

Dein fehlendes Vertrauen könntest Du durch einmaliges Ausprobieren aufbauen, aber dazu bist Du ja leider zu faul (deine Worte). Daher meine Bitte: Verbreite aber deine Faulheit und deine dadurch bedingte Unsicherheit nicht weiter, insbesondere nicht durch Tipps, wie 'Sicherheitsklammern'. Klammen sind entweder sinnvoll oder sinnlos. 'Zur Sicherheit' werden diese nicht benötigt. Zur Lesbarkeit: Jeder mathematisch halbwegs versierte Programmierer wird hier WTF rufen, denn alles, was überflüssig ist, ist eben 'falsch' (weil überflüssig). Lies mal Bücher über sauberes Programmieren, und was genau den Unterschied zwischen einem sauberen Programm und Schrottcode ausmacht (nämlich genau der WTF-Faktor).

Was Du natürlich in deiner Freizeit und privat auf deinem Rechner machst, bleibt Dir überlassen. Klammere ruhig zu viel als zu wenig. Wie wäre es noch mit Sicherheitsblöcken à la "Begin End" (man kann ja nie wissen)? Oder doppelte Zuweisungen, damit es richtig hält. :stupid:

Daniel 23. Nov 2014 18:38

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
... Grundgütiger - was für eine schroffe Zurechtweisung. War die in dieser Schärfe tatsächlich nötig?
Sei Dir bitte bewusst, dass es sich hier um Deine Meinung handelt - ich beispielsweise finde sehr wohl, dass sinnvoll gesetzte Klammern zur Lesbarkeit beitragen können, selbst wenn sie mathematisch nicht erforderlich sind.

himitsu 23. Nov 2014 19:53

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Zitat:

Es wird von links nach rechts ausgewertet, da werden keine Klammern benötigt.
Njain, Gleichrangiges wird von links nach rechts ausgewertet.

Klammer haben Vorrang vor Allem, dann kommt nacheinander die Gruppe der unären Operatoren
Delphi-Quellcode:
@ not
, dann die Multiplitationsoperatoren
Delphi-Quellcode:
* / div mod and shl shr as
, danach die Additionen
Delphi-Quellcode:
+ - or xor
und zum Schluß die Vergleichsoperationen
Delphi-Quellcode:
= <> < > <= >= in is
dran,
so wie man es aus dem Matheunterricht kennt. (Klammer, Multiplikation/Division und Addition/Subtraktion)

Gut, hier sind * / div und shr gleichrangig, dann stimmt die Aussage zufällig.


Und ja, ich mache Klamern auch nur dann, wenn es nötig ist, somit fällt gleich auf, was los ist und man wird nicht unnötig abgelenkt,
aber Andere sind sich mit der Reihenfolge nicht sicher und da sind Klammern dann (für sich) sicherer.

Dejan Vu 24. Nov 2014 06:43

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Zitat:

Zitat von Daniel (Beitrag 1280847)
... Grundgütiger - was für eine schroffe Zurechtweisung. War die in dieser Schärfe tatsächlich nötig?

Nein, nötig war das natürlich nicht. Aber ich kämpfe täglich gegen schlechten Code und da gehen einem manchmal die Gäule durch.
Was Du gut findest, sind aber keine Sicherheitsklammern, sondern Übersichtlichkeitsklammern. Auch 'falsch' (nimm lieber sprechende Zwischenvariablen).... Aber eben I-M-H-O. Das hätte ich stärker betonen müssen.

samso 24. Nov 2014 11:35

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Der Befehl "shr 8" bringt nach meinen Tests gegenüber "div 256" keine Verbesserung, weil der Compiler (zumindestens ab XE4) die 2er Potenz korrekt erkennt und selbstständig aus dem div einen entsprechenden Shift-Befehl macht (logisch/arithmetisch bei Cardinal/Integer).

Dejan Vu 24. Nov 2014 12:29

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
MulDiv könnte etwas bringen, aber -wenn überhaupt- nur marginal.
Was auch helfen könnte: Statt 'RGBA_Unten^[w]....' nur 'RGBA_Unten^...' und am Ende ein 'Inc(RGBA_Unten)'... Damit wird der Zeiger weiter bewegt (ich schätze, automatisch um 4 Bytes).

allgemein sind Array-Zugriffe fast immer etwas langsamer, als Dereferenzierung über einen Pointer und anschließendes Pointer-Increment.

manfred42 24. Nov 2014 17:28

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
Ich hatte mich gestern bei DP angemeldet, weil mich das Thema "Bitmap"
interessiert, ich auch etwas dazu beisteuern kann und ich mich gern an
sachlichen Diskussionen beteilige.

Heute beschleichen mich etwas gemischte Gefühle, wenn ich mir den Verlauf
der Diskussion ansehe. Aus meiner ersten Sicht wirkt das nicht sehr sachdienlich.

Als Praktiker kann ich beim Debuggen des CPU-Codes einschätzen,
welche Eskapaden der Compiler machte und dann am Quellcode schrauben.
um eine 'Linderung' zu versuchen.
Auf diese Weise habe ich ein Antialiasing mit MMX-Assemblercode passabel
hinbekommen.

Ich 'tethere' mit einem Androiden. Es gelingt mir nicht, eine korrekte
Zip-Datei eines kompletten Delphi-Projektes oder ein Refernzbitmap
abzusaugen. Heruntergeladene Zip-Files werden von RAR, AntekZIP
und anderen als inkorrekt abgewiesen.

Was habe ich nicht beachtet?

Harry Stahl 24. Nov 2014 22:33

AW: Geht das noch schneller? - Bitmap-Verrechnung
 
@manfred42:

Habe mal das Zip-Paket (mit einem anderen ZIP-Programm gepackt) an Deine private Mailadresse geschickt, wie gewünscht.


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:28 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz