Imagedarstellung beschleunigen, aber wie?

Anfängerfragen zum Programmieren mit PureBasic.
hollimaus
Beiträge: 6
Registriert: 05.02.2006 15:52
Wohnort: Tief im Westen

Imagedarstellung beschleunigen, aber wie?

Beitrag von hollimaus »

Hallo zusammen,

ich habe ein kleinen "Grafikprogramm" erstellt, welches auf Basis einer 50x50-Matrix ein Raster darstellt, und zwar im Grundzustand mit 50 x 50 weißen Images mit einer Größe von 10x10Pixel je Images. Wenn eines dieser 10x10-Pixel-Images angeclickt wird, ändert es die Farbe in schwarz (und umgekehrt). So weit so gut.

Jetzt soll das Programm aber auch die Möglickeit haben, die Matrix zu verändern, maximal 200 Kästchen breit und ca. 100 Kästchen hoch.

Das funktioniert auch, allerdings, und hier kommt das Problem, dauert das ziemlich lange, bis die Matrix von 200x100 Images aufgebaut und dargestellt wird.

Gibt es hier eine elegante Möglichkeit, um diesen Aufbau zu beschleunigen?

Hier ist der Code:

Code: Alles auswählen

 musterbreite.w
  musterhoehe.w
  nummer.w
  
  musterbreite=50
  musterhoehe=50
  nummer=1
  
  Dim muster_bit.s(200,100)
  
 
  If OpenWindow(0, 0, 0, 50, 50,#PB_Window_TitleBar|#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget|#PB_Window_SystemMenu|#PB_Window_ScreenCentered, "KnitAs - Assistent zum Erstellen und Bearbeiten von Strickmustern")
      
       LoadImage(0,"d:\privat\purebasic\schwarz.bmp") And LoadImage(1,"d:\privat\purebasic\weiss.bmp") 
      
  neu:
          
       CreateGadgetList(WindowID(0))
    
      ScrollAreaGadget(0,0,0,800,600,1000, 1000,10)
        OpenGadgetList(0) 
             For y=0 To musterhoehe-1 
              For I=0 To musterbreite-1
                ImageGadget(nummer,i*10,y*10,10,10,UseImage(1))
                nummer=nummer+1
              Next i
            Next y
      CloseGadgetList() 
            
           
           For y=0 To musterhoehe-1     ;array einlesen 
              For I=0 To musterbreite-1
                muster_bit(i,y)="1"
              Next i
            Next y
        
 Repeat : EventID = WaitWindowEvent() 
        
        If eventid=#PB_EventGadget
      
            ;-----------Berechnung, welches MusterBit verändert werden muss--------------------
              ausgewaehltes_bild.w=EventGadgetID()-1
              ;-------welche reihe?---------------------
              reihe.w=Int(ausgewaehltes_bild/(musterbreite)) 
              ;-------welche Position?
              position.w=ausgewaehltes_bild-(musterbreite*reihe)
               
           Select muster_bit(reihe,position)      ;neuen images setzten 1->0 oder 0->1
              Case "0"
              muster_bit(reihe,position)="1"
              OpenGadgetList(0)
              ImageGadget(EventGadgetID(),position*10,reihe*10,10,10,UseImage(1))
              CloseGadgetList()      
              
              Case "1"
              muster_bit(reihe,position)="0"
              OpenGadgetList(0)
              ImageGadget(EventGadgetID(),position*10,reihe*10,10,10,UseImage(0))
              CloseGadgetList()
            
            EndSelect
 
 EndIf
 Until EventID = #PB_Event_CloseWindow
  EndIf
Danke vorab.

LG
Benutzeravatar
Dostej
Beiträge: 529
Registriert: 01.10.2004 10:02
Kontaktdaten:

Beitrag von Dostej »

Sorry, der Code ist nicht für 4.0, kann ihn daher nicht testen.
Einfach mal als Vorschlag:
Probiers doch mit Windowedscreen und Sprites. Das Sollte deutich schneller gehen als per Image.
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

habs mal versucht zu testen, bekomme natürlich einen fehler, weil ich die grafiken nicht hab...

aber der fehler kommt bei UseImage(), weil du den Load-Befehl nicht checkst.

Code: Alles auswählen

  LoadImage(0,"d:\privat\purebasic\schwarz.bmp") And LoadImage(1,"d:\privat\purebasic\weiss.bmp") 
1. du solltest das in ein If packen, dann ergibt auch das And einen Sinn.
2. verwende keine absoluten pfade, sondern relative.


und dann zum knackpunkt:

als ereignisreaktion öffnest du die gadgetliste, kreierst ein neues gadget, und schließt die liste wieder.
wenn ich dich richtig verstanden habe, reagierst du doch auf einen klick auf ein gadget.
du solltest dieses gadget verändern, anstatt ein neues drüberzumachen.
schließlich löscht du auch kein altes. irgendwann hättest du 37 images übereinander...

ich kann mir vorstellen, dass gerade diese gadgetlist-aktion sehr viel zeit beansprucht.
ein simples ändern des images im bestehenden gadget dürfte wesentlich schneller sein.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
hollimaus
Beiträge: 6
Registriert: 05.02.2006 15:52
Wohnort: Tief im Westen

Beitrag von hollimaus »

@Kaeru Gaman

danke für die Hinweise :)

Allerdings eines habe ich nicht so ganz verstanden. Du schreibst
  • als ereignisreaktion öffnest du die gadgetliste, kreierst ein neues gadget, und schließt die liste wieder.
    wenn ich dich richtig verstanden habe, reagierst du doch auf einen klick auf ein gadget.
    du solltest dieses gadget verändern, anstatt ein neues drüberzumachen.
    schließlich löscht du auch kein altes. irgendwann hättest du 37 images übereinander...
Ich greife doch mit

Code: Alles auswählen

ImageGadget(EventGadgetID(),position*10,reihe*10,10,10,UseImage(1)) 
auf ein vorhandenes imagegadget zu, oder nicht?. Diesem imagegadget weise ich doch nur ein neues image zu. Damit dürften sich doch keine "37" gadgets übereinanderstapeln, oder?

Mein Hauptproblem liegt darin, dass, wenn ich z.B. 200x100 Images in einer Schleife aufbauen lasse, dieses sehr lange dauert, also Bild für Bild relativ langsam dargestellt wird. Ob das irgendwie schneller gehen kann, also nicht Bild für Bild (wie früher bei BTX :wink: )

@Dostej
auch an dich danke für den Hinweis :)

Mit Sprites habe ich noch keine Erfahrungen. Ich werde es mal probieren...

LG
Benutzeravatar
PMV
Beiträge: 2765
Registriert: 29.08.2004 13:59
Wohnort: Baden-Württemberg

Beitrag von PMV »

deine Frage bezieht sich doch erst mal nur auf:

Code: Alles auswählen

      ScrollAreaGadget(0,0,0,800,600,1000, 1000,10) 
        OpenGadgetList(0) 
             For y=0 To musterhoehe-1 
              For I=0 To musterbreite-1 
                ImageGadget(nummer,i*10,y*10,10,10,UseImage(1)) 
                nummer=nummer+1 
              Next i 
            Next y 
      CloseGadgetList()
Du erstellst 50 X 50 ImageGadgets, das ist für Windows zu viel und
braucht seine Zeit, um dargestellt zu werden.
Wenn du ein sofortiges darstellen haben möchtest, musst du das anders
lösen.

Ich denke da an ein einzellnes ImageGadget. Du hast ein großes Image
und erstellst in der selben größe das ImageGadget. Wäre dann hier also
500 X 500 da ja die grundmaße eines 10X10 ist :D (50 * 10 = 500)

Jetzt überprüfst du, wo sich die Maus befindet und wenn auf dein Gadget
geklickt wird malste auf dein Image an der stelle das andersfarbige kleine
Image hin und weist es wieder dem ImageGadget zu.

Das sollte wesentlich schneller sein, allerdings natürlich auch für einen
Anfänger nicht ganz so leicht ... im zweiflesfalle fragste halt noch mal,
wird sich sicher wer arbarmen dir das genauer zu erklären <)

Und um ein ImageGadget ein neues Image zuzuweisen nutzte den Befehl
SetGadgetState(), siehe Hilfe :wink:

MFG PMV
alte Projekte:
TSE, CWL, Chatsystem, GameMaker, AI-Game DLL, Fileparser, usw. -.-
Benutzeravatar
Xaby
Beiträge: 2144
Registriert: 12.11.2005 11:29
Wohnort: Berlin + Zehdenick
Kontaktdaten:

Hier mein Beitrag dazu

Beitrag von Xaby »

:mrgreen: Ich hatte ein ähnliches Problem, war auch alles zu langsam. Hier ein Ergebnis, bei dem ich mit der Geschwindigkeit ganz zu frieden bin. Ihr müsst natürlich die beiden QuellBilder entprechend anpassen

Code: Alles auswählen

;{- Information
;/ FLEffects by Folker Linstedt
; 
; Anfang: 18.12.2005
; Stand : 18.12.2005
;
;}/

InitSprite(): ;InitSprite3D()

Global GraphicOutPutX.l
Global GraphicOutPut.l

Global MaxX.l
Global MaxY.l

Global Ani1.w

MaxX=640
MaxY=480

Dim Teile.w(31,31, 2)     ; Teile, Sprites, Bild 1 und 2
Dim Alpha.w(31,31,20)  ; 20 Bilder Blendung, In Ani1.PNG
Dim Posit.w(31,31,20,1); 20 Bilder Position, In Ani1.TXT 0 = X, 1 = Y

OpenWindow(1,0,0,660,660,#PB_Window_ScreenCentered|#PB_Window_SystemMenu,"(c) Folker Linstedt 2005, Erschaffen am 19.12.2005:  . . . . FLEffekte . . . . V.0.0.4 PreAlpha >> Blending2")

GraphicOutPutX= 10;
GraphicOutPutY=100;


OpenWindowedScreen(WindowID(),GraphicOutPutX,GraphicOutPutY,MaxX,MaxY,0,0,0)

UsePNGImageDecoder()
UsePNGImageEncoder()
UseJPEGImageDecoder()

StartDrawing(ScreenOutput())
Locate(20,20)
FrontColor(100,255,100)
DrawingMode(1)
DrawText("Bilder werden gezerrt und gespeichert ... Bitte Geduld")
StopDrawing()
FlipBuffers()

For i=1 To 2; Ein Image laden und Resize benutzen, um daraus ein Sprite zu machen
If LoadSprite(i, "temp"+Str(i)+".png",#PB_Sprite_Texture)=0
 LoadImage(0,"bild"+Str(i)+".jpg")  
 ResizeImage(0,MaxX,MaxY,#PB_Image_Smooth)
 SaveImage(0,"temp"+Str(i)+".png",#PB_ImagePlugin_PNG)
 FreeImage(0)
 LoadSprite(i, "temp"+Str(i)+".png",#PB_Sprite_Memory)
EndIf
Next

If LoadImage(0,"Ani1.png")=0
  CreateImage(0,640,32)
  Ani1=0
Else
  Ani1=1
  EndIf

DisplaySprite(2,0,0)
FlipBuffers()

For y=0 To 31
  For x=0 To 31
    Teile(x,y,2)=32*y+x+2000
    Posit(x,y,0,0)=x*20
    Posit(x,y,0,1)=y*15
    GrabSprite(Teile(x,y,2),20*x,15*y,20,15,#PB_Sprite_Memory)
    ;Alpha(x,y)=255
  Next
Next

DisplaySprite(1,0,0)
FlipBuffers()

For y=0 To 31
  For x=0 To 31
    Teile(x,y,1)=32*y+x+4000
    Posit(x,y,0,0)=x*20
    Posit(x,y,0,1)=y*15
    GrabSprite(Teile(x,y,1),20*x,15*y,20,15,#PB_Sprite_Memory)
    ;Alpha(x,y)=255
  Next
Next
 

;/ Berechnung der Positionen
Procedure Berechnung(b.l)
  
  yR=Random(10)*10-50
  xR=Random(1)
  R3=1+Random(100)*0.01
  Rx=Random(620)
  Ry=Random(475)
  
  
  If xR=1 : R=1: Else : R=-1: EndIf
  
  If Ani1=0 And b=10 : b=0: EndIf
  
UseImage(0)  
StartDrawing(ImageOutput())  
For i=0 To 20
 For y=0 To 31
  For x=0 To 31
    If b=0 
      Posit(x,y,i,0)=20*x-MaxX+32*i
      Posit(x,y,i,1)=15*y  
      Alpha(x,y,i)=Round(12.75*i,0)
    EndIf
    If b=1 
      Posit(x,y,20-i,0)=20*x-32*i
      Posit(x,y,20-i,1)=15*y  
      Alpha(x,y,  i)=Round(12.75*i,0)
    EndIf
    If b=2
      Posit(x,y,20-i,0)=20*x
      Posit(x,y,20-i,1)=15*y
      Alpha(x,y,i)=Round(12.75*i,0)
    EndIf
    If b=3
      If x<16: Posit(x,y,20-i,0)=20*x-17*i: Else
        Posit(x,y,20-i,0)=20*x+17*i
      EndIf
      If y<16: Posit(x,y,20-i,1)=15*y-10*i: Else
        Posit(x,y,20-i,1)=15*y+10*i
      EndIf
      Alpha(x,y,i)=255 
    EndIf
    If b=4
      Posit(x,y,20-i,0)=20*x
      Posit(x,y,20-i,1)=15*y*i
      Alpha(x,y,i)=Round(12.75*i,0)
    EndIf 
    If b=5
      Posit(x,y,20-i,0)=20*x*i
      Posit(x,y,20-i,1)=15*y*i
      Alpha(x,y,i)=Round(12.75*i,0)
    EndIf
    If b=6
      Posit(x,y,20-i,0)=20*x
      Posit(x,y,20-i,1)=15*y+(i-1)*(x+32)
      Alpha(x,y,i)=255
    EndIf 
    If b=7
      If x<16: Posit(x,y,20-i,0)=20*x+(15-x)*i: Else
        Posit(x,y,20-i,0)=20*x-(-16+x)*i
      EndIf
      If y<16: Posit(x,y,20-i,1)=15*y+(15-y)*i: Else
       Posit(x,y,20-i,1)=15*y-(-16+y)*i
      EndIf
      Alpha(x,y,i)=Round(12.75*i,0)
    EndIf 
    If b=8
      Posit(x,y,20-i,0)=Round(20*x+Sin(y*i)*R3,0)
      Posit(x,y,20-i,1)=15*y
      Alpha(x,y,i)=Round(12.75*i,0)
    EndIf 
    If b=9
      
      If i=0
      Posit(x,y,20-i,0)=20*x
      Posit(x,y,20-i,1)=15*y
      Else
        Posit(x,y,20-i,0)=Round((Posit(x,y,21-i,0)+Rx)/2,0)
        Posit(x,y,20-i,1)=Round((Posit(x,y,21-i,1)+Ry)/2,0)
      EndIf
    
      Alpha(x,y,i)=Round(12.75*i,0)
    EndIf 
    If b=10
      Posit(x,y,20-i,0)=20*x
      Posit(x,y,20-i,1)=15*y
      Alpha(x,y,i)=Red(Point(x+32*i,y))
    EndIf
    If b>10
      Posit(x,y,20-i,0)=20*x+32*i*R
      Posit(x,y,20-i,1)=15*y+yR*i  
      Alpha(x,y,i)=255
    EndIf
   Next
 Next
Next
StopDrawing() 
  
EndProcedure


;CreateSprite3D(1,1)
;CreateSprite3D(2,2)

;Sprite3DQuality(1)

Durchlauf=0
Richtung=1
Bild=0
Berechnung(0)

If ReadFile(0,"Folki ist cool.txt")<>0
     Zufall=1
     Pause=15
  Else
    Zufall=0
    Pause=500
  EndIf
  
 
Repeat
  
  Event.l = WindowEvent() 
   
  ;/ die schnellste Methode, aber nicht sonderlich schoen und noch haesslicher, wenn SpriteQuality(0)
  ;Start3D()
  ;DisplaySprite3D(1,0,0,255-Alpha)
  ;ZoomSprite3D(2,640,480)
  ;DisplaySprite3D(2,0,0,Alpha) 
  ;Stop3D()
  
  ;/ Langsamer, aber viel viel huepscher
  
   
  StartSpecialFX()
  DisplaySprite(1,0,0)
  For y=0 To 31
    For x=0 To 31
       DisplayTranslucideSprite(Teile(x,y,2),Posit(x,y,Bild,0),Posit(x,y,Bild,1),Alpha(x,y,Bild)) 
    Next
  Next
  
  StopSpecialFX()
  
  
  
  Bild+Richtung 
  
  If Bild>20: Bild=20: Richtung*-1: Durchlauf+1 : EndIf
  If Bild<0  : Bild=  0: Richtung*-1: EndIf
  
  If Durchlauf=1
    Durchlauf=0
    If Zufall=1 :Berechnung(Random(13)+1): Else: Berechnung(0): EndIf
    ;Berechnung(10)
  EndIf
  
 
  FlipBuffers()
  ;ClearScreen(0,0,0)
  Delay(Pause)
  
Until Event=#PB_Event_CloseWindow
CloseFont(1)
Wenn es dann noch nicht geht, vielleicht die Zeile:

Code: Alles auswählen

If ReadFile(0,"Folki ist cool.txt")<>0
ausklammern :D

Ansonsten dürftet ihr schon gefallen dran finden. Man kann auch die
"Ani1.png" selbst machen. In dem Bild ist eine Animation gespeichert.
Helle Farben ist sichtbarer, dunklere Farben sind weniger sichtbar.
Ein komplett schwarzes Bild zeigt das erste Bild Temp1.
Ein komplett weißes Bild zeigt das zweite Bild Temp2

Das Prinzip sollte klar sein. Man kann es natürlich noch erweitern. Das war nur eine Möglichkeit, um schnell eigene Übergänge zu konstruieren, ohne den Quellcode wirkliche verstehen zu müssen /:->
Das Ding nimmt auch nur zwei Bilder, also nicht fortlaufend alle aus einem Ordner oder so. War nur ein Test, wie man eine SlideShow hüpsch machen könnte.


Ani*.txt sollte dann eine Erweiterung werden, dass man auch richtige Animationen machen kann. Also das die Teilchen sich auch bewegen und nicht nur geblendet werden. Aber hab das Projekt nicht weiter ausgebaut, mich mit anderen Dingen beschäftigt. Vielleicht macht's ja jemand weiter. :allright:

Vielleicht kann ja jemand was mit anfangen.

Netten Gruß, Folker :shock:
Kinder an die Macht http://scratch.mit.edu/
Benutzeravatar
PureLust
Beiträge: 1145
Registriert: 21.07.2005 00:02
Computerausstattung: Hab aktuell im Grunde nur noch 'nen Lenovo Yoga 2 Pro im Einsatz.
Wohnort: am schönen Niederrhein

Beitrag von PureLust »

Hallo Zusammen, ...

beim Umsetzen des Codes von Hollimaus nach PB4 ist mir vom Debugger ein seltsamer Laufzeit-Fehler gemeldet worden:

#Gadget object number is very high (over 10000), are You sure of that?

Hollimaus scheint diese Meldung ja mit seiner älteren PB-Version nicht bekommen zu haben - daher meine Frage:

Ist diese Limitierung auf 10000 Gadgets neu ??? :o

Greetz & ThanX,
PureLust.


PS. @ Hollimaus:
Wenn Du das ScrollAreaGadget VOR dem erstellen der ganzen ImageGadgets unsichtbar machst und erst nach dem Erstellen der ImageGadgets wieder sichtbar machst (per HideGadget(..)), so beschleunigt sich der Aufbau teilweise erheblich.
Nichtsdestotrotz ist die von Dir gewählte Methode mit tausenden von ImageGadgets nicht unbedingt der beste Lösungsansatz für solch eine Problemstellung. ;)
[Dynamic-Dialogs] - komplexe dynamische GUIs einfach erstellen
[DeFlicker] - Fenster flimmerfrei resizen
[WinFX] - Window Effekte (inkl. 'durchklickbares' Window)
Benutzeravatar
edel
Beiträge: 3667
Registriert: 28.07.2005 12:39
Computerausstattung: GameBoy
Kontaktdaten:

Beitrag von edel »

Nein , ist sie nicht , du musst ein Fehler gemacht haben.

Der Code ist nen bisschen dreckig und fuer 4.0 b11 :-)

Code: Alles auswählen

  global w.l = 800 , h.l = 600 , size.l = 10
  global old.l , Dim map(w/size,h/size)
  
  Procedure mapProc(hwnd,msg,wP,lP)
    Protected hdc.l ,i.l , x.l , y.l
    Protected ps.PAINTSTRUCT , id.l , pen.l
    
    IF #WM_LBUTTONDOWN = msg ; linke maustaste setzen und loeschen
      map((lp & $FFFF)/size,((lp >> 16) & $FFFF)/size) ! #true 
      InvalidateRect_(hwnd,0,0)
    endif
    
    IF #WM_PAINT = msg
      
      if isimage(0) = 0
        CreateImage(0,w,h)
      endif 
      
      hdc = StartDrawing(ImageOutput(0))
      
      SelectObject_(hdc,GetStockObject_(#WHITE_BRUSH)) 
      Rectangle_(hdc,0,0,w,h) 
      pen = createpen_(#PS_SOLID,1,$FAFAFA)
      SelectObject_(hdc,GetStockObject_(#BLACK_BRUSH))  
      SelectObject_(hdc,pen)
      
      For i = 0 To w/size -1 
        MoveToEx_(hdc,i*size,0,0)   ; horizontale linien
        lineto_(hdc,i*size,h)       ; horizontale linien
        For j = 0 To h/size -1
          MoveToEx_(hdc,0,j*size,0) ; vertikale linien
          lineto_(hdc,w,j*size)     ; vertikale linien
          if map(i,j) 
            Rectangle_(hdc,i*size,j*size,size+i*size,size+j*size)  ; kaestchen malen
         endif 
        Next
      Next 
      
      StopDrawing()
      
      brush = CreatePatternBrush_(ImageID(0)) 
      hdc   = BeginPaint_(hwnd,@ps.PAINTSTRUCT)
      
      SelectObject_(hdc , brush)
      Rectangle_(hdc,0,0,w,h)
      
      EndPaint_(hwnd,@ps)
      DeleteObject_(brush)
      DeleteObject_(pen)
    ELSE
      ProcedureReturn CallWindowProc_(old,hwnd,msg,wP,lP)
    ENDIF  
    
  EndProcedure
  
  *hWindow.long = OpenWindow(#PB_Any,0,0,w,h,"blub") : CreateGadgetList(*hWindow\l)
  
  *map.long = ContainerGadget(#pb_any,0,0,w,h) 
  
  old = SetWindowLong_(*map\l,#GWL_WNDPROC,@mapProc())

  Repeat : Until WaitWindowEvent() = #WM_CLOSE
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

Hi @ all, ich habe auch mal eine Frage zur BEschleunigung!

Meine Bildschirmauflösung beträgt 1280x1024; aus diesem Code habe ich den COde übernommen, um auf dem Desktop zu zeichnen.

Ich gehe mit 2 FOR-Schleifen, eine für die x- eine für die y-Achse, jeden Pixel des Bildschirms durch und lasse mit Plot(x, y, 16777215-Point(x, y)) (oder so ähnlich) alle Pixel invertieren; warum ist dieser Vorgang so langsam?

Ich kann förmlich mitbeobachten, wie jeder Pixel einzeln invertiert wird, obwohl ich kein Delay() verwende. Ich hatte wenigstens gedacht, dass mehrere zeile auf einmal invertiert werden, aber nööö. Der Unterschied ist deutlich erkennbar.
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
hollimaus
Beiträge: 6
Registriert: 05.02.2006 15:52
Wohnort: Tief im Westen

Beitrag von hollimaus »

@PureLust

Die Fehlermeldung

#Gadget object number is very high (over 10000), are You sure of that?

bekomme ich bei meiner 3.94-Version auch unter Verwendung des Debugger. Wenn ich ohne Debugger kompiliere, läuft das Programm durch. Ist wahrscheinlich nur ein Hinweis, der nicht zum Programmstop führt ?!

LG
Antworten