Gesucht: Der schnellste Weg ein Bild zu pixeln

Übersicht BlitzBasic Allgemein

Neue Antwort erstellen

Merced

Betreff: Gesucht: Der schnellste Weg ein Bild zu pixeln

BeitragFr, Sep 17, 2004 20:29
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich bin momentan dabei einige Routinen zu optimieren um einige Sachen auch auf lahmen Rechnern besser zum laufen zu bringen. Dabei habe ich eine eigene Bild-Laderoutine. Ich lade die Bilddaten (RGB) als Block in eine Bank und pixle sie dann einzeln in ein Image.

So sieht das Pixeln aus:

Code: [AUSKLAPPEN]

LockBuffer ImageBuffer(img)
z = 0
For y = 0 To thohe-1
 For x = 0 To tbreite-1
  g = PeekByte(mem, z)
  z = z + 1
  b = PeekByte(mem, z)
  z = z + 1
  r = PeekByte(mem, z)
  z = z + 1
  WritePixelFast x, y, ((256*256*256*255)+(256*256*r)+(256*g)+b), ImageBuffer(img)
  Next
 Next
UnlockBuffer ImageBuffer(img)


Die einzelnen Variablen sollten einleuchtend sein, gbr ist die Reihenfolge der Farben in diesen Daten (das Ergebnis stimmt).
Die Wurst mit Multiplikationen errechnet den Farbwert.

Weiß jemand einen Weg das schneller zu lösen?

Auch minimale Beschleunigung (auf schnellen Rechnern nicht meßbar Wink ist erwünscht - geht wie gesagt darum das ganze möglichst schnell zu bekommen, vor allem bei größeren Bildern. Dass ich die Multiplikationen vorberechnen kann ist mir grad selber aufgefallen. Sonst noch was?
http://www.starship-battles.de.vu
http://www.venture-interactive.de.vu

BladeRunner

Moderator

BeitragFr, Sep 17, 2004 20:48
Antworten mit Zitat
Benutzer-Profile anzeigen
Ersetze die Multiplikationen durch ihre Ergebnisse (soweit machbar), spart schon ein paar nanosekunden...
Zu Diensten, Bürger.
Intel T2300, 2.5GB DDR 533, Mobility Radeon X1600 Win XP Home SP3
Intel T8400, 4GB DDR3, Nvidia GF9700M GTS Win 7/64
B3D BMax MaxGUI

Stolzer Gewinner des BAC#48, #52 & #92

Travis

BeitragFr, Sep 17, 2004 20:49
Antworten mit Zitat
Benutzer-Profile anzeigen
Code: [AUSKLAPPEN]

WritePixelFast x, y, ((256*256*256*255)+(256*256*r)+(256*g)+b), ImageBuffer(img)


Hier würde ich die Multiplikationen manuell ausrechnen und die Werte direkt eintragen. Dann muss das nicht immer extra berechnet werden.
www.funforge.org

Ich hasse WASD-Steuerung.

Man kann alles sagen, man muss es nur vernünftig begründen können.

Merced

BeitragFr, Sep 17, 2004 20:58
Antworten mit Zitat
Benutzer-Profile anzeigen
Okay. Das hatte ich zwar schon gemeint, aber danke! Noch mehr Ideen? Kann auch gerne ein anderer Ansatz zum Erstellen des Bildes sein - hauptsache es wird noch etwas schneller.

Ein paar Nanosekunden kann man zwar mit Blitz nicht messen aber auf altersschwachen Systemen werden daraus schnell einige Millisekunden und die sind dann schon spürbar Wink

Der etwas verbesserte Code:

Code: [AUSKLAPPEN]

LockBuffer ImageBuffer(img)
z = 0
For y = 0 To thohe-1
 For x = 0 To tbreite-1
  g = PeekByte(mem, z)
  z = z + 1
  b = PeekByte(mem, z)
  z = z + 1
  r = PeekByte(mem, z)
  z = z + 1
  WritePixelFast x, y, ((4278190080)+(65536*r)+(256*g)+b), ImageBuffer(img)
  Next
 Next
UnlockBuffer ImageBuffer(img)
http://www.starship-battles.de.vu
http://www.venture-interactive.de.vu
 

BIG BUG

BeitragFr, Sep 17, 2004 21:05
Antworten mit Zitat
Benutzer-Profile anzeigen
Wieso liest du das Byteweise aus und stöpselst es wieder zusammen... du könntest doch gleich peekint machen(vorsicht Alphakanal berücksichtigen!)
Mit Blitz+ kann man auch direkt auf den Imagebuffer zugreifen was nochmal schneller gehen würde.
B3D-Exporter für Cinema4D!(V1.4)
MD2-Exporter für Cinema4D!(final)

Merced

BeitragFr, Sep 17, 2004 21:20
Antworten mit Zitat
Benutzer-Profile anzeigen
Hmm. Ja, das ist eine gute Idee.

Funktioniert leider nicht, da peekint einen 32-Byte Integer liest, die Datei aber nur 24-Bit Farben enthält. Außerdem ist die Reihenfolge der Daten nicht RGB, sondern GBR, womit das endgültig flachfällt.

Danke trotzdem für den Tipp.

Die Blitz+ Lösung wird wohl nicht funktionieren, da ich Blitz3D verwende.
http://www.starship-battles.de.vu
http://www.venture-interactive.de.vu

Rallimen

Sieger des 30-EUR-Wettbewerbs

BeitragFr, Sep 17, 2004 21:28
Antworten mit Zitat
Benutzer-Profile anzeigen
evt. ist es schneller wenn du erst
Code: [AUSKLAPPEN]
setbuffer imagebuffer (bild)
lockbuffer

und
Code: [AUSKLAPPEN]
writepixelfast x,y,rgb

ohne angabe des Buffers schreibst
muste dann allerdings wieder auf Backbuffer setzten

ich mach mal ebend CodeBeispiel:
Code: [AUSKLAPPEN]
Graphics 800,600,16,1
Delay 100
bild = CreateImage (10,10)

timer = MilliSecs()
   LockBuffer ImageBuffer (bild)
   For i =0 To  10000000
      WritePixelFast 5,5,$FFFFFFFF,ImageBuffer (bild)
   Next
   UnlockBuffer  ImageBuffer (bild)
timer1 = MilliSecs() - timer

timer = MilliSecs()
   SetBuffer  ImageBuffer (bild)
   LockBuffer
   For i =0 To  10000000
      WritePixelFast 5,5,$FFFFFFFF
   Next
   UnlockBuffer
   SetBuffer BackBuffer()
timer2 = MilliSecs() - timer


Print "Variante 1: "+ timer1
Print "Variante 2: "+ timer2
WaitKey
End


Variante 1 = 285
Variante 2 = 185
bei mir ist es schneller
[BB2D | BB3D | BB+]

Merced

BeitragFr, Sep 17, 2004 21:51
Antworten mit Zitat
Benutzer-Profile anzeigen
Karamba!

Nach solchen Tweaks such ich Wink

Auf der Schrottmühle an der ich mich gerade versuche läuft Dein Test folgendermassen:

Variante 1 = 13832 *lol*
Variante 2 = 7400 (ist das älteste was ich gefunden hab: Ein Sellery 400)

Das braucht knapp halb soviel Zeit.

Leider verpufft der Vorteil sehr stark beim Pixeln mit den Daten. Hier die Daten vom Laden eines 512x512 großen Bildes:

Variante 1 = 1668
Variante 2 = 1585

Ist nicht viel aber immerhin hat es dass um etwa 5 % beschleunigt. Danke!

Zu den Daten. Die Werte für Breite und Höhe werden vorher bestimmt. Dann folgen nur noch die reinen unkomprimierten 24-Farbdaten: GBRGBRGBR...

Hier die aktuell schnellste Variante um daraus wieder ein Bild zu machen:

Code: [AUSKLAPPEN]

img = CreateImage(tbreite, thohe)
SetBuffer ImageBuffer(img)
LockBuffer ImageBuffer(img)
z = 0
For y = 0 To thohe-1
 For x = 0 To tbreite-1
  g = PeekByte(mem, z)
  z = z + 1
  b = PeekByte(mem, z)
  z = z + 1
  r = PeekByte(mem, z)
  z = z + 1
  WritePixelFast x, y, ((4278190080)+(65536*r)+(256*g)+b)
  Next
 Next
UnlockBuffer ImageBuffer(img)
SetBuffer BackBuffer()


Noch jemand eine gute Idee?
http://www.starship-battles.de.vu
http://www.venture-interactive.de.vu

joachim_neu

BeitragFr, Sep 17, 2004 22:03
Antworten mit Zitat
Benutzer-Profile anzeigen
wenn du fertig bist, stell deine routine bitte ins codearchiv!!! sehr gute idee!!!
http://www.joachim-neu.de | http://www.orbitalpirates.de | http://www.middleageworld.de

Rallimen

Sieger des 30-EUR-Wettbewerbs

BeitragFr, Sep 17, 2004 22:36
Antworten mit Zitat
Benutzer-Profile anzeigen
hab da noch etwas was schneller sein sollte....
habs jetzt aber nicht getestetCode: [AUSKLAPPEN]
  WritePixelFast x, y, (($ff000000) + (r Shl 16) + (g Shl 8) + b)
[BB2D | BB3D | BB+]

Merced

BeitragSa, Sep 18, 2004 0:06
Antworten mit Zitat
Benutzer-Profile anzeigen
Hmm. Seeeehr seltsam.

Ich hab den Code mal so mal so laufen lassen. Ergebnis:

Die alte Methode mit Multiplikation hatte folgende Werte:

1585, 1613 und 1606 ms

Deine mit Shl: (Und ja, die alte Berechnung war nicht mit drin)

1621, 1636 und 1590 ms.

Bis auf die 1590 war es mit Shl immer ein bisschen langsamer. Und die 1590 kommen auch nicht an die 1585 ran. Man schließe: Selber rechnen ist in dem Fall sogar schneller als die entsprechende Routine Wink

Ach ja: Hab auch mal beide Hintereinander gehangen (mit einem FreeImage dazwischen nochmal neu aufgebaut). Ergebnis: Unabhängig davon welche Routine ich als zweites verwendet habe - sie war IMMER fast doppelt so schnell wie die erste Berechnung.

@joachim
Kann ich machen, aber ich glaub nicht dass sie vielen was bringt. Der einzige Grund den ich sehe sowas zu pixeln ist ein eigenes Grafikformat und mal ehrlich: Wieviele hier benutzen ein eigenes?

Öhm... *meld*

Übrigens ist mir da noch eine Idee gekommen mit der ich in meinem konkreten Fall zwei Fliegen mit einer Klappe schlagen kann. Ich füge dem Format eine RLE-Kompression hinzu. Dadurch spare ich Platz und muss häufig wiederkehrende Farben nicht zig mal hintereinander berechnen.
http://www.starship-battles.de.vu
http://www.venture-interactive.de.vu

Mr.Keks

BeitragSa, Sep 18, 2004 7:45
Antworten mit Zitat
Benutzer-Profile anzeigen
Gib bitte auch den Bankeinladecode!
Btw. bringen diese ganzen Klammern etwas?!Zitat:
((4278190080)+(65536*r)+(256*g)+b)
MrKeks.net

Merced

BeitragSa, Sep 18, 2004 11:01
Antworten mit Zitat
Benutzer-Profile anzeigen
Öhm, die Klammern haben ursprünglich mal für mehr Übersicht gesorgt. Aber die Testwerte liegen mit oder ohne Klammern etwa gleich. Da die Schwankungen (beim gleichen Test) jeweils bis zu 100 ms betragen ist es schwer es in Stein zu meisseln - seltsamerweise ist es aber in 4 von 5 Versuchen MIT Klammern zwischen 13 und 78 ms schneller gewesen (einmal 10 ms langsamer). Bei einem Zeitrahmen von 1500-1700 Millisekunden für den Bildaufbau.

Hier der Code nochmal mit Bankeinladung: (welcher mit ca 500-600 ms zusätzlich zu Buche schlägt auf dem erwähnten Sellery 400)

Code: [AUSKLAPPEN]

mem = CreateBank(tsize)
hasread = ReadBytes(mem,vgf,0,tsize)
If hasread <> tsize Then Return 0

img = CreateImage(tbreite, thohe)
SetBuffer ImageBuffer(img)
LockBuffer ImageBuffer(img)
z = 0
For y = 0 To thohe-1
 For x = 0 To tbreite-1
  g = PeekByte(mem, z)
  z = z + 1
  b = PeekByte(mem, z)
  z = z + 1
  r = PeekByte(mem, z)
  z = z + 1
  WritePixelFast x, y, (4278190080+(65536*r)+(256*g)+b)
  Next
 Next
UnlockBuffer ImageBuffer(img)
SetBuffer BackBuffer()


Wobei vgf das filehandle ist in dem die Daten stehen und tsize die Größe in Byte.
http://www.starship-battles.de.vu
http://www.venture-interactive.de.vu
 

Black

BeitragSa, Sep 18, 2004 11:47
Antworten mit Zitat
Benutzer-Profile anzeigen
Erm, wenn Blitzbasic einen halbwegs guten Compiler hat, dann sollte zwischen 256*256*256*255 und dem vorberechneten Wert kein Unterschied sein, will normalerweise der Compiler konstante Operationen in Compile-Time ausführt.

Merced

Betreff: Das schnellste Bild gepixelt mit RLE

BeitragSa, Sep 18, 2004 18:15
Antworten mit Zitat
Benutzer-Profile anzeigen
So, nun wirds komplizierter Wink :

Code: [AUSKLAPPEN]

mem = CreateBank(tsize)
hasread = ReadBytes(mem,vgf,0,tsize)
If hasread <> tsize Then Return 0

img = CreateImage(tbreite, thohe)
SetBuffer ImageBuffer(img)
LockBuffer ImageBuffer(img)
z = 0

; ++++++++++++++++++++++++++++++++++++ uncompressed 24-bit image
If t$ = "I24"
 For y = 0 To thohe-1
  For x = 0 To tbreite-1
   g = PeekByte(mem, z)
   z = z + 1
   b = PeekByte(mem, z)
   z = z + 1
   r = PeekByte(mem, z)
   z = z + 1
   WritePixelFast x, y, (4278190080+(65536*r)+(256*g)+b)
   Next
  Next
 EndIf
; ------------------------------------ uncompressed 24-bit image

; ++++++++++++++++++++++++++++++++++++ RLE compressed 24 bit image
If t$ = "I3R"
 counted = 0
 tocount = 0
 For y = 0 To thohe-1
  For x = 0 To tbreite-1
   If counted = tocount ; Next RLE block
    tocount = PeekByte(mem, z)
   z = z + 1
   compressed = False
   If tocount > 127
    compressed = True
    tocount = tocount - 128
     g = PeekByte(mem, z)
     z = z + 1
     b = PeekByte(mem, z)
     z = z + 1
     r = PeekByte(mem, z)
     z = z + 1
    EndIf ; tcount > 127
   tocount = tocount + 1
   counted = 0
    EndIf ; counted = tocount
   If Not compressed   
    g = PeekByte(mem, z)
    z = z + 1
    b = PeekByte(mem, z)
    z = z + 1
    r = PeekByte(mem, z)
    z = z + 1
   EndIf
   WritePixelFast x, y, (4278190080+(65536*r)+(256*g)+b)
   counted = counted + 1
   Next
  Next
 EndIf
; ------------------------------------ RLE compressed 24 bit image
 
UnlockBuffer ImageBuffer(img)
SetBuffer BackBuffer()


t$ ist schlicht der interne Name des Subformats. Das Ergebnis der Einbindung von RLE war wie erwartet. Das hier so oft verwendete Bild von 512x512 ist ein Sternenhintergrund, dementsprechend gut klappt das mit RLE. Wie das RLE-Subformat aufgebaut ist sollte beim Lesen des RLE-Codes klar werden (das Komprimieren ist schwerer als das Anzeigen...)

Vorteile: Die Größe der Bibliothek (die neben diesem Sternenbild bisher nur ein paar winzige Bilder beinhaltet die zusammen 7,6 KB ausmachen) ist von 775 auf 86 KB geschrumpft.
Die Zeit zum Aufbau des Bildes auf erwähntem 400er Sellery ist von durchschnittlich 1563ms auf 1409ms gesunken (also 1/6 Sekunde gespart!) und noch besser: Die Ladezeit (um den Datenblock in den Speicher zu bringen ist von zuvor durchschnittlich 668ms auf 92ms gesunken. Zusammen gibt das eine Zeitersparnis von über 700ms. Dazu kommen noch etwa 100ms durch den Bufferwechsel, den Rallimen empfohlen hat und ein paar andere kleine Tweaks. Gesamtersparnis seit Öffnung des Threads: ca 850ms für den Aufbau des Bildes Wink

Danke an alle die was dazu beigetragen haben!

Noch jemand eine Idee wie noch mehr rauszuholen ist?Wink

@Black Da hast Du sicherlich recht. Hast Du es mal ausgemessen?
http://www.starship-battles.de.vu
http://www.venture-interactive.de.vu

soli

BeitragSa, Sep 18, 2004 19:16
Antworten mit Zitat
Benutzer-Profile anzeigen
Habs jetzt nicht komplett durchgelesen.
Nur das hier
4278190080+(65536*r)+(256*g)+b)
ist doch eine ständig wiederkehrende Berechung,
oder habe ich mich verguckt?

Warum berechnest du das nicht einmal vor Beginn
der Schleife und schreibst das Ergebnis in ein Array?

Pseudo:

Dim gwert(255)
Dim rwert(255)

For laufvari=0 to 255
gwert(laufvari) = 256*laufvari
rwert(laufvari) = 65536*laufvari
next
solitaire

Merced

BeitragSa, Sep 18, 2004 22:49
Antworten mit Zitat
Benutzer-Profile anzeigen
Hmm. Ja, ist eine gute Idee, soli.

Hab es mal getestet kam aber auf Werte jenseits der 2000 ms. Da schien es langsamer zu sein, doch dann hab ich die alten nochmal getestet und da waren es plötzlich über 3000 *bg*

Muss den Rechner mal neu starten, aber das dauert bei der Schleuder immer so lange. Wenn ich einen realistischen Vergleich hab sag ich nochmal Bescheid. Danke für den Tipp Wink

Gruß
Merced
http://www.starship-battles.de.vu
http://www.venture-interactive.de.vu

soli

BeitragSo, Sep 19, 2004 0:22
Antworten mit Zitat
Benutzer-Profile anzeigen
Es kann halt niemand anders testen,
wenn er nicht deine spezielle Datei hat.
Sad

Aber es muss schneller sein.
Es stehen 512 Berechnungen
gegen -zig Tausende.
solitaire

Merced

BeitragSo, Sep 19, 2004 1:58
Antworten mit Zitat
Benutzer-Profile anzeigen
Also nach einem kompletten Neustart des Rechners und allen Hintergrund-Programmen ausgeschaltet bekomme ich folgende Messwerte (jeweils 3 Testläufe) für den Aufbau des Bildes im Speicher:

Ohne Vorberechnung: 1383ms, 1360ms, 1336ms
MIT Vorberechnung: 1339ms, 1347ms, 1340ms

Zweimal schneller, einmal langsamer. Wobei man natürlich berücksichtigen muss dass es dabei eine erhebliche Messungenauigkeit gibt. Es scheint schneller zu sein, aber der Vorteil ist verschwindend gering, sofern er nicht durch Messungenauigkeit zustande kommt.

Wie sich das erklärt? Keine Ahnung. Vielleicht ist Blitz schlau genug zu merken wenn oft dasselbe berechnet wird. Immerhin sind die meisten Pixel eher schwarz, da das Bild ein Sternenhintergund ist. Vielleicht ist der Unterschied zwischen Zugriff auf ein Array und erneute Berechnung auch wirklich nur so marginal.

Wie auch immer, hier der neue Code:

Code: [AUSKLAPPEN]

; ------ PreCalcs
Dim precalcr(255)
Dim precalcg(255)
For z = 0 To 255
 precalcr(z) = 4278190080+(65536*z)
 precalcg(z) = 256*z
 Next


...


mem = CreateBank(tsize)
hasread = ReadBytes(mem,vgf,0,tsize)
If hasread <> tsize Then Return 0

img = CreateImage(tbreite, thohe)
SetBuffer ImageBuffer(img)
LockBuffer ImageBuffer(img)
z = 0

; ++++++++++++++++++++++++++++++++++++ uncompressed 24-bit image
If t$ = "I24"
 For y = 0 To thohe-1
  For x = 0 To tbreite-1
   g = PeekByte(mem, z)
   z = z + 1
   b = PeekByte(mem, z)
   z = z + 1
   r = PeekByte(mem, z)
   z = z + 1
   WritePixelFast x, y, (precalcr(r)+precalcg(g)+b)
   Next
  Next
 EndIf ; I24
; ------------------------------------ uncompressed 24-bit image

; ++++++++++++++++++++++++++++++++++++ RLE compressed 24-bit image
If t$ = "I3R"
 counted = 0
 tocount = 0
 For y = 0 To thohe-1
  For x = 0 To tbreite-1
   If counted = tocount ; Next RLE block
    tocount = PeekByte(mem, z)
   z = z + 1
   compressed = False
   If tocount > 127
    compressed = True
    tocount = tocount - 128
     g = PeekByte(mem, z)
     z = z + 1
     b = PeekByte(mem, z)
     z = z + 1
     r = PeekByte(mem, z)
     z = z + 1
    EndIf ; tcount > 127
   tocount = tocount + 1
   counted = 0
    EndIf ; counted = tocount
   If Not compressed   
    g = PeekByte(mem, z)
    z = z + 1
    b = PeekByte(mem, z)
    z = z + 1
    r = PeekByte(mem, z)
    z = z + 1
   EndIf ; not compressed
   WritePixelFast x, y, (precalcr(r)+precalcg(g)+b)
   counted = counted + 1
   Next
  Next
 EndIf ; I3R
; ------------------------------------ RLE compressed 24-bit image
 
UnlockBuffer ImageBuffer(img)
SetBuffer BackBuffer()


Noch jemand Ideen? Wink
http://www.starship-battles.de.vu
http://www.venture-interactive.de.vu
 

BIG BUG

BeitragSo, Sep 19, 2004 18:53
Antworten mit Zitat
Benutzer-Profile anzeigen
Naja, diese kleinen Berechnungen zerren nicht soviel Speed und ein Lookup in einem Array kostet halt auch seine Zeit.
B3D-Exporter für Cinema4D!(V1.4)
MD2-Exporter für Cinema4D!(final)

Neue Antwort erstellen


Übersicht BlitzBasic Allgemein

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group