Bilder drehen

Für allgemeine Fragen zur Programmierung mit PureBasic.
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Bilder drehen

Beitrag von ccode_new »

Hallo!

Hat jemand spontan eine schnelle Procedure um Bilder (keine Sprites) zu drehen ?

Also nicht so etwas langsames wie:

Code: Alles auswählen

Procedure RotiereEinBild(bild, richtung)
 Protected i.i, k.i
 Protected rbild.i
 Protected w.i = ImageWidth(bild)
 Protected h.i = ImageHeight(bild)
 Protected Dim p(w,h)
 
  If IsImage(bild)
    
    ;Lese die Pixel
    StartDrawing( ImageOutput(bild) )
      For k=0 To h-1
        For i=0 To w-1
          p(i,k)=Point(i,k)
        Next
      Next
    StopDrawing()
    
    ;Drehrichtung
    If richtung = 0 ;"90° oder Pi/2"
      If w<>h
        Swap w,h
        rbild = CreateImage(#PB_Any,w+1,h+1)
        If IsImage(rbild)
          FreeImage(bild)
        EndIf
      EndIf
      
      StartDrawing( ImageOutput(rbild) )
      For k=0 To h
        For i=0 To w
          Plot(i,k, p(k,w-i))
        Next
      Next
      StopDrawing()
    ElseIf richtung = 1 ;"180° oder Pi"
      rbild = CreateImage(#PB_Any,w+1,h+1)
      If IsImage(rbild)
        FreeImage(bild)
      EndIf
      
      StartDrawing( ImageOutput(rbild) )
      For k=0 To h-1
        For i=0 To w-1
          kk = (h-1)-k
          ii = (w-1)-i
          Plot(i,k, p(ii,kk))
        Next
      Next
      StopDrawing()
    ElseIf richtung = 2 ;"270° oder 3/2 * Pi"
      If w<>h
        Swap w,h
        rbild = CreateImage(#PB_Any,w+1,h+1)
        If IsImage(rbild)
          FreeImage(bild)
        EndIf
      EndIf
      
      StartDrawing( ImageOutput(rbild) )
      For k=0 To h
        For i=0 To w
          kk = (h)-k
          ii = (w)-i
          Plot(i,k, p(kk,ii))
        Next
      Next
      StopDrawing()
    EndIf
 
    ProcedureReturn rbild
  EndIf
EndProcedure
Bitte keine OpenGL-Lösungen mit glScale,... oder Shader wie:

Code: Alles auswählen

uniform sampler2D color_texture;
uniform vec2 resolution;

void main(){
    float angle = 1.570796327; //270°
    vec2 pos = gl_FragCoord.xy/resolution;
    pos.x = 1.0 - pos.x;
    float sin_factor = sin(angle);
    float cos_factor = cos(angle);
    pos = (-pos - 0.5) * mat2(cos_factor, sin_factor, -sin_factor, cos_factor);
    pos += 0.5;

    gl_FragColor = texture2D(color_texture, -pos);
}
Achso noch etwas:

Die Procedure sollte nicht nur mit 32bit Farbtiefe klarkommen, sondern auch mit anderen Farbtiefen (24bit).
Und die Procedure sollte mit hohen Auflösungen (> 20 Megapixel) klarkommen.
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8679
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Re: Bilder drehen

Beitrag von NicTheQuick »

Ich hab das hier gefunden, aber nicht getestet, da das wohl nur unter Windows geht: https://www.purebasic.fr/english/viewto ... 12&t=38975
Bild
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: Bilder drehen

Beitrag von ccode_new »

@Nic

Genial!
(Vor allem die freie Rotation)

-> Nur leider ist meine gepostete Procedure schneller.

nImgOut = RotateImage(nImgSrc, 90)
nImgOut = RotiereEinBild(nImgSrc, 0) ;Ist schneller!
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: Bilder drehen

Beitrag von ccode_new »

Naja, wegen der Vollständigkeit:

Mit Vector-Drawing bin ich am flexibelsten, aber leider noch langsamer.

Code: Alles auswählen

Procedure RotiereEinBild(bild, richtung)
  Protected rbild.i
  If IsImage(bild)
    If richtung = 0
      ;90°
      rbild = Createbild(#PB_Any, ImageHeight(bild), ImageWidth(bild))
      If StartVectorDrawing(ImageVectorOutput(rbild))
        MovePathCursor((ImageWidth(rbild)/2)+(ImageHeight(bild)/2), 0)
        RotateCoordinates(0, 0, 90)
        DrawVectorbild(ImageID(bild))
        StopVectorDrawing()
      EndIf
    ElseIf richtung = 1
      ;180°
      rbild = Createbild(#PB_Any, ImageWidth(bild), ImageHeight(bild))
      If StartVectorDrawing(ImageVectorOutput(rbild))
        MovePathCursor((ImageWidth(rbild)/2)+(ImageWidth(bild)/2), (ImageHeight(rbild)/2)+(ImageHeight(bild)/2))
        RotateCoordinates(0, 0, 180)
        DrawVectorbild(ImageID(bild))
        StopVectorDrawing()
      EndIf
    ElseIf richtung = 2
      ;270°
      rbild = Createbild(#PB_Any, ImageHeight(bild), ImageWidth(bild))
      If StartVectorDrawing(ImageVectorOutput(rbild))
        MovePathCursor(0, ImageHeight(rbild))
        RotateCoordinates(0, 0, 270)
        DrawVectorbild(ImageID(bild))
        StopVectorDrawing()
      EndIf
    EndIf
    ProcedureReturn rbild
  EndIf
EndProcedure
Zuletzt geändert von ccode_new am 21.11.2018 22:08, insgesamt 1-mal geändert.
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: Bilder drehen

Beitrag von ccode_new »

Guten Abend!

Das hier funktioniert auch für verschiedene Zwecke und ist schnell:

Code: Alles auswählen

Procedure PropSize(oldWidth, oldHeight, newWidth, newHeight = #PB_Any)
  If newHeight = #PB_Any
    ProcedureReturn newWidth * oldHeight / oldWidth
  Else
    ProcedureReturn newHeight * oldWidth / oldHeight
  EndIf
EndProcedure

Procedure RotateImage_(img.s, dir, w, h) ;img = Übergabe des Bildpfades
  Protected rspr.i, tmp_rspr.i, rimg.i
  rspr = LoadSprite(#PB_Any, img)
  If IsSprite(rspr)
    ZoomSprite(rspr, PropSize(SpriteWidth(rspr), SpriteHeight(rspr), #PB_Any, h), h)
    If dir = 0
      RotateSprite(rspr, 90, #PB_Absolute)
    ElseIf dir = 1
      RotateSprite(rspr, 180, #PB_Absolute)
    ElseIf dir = 2
      RotateSprite(rspr, 270, #PB_Absolute)
    EndIf
    ClearScreen(RGB(0,0,0))
    DisplaySprite(rspr,(w/2)-(SpriteWidth(rspr)/2), (h/2)-(SpriteHeight(rspr)/2))
    tmp_rspr = GrabSprite(#PB_Any, 0, 0, w, h)
    If IsSprite(tmp_rspr)
      FreeSprite(rspr)
    EndIf
    StartDrawing(SpriteOutput(tmp_rspr))
    rimg = GrabDrawingImage(#PB_Any, 0, 0, SpriteWidth(tmp_rspr), SpriteHeight(tmp_rspr))
    StopDrawing()
    ProcedureReturn rimg
  Else
    Debug "Fehler!"
  EndIf
EndProcedure
,... aber:

Die Renderqualität ist schlechter !!!
Und bei vielen Bildern funktioniert Rotate/Zoom/Grab-Sprite nicht und man erhält leider nur ein weißes Bild.
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
Benutzeravatar
HeX0R
Beiträge: 2960
Registriert: 10.09.2004 09:59
Computerausstattung: AMD Ryzen 7 5800X
96Gig Ram
NVIDIA GEFORCE RTX 3060TI/8Gig
Win10 64Bit
G19 Tastatur
2x 24" + 1x27" Monitore
Glorious O Wireless Maus
PB 3.x-PB 6.x
Oculus Quest 2
Kontaktdaten:

Re: Bilder drehen

Beitrag von HeX0R »

Ich denke mit DrawingBuffer() und co. solltest Du wesentlich schneller sein, als Dein Plot/Point-Gedöns.

[Edit]
Hier gibts sowas:
https://www.purebasic.fr/english/viewtopic.php?p=437885

Weiterlesen! Da sind noch mehr Codes drin.
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: Bilder drehen

Beitrag von ccode_new »

Hallo HeXOR!

Alle von mir getesteten Varianten mit DrawingBuffer() sind nicht schneller/bzw. gleich schnell mit der ersten geposteten Procedure.

Ich glaube die Plot/Point - Funktionen von PureBasic sind schon dahingehend optimiert wurden.

Du bist am Zug mir eine schnellere Procedure zu liefern. ;)

Anbei:
Das mit den weißen Bildern liegt an zu großen Bildern. Diese Texturegrößen kann die Sprite-Lib/bzw. die GPU nicht mehr (direkt) verarbeiten.
(>= 20 Megapixel-Bilder !!!)

Hier würde eine gute Resize-Funktion helfen! Hat da jemand Tipps!
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8679
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Re: Bilder drehen

Beitrag von NicTheQuick »

Darf ich den Hintergrund erfahren, warum du das machen willst? 20 MP kannst du ja eh nicht am Stück auf einem Bildschirm anzeigen. Aber wenn du zum Anzeigen zum Beispiel immer nur den Teil drehst, der aktuell angezeigt wird, dann sollte das doch recht flott gehen, oder?
Und hast du den Debugger deaktiviert? Damit geht alles sehr viel langsamer.
Bild
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: Bilder drehen

Beitrag von ccode_new »

@Nic

Ja ich möchte/ muss die Bilder auch "Resizen".

Das mache ich auch.

Aber wenn ich über Sprites rotieren möchte (weil es schneller ist) dann brauche ich eine Resize-Funktion für Sprites!

ZoomSprite() bringt dann nämlich nichts! (Funktioniert dann nicht!)

ResizeImage() funktioniert aber gut, geht aber nur mit Bilder (und nicht mit Sprites).
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Bilder drehen

Beitrag von ts-soft »

Nicht ganz Ernst gemeint!
Die schnellste Möglichkeit Bilder, bzw. den Bildschirm zu drehen unter Windows ist die hier abgebildete:
Bild
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Antworten