Seite 1 von 3

rgb zu hsv und zurück beschleunigen?

Verfasst: 28.02.2012 22:59
von The_Dark_Zim-.-
Hey ho

ich versuche gerade eine Texture umfärben su lassen. Klappt soweit ganz gut aber mir ist die ganze sache noch etwas zu langsam. Ich habe ein Bild/Texture von 2048*2048 welche ich umfärben will.
Vllt hat ja der ein oder andere eine Idee wie man es schneller machen kann.

Code: Alles auswählen

Global H.d,S.d,V.d

Procedure RGB_To_HSV(ColorRed.d,ColorGreen.d,ColorBlue.d)
  
  MinColor.d
  MaxColor.d
  
  ColorRed / 255
  ColorGreen / 255
  ColorBlue / 255
  
  If ColorRed < ColorGreen
    MinColor = ColorRed
  Else
    MinColor = ColorGreen
  EndIf
  If MinColor > ColorBlue
    MinColor = ColorBlue
  EndIf
  If ColorRed > ColorGreen
    MaxColor = ColorRed
  Else
    MaxColor = ColorGreen
  EndIf
  If MaxColor < ColorBlue
    MaxColor = ColorBlue
  EndIf
  
  If MaxColor = MinColor
    H = 0
  ElseIf MaxColor = ColorRed
    H = 60 * ((ColorGreen-ColorBlue)/(MaxColor-MinColor))
  ElseIf MaxColor = ColorGreen
    H = 60 * (2+((ColorBlue-ColorRed)/(MaxColor-MinColor)))
  ElseIf MaxColor = ColorBlue
    H = 60 * (4+((ColorRed-ColorGreen)/(MaxColor-MinColor)))
  EndIf
  
  If MaxColor = 0
    S = 0
    H = 0
  Else
    S = (MaxColor-MinColor)/MaxColor
  EndIf
  
  V = MaxColor
  
EndProcedure

Procedure.l HSV_To_RGB()
  
  ColorRed.d
  ColorGreen.d
  ColorBlue.d
  
  If S = 0
    ColorRed = V
    ColorGreen = V
    ColorBlue = V
  Else
    
    hi.d = H/60
    l = Round(hi, #PB_Round_Down)
    f.d = hi-l
    p.d = V * (1-S)
    q.d = V * (1-S*f)
    t.d = V * (1-S*(1-f))
    
    If l = 1
      ColorRed = q
      ColorGreen = V
      ColorBlue = p
    ElseIf l = 2
      ColorRed = p
      ColorGreen = V
      ColorBlue = t
    ElseIf l = 3
      ColorRed = p
      ColorGreen = q
      ColorBlue = V
    ElseIf l = 4
      ColorRed = t
      ColorGreen = p
      ColorBlue = V
    ElseIf l = 5
      ColorRed = V
      ColorGreen = p
      ColorBlue = q
    Else
      ColorRed = V
      ColorGreen = t
      ColorBlue = p
    EndIf
  EndIf
  
  ProcedureReturn Color.l = RGB(ColorRed * 255,ColorGreen * 255,ColorBlue * 255)
EndProcedure

Procedure ChangeColor(Grad)
  
  StartTime = ElapsedMilliseconds()  
  
  If IsImage(1) = 0
    
    LoadImage(1,"media\CarTexture.bmp")
    LoadImage(3,"media\TailLight.png")
    CreateImage(2,ImageWidth(1),ImageHeight(1),ImageDepth(1))
    
    Global Dim Color(ImageWidth(1),ImageHeight(1))
    
    StartDrawing(ImageOutput(1))
    
    For i = 0 To ImageHeight(1)-1
      
      For j = 0 To ImageWidth(1)-1
        
        Color(j, i) = Point(j, i)
        
      Next j
      
    Next
    StopDrawing()
    
  EndIf
  
  i = 0
  j = 0
  
  StartDrawing(ImageOutput(2))
  For i = 0 To ImageHeight(1)-1
    
    For j = 0 To ImageWidth(1)-1
      
      RGB_To_HSV(Red(Color(j,i)),Green(Color(j,i)),Blue(Color(j,i)))
      
      H + Grad
      
      If H < 0
        H + 360
      ElseIf H > 360
        H - 360
      EndIf   
      
      Plot(j,i,HSV_To_RGB())
      
    Next j
    
  Next  
  
  DrawAlphaImage(ImageID(3), 0, 0)
  
  StopDrawing()  
  
  SaveImage(2,"media\NewTexture.bmp",#PB_ImagePlugin_BMP)
  
  Debug ElapsedMilliseconds()-StartTime
EndProcedure
Ja ich habe auch ohne Debuger getestet ^^

Testsystem:
Win7 Ultimate
PB 4.6 x86
Intel Core 2 Duo T5250 @ 1,5ghz
2GB Ram
Nvidia Gforce 8600M GS 256mb

Gruß Zim

Re: rgb zu hsv und zurück beschleunigen?

Verfasst: 28.02.2012 23:04
von WPö
Öööhh. Kenne mich da ja nicht sooo aus, aber ich glaube, das sollte sich mit 'ner GPU doch wohl erheblich beschleunigen lassen. Das gab's doch schon vor ein, zwei Tagen eine Frage zu dem Thema. Such doch mal danach.

Gruß - WPö

Re: rgb zu hsv und zurück beschleunigen?

Verfasst: 28.02.2012 23:08
von The_Dark_Zim-.-
Ja das habe ich gesehen ;) Hab ich auch schon dran gedacht, aber ich denke das an diesem Code auch so noch Verbesserungen möglich sind :)

Re: rgb zu hsv und zurück beschleunigen?

Verfasst: 28.02.2012 23:30
von STARGÅTE
Ich weiß nicht genau ob meins schneller ist, aber ich hatte vor einigen Monaten mal ein paar Proceduren dazu geschrieben, welche die Funktion CustomFilterCallback() nutzen, und damit etwas schneller sein könnten, u.a. auch eine für dein Zweck:
ImageColorRotation(Image.i, Angle.f)
http://www.purebasic.fr/german/viewtopi ... 63#p291263
EInfach das Bild "reinwerfen" und den Winkel angeben, fertig.

Natürlich musst du solche rechenintensiven Funktionen immer ohne Debugger starten, weil der sonst viel Zeit frisst.

Edit: Dein Code könnte schon mal schneller laufen wenn du sowas vermeidest:

Code: Alles auswählen

For i = 0 To ImageHeight(1)-1
Weil dann mit jedem Durchgang erneut das Image "gesucht" wird und die Height - 1 gerechnet wird.
Dann lieber:

Code: Alles auswählen

max_i = ImageHeight(1)-1
For i = 0 To max_i
oder

Code: Alles auswählen

For i = ImageHeight(1)-1 To 0 step -1
weil der For-Parameter nur einmal ausgewertet wird, der To-Parameter hingegen immer.

Re: rgb zu hsv und zurück beschleunigen?

Verfasst: 28.02.2012 23:54
von The_Dark_Zim-.-
Hey

ja wo du es sagst ist natürlich ein blöder Fehler ^^ Hat es bei mir mit Debuger 100ms schneller gemacht :)
ich guck mir mal die Sachen an.

Edit:
So habe mir deins mal durchgeguckt. Sieht in meinen Augen aus wie das Selbe nur kleiner wegen Select und CustomFilterCallback ^^

Re: rgb zu hsv und zurück beschleunigen?

Verfasst: 29.02.2012 01:43
von Thorium
Ich sehe jede Menge Optimierungsmöglichkeiten.
Die offensichtlichste zuerst: Warum überhaupt nach HSV umrechnen und wieder zurück, warum färbst du nicht im RGB-System um?

Dann nutzt du Point, das durch direkten Zugriff auf den Speicher ersetzen. Stichwort: DrawingBuffer

Wenn du die beiden Sachen änderst sollte es minimum 10 fach schneller werden.
The_Dark_Zim-.- hat geschrieben: ja wo du es sagst ist natürlich ein blöder Fehler ^^ Hat es bei mir mit Debuger 100ms schneller gemacht :)
ich guck mir mal die Sachen an.
Immer ohne Debugger testen, nicht nur weil ersn unnötig verlangsamt, sondern er verfälscht auch das Ergebnis, da verschiedener Code unterschiedlich durch den Debugger verlangsamt wird.

Re: rgb zu hsv und zurück beschleunigen?

Verfasst: 29.02.2012 12:29
von The_Dark_Zim-.-
Ich wandle das ganze zum HSV-Farbbaum um damit ich die Farben gleichmäßig ändern kann. Ich weiss nicht wie ich das nur mit RGB machen soll.

Okey werde mich mal ran machen das mit dem DrawBuffer um zu setzen.

Ich teste doch nur im Debugger um zu sehen ob es überhaupt einen Unterschied gibt ;)
Ich habe doch ganz oben geschrieben das ich auch ohne getestet habe.

Gruß Zim

Edit:

So ich habe das ganze nun auf DrawingBuffer umgestellt. Es schwangt bei mir extrem zwischen ~400 bis ~1700 :|

Achja die Texture hat nur eine Auflösung von 1024*1024 <)

Code: Alles auswählen

Global H.d,S.d,V.d

Structure Pixel
  Pixel.l
EndStructure

Procedure RGB_To_HSV(ColorRed.d,ColorGreen.d,ColorBlue.d)
  
  MinColor.d
  MaxColor.d
  
  ColorRed / 255
  ColorGreen / 255
  ColorBlue / 255
  
  If ColorRed < ColorGreen
    MinColor = ColorRed
  Else
    MinColor = ColorGreen
  EndIf
  If MinColor > ColorBlue
    MinColor = ColorBlue
  EndIf
  If ColorRed > ColorGreen
    MaxColor = ColorRed
  Else
    MaxColor = ColorGreen
  EndIf
  If MaxColor < ColorBlue
    MaxColor = ColorBlue
  EndIf
  
  If MaxColor = MinColor
    H = 0
  ElseIf MaxColor = ColorRed
    H = 60 * ((ColorGreen-ColorBlue)/(MaxColor-MinColor))
  ElseIf MaxColor = ColorGreen
    H = 60 * (2+((ColorBlue-ColorRed)/(MaxColor-MinColor)))
  ElseIf MaxColor = ColorBlue
    H = 60 * (4+((ColorRed-ColorGreen)/(MaxColor-MinColor)))
  EndIf
  
  If MaxColor = 0
    S = 0
    H = 0
  Else
    S = (MaxColor-MinColor)/MaxColor
  EndIf
  
  V = MaxColor
  
EndProcedure

Procedure.l HSV_To_RGB()
  
  ColorRed.d
  ColorGreen.d
  ColorBlue.d
  
  If S = 0
    ColorRed = V
    ColorGreen = V
    ColorBlue = V
  Else
    
    hi.d = H/60
    l = Round(hi, #PB_Round_Down)
    f.d = hi-l
    p.d = V * (1-S)
    q.d = V * (1-S*f)
    t.d = V * (1-S*(1-f))
    
    If l = 1
      ColorRed = q
      ColorGreen = V
      ColorBlue = p
    ElseIf l = 2
      ColorRed = p
      ColorGreen = V
      ColorBlue = t
    ElseIf l = 3
      ColorRed = p
      ColorGreen = q
      ColorBlue = V
    ElseIf l = 4
      ColorRed = t
      ColorGreen = p
      ColorBlue = V
    ElseIf l = 5
      ColorRed = V
      ColorGreen = p
      ColorBlue = q
    Else
      ColorRed = V
      ColorGreen = t
      ColorBlue = p
    EndIf
  EndIf
  
  ProcedureReturn RGB(Colorblue * 255,ColorGreen * 255,Colorred * 255)
EndProcedure

Procedure ChangeColor(Grad)
  
  StartTime = ElapsedMilliseconds()  
  
  If IsImage(1) = 0
    
    Global MaxHeight,MaxWidth
    
    LoadImage(1,"media\CarTexture.bmp")
    LoadImage(3,"media\TailLight.png")
    MaxHeight = ImageHeight(1)
    MaxWidth = ImageWidth(1)
    CreateSprite(2,MaxWidth,MaxHeight)
    
    Global Dim Color(MaxWidth,MaxHeight)

    MaxHeight-1
    MaxWidth-1
    
    StartDrawing(ImageOutput(1))
    
    For i = 0 To MaxHeight
      
      For j = 0 To MaxWidth
        
        Color(j, i) = Point(j, i)
        
      Next j
      
    Next
    StopDrawing()
    
  EndIf
  
  i = 0
  j = 0
  
  StartDrawing(SpriteOutput(2))
  
      Buffer      = DrawingBuffer()             ; Get the start address of the screen buffer
      Pitch       = DrawingBufferPitch()        ; Get the length (in byte) took by one horizontal line
  
  For i = 0 To MaxHeight

    For j = 0 To MaxWidth

      RGB_To_HSV(Red(Color(j,i)),Green(Color(j,i)),Blue(Color(j,i)))
      
      H + Grad
      
      If H < 0
        H + 360
      ElseIf H > 360
        H - 360
      EndIf 
      
      *Line.Pixel = Buffer+(Pitch*i)+(j*4) 
      *Line\Pixel = HSV_To_RGB()
      
    Next j
    
  Next  
  
  DrawAlphaImage(ImageID(3), 0, 0)
  
  StopDrawing()  
  
  SaveSprite(2,"media\NewTexture.bmp",#PB_ImagePlugin_BMP)
  
  MessageRequester("Time",Str(ElapsedMilliseconds()-StartTime))
EndProcedure

Re: rgb zu hsv und zurück beschleunigen?

Verfasst: 29.02.2012 15:28
von Thorium
Die Berechnung der Pixelposition ist zu aufwendig.
Wenn ich heut abend nachhause komme schreib ich dir ne optimale Schleife für DrawingBuffer.
Die Schleife mit Point kanns du dadurch auch ersetzen.

Wie wichtig ist den die Geschwindigkeit dabei? Das ganze würde sich wunderbar parallelisieren lassen. Mit reinem PB könntest du die Arbeit au mehrere Threads aufteilen um alle Cores zu nutzen. Ich würde dafür jedem Thread X Zeilen des Bildes zuweisen.

Hier würde sich auch SSE anbieten aber dafür muss dann Assembler rann.

Re: rgb zu hsv und zurück beschleunigen?

Verfasst: 29.02.2012 16:16
von The_Dark_Zim-.-
Naja das soll für ein spiel sein, was ich entwickeln will. Da will ich das der Benutzer sich die Farbe seines Autos auswählen kann. Dafür will ich dann einfach die Texture ändern und nicht tausende Texturen benutzen.

Re: rgb zu hsv und zurück beschleunigen?

Verfasst: 29.02.2012 16:29
von STARGÅTE
Dann kannst du doch die Texturefarbe direkt ändern:
Sprite3DColor()

Das erspart das Umrechnen und außerdem den zusätzliche Speicher für die geänderten Texturen.