Image spiegeln

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
fabulouspaul
Beiträge: 120
Registriert: 01.04.2011 21:59

Image spiegeln

Beitrag von fabulouspaul »

Hallo Gemeinde,

ich habe für ein kleines Programm die schnelle Spiegelung von Images benötigt und wollte Euch meine "geistigen Ergüsse" nicht vorenthalten. :lol:

Wichtig dabei: ich arbeite immer mit 32 Bit Farbtiefe. Nur dann funktioniert das vertikale Spiegeln. Es gibt durchaus Images mit weniger Farbtiefe... diese müsste man dann ggf. konvertieren oder die Routine etwas umbauen, was sie aber wieder langsamer machen würde...

Code: Alles auswählen

EnableExplicit

Structure einzeln                                     ; Zugriff auf die einzenen Farbkanäle
  pix_r.a
  pix_g.a
  pix_b.a
  pix_a.a
EndStructure

Structure pixel                                       ; Zugriff auf komplettes Pixel oder Farbkanäle
  StructureUnion
    pix_l.l
    pix.einzeln
  EndStructureUnion
EndStructure

Procedure hspiegeln(image)
  Protected zeilenlaenge                              ; Länge (in Byte) einer Zeile im Image 
  Protected hoehe                                     ; Image-Höhe
  Protected tiefe                                     ; Farbtiefe des Images in Byte (echte Tiefe im Speicher)
  Protected *obere.pixel                              ; Adresse der oberen Zeile im Speicher
  Protected *untere.pixel                             ; Adresse der unteren Zeile im Speicher
  Protected i                                         ; Laufvariable
  Protected halbe_hoehe                               ; Image-Höhe / 2 für optimierten Durchlauf
  Protected *zeilenpuffer                             ; Zwischenspeicher für 1 Zeile
  
  ; Daten über das Image holen
  StartDrawing(ImageOutput(image))
    *obere.pixel = DrawingBuffer()
    zeilenlaenge = DrawingBufferPitch()
  StopDrawing()
  *zeilenpuffer = AllocateMemory(zeilenlaenge)
  hoehe = ImageHeight(image)
  tiefe = ImageDepth(image) / 8                       ; Bytes pro Pixel
  halbe_hoehe = hoehe / 2                             ; in eine Durchlauf linkes und rechtes Pixel tauschen, daher muss nur die halbe Länge durchlaufen werden 
  *untere = *obere + (zeilenlaenge * (hoehe-1))       ; Adresse der unteren Zeile ermitteln
  
  For i = 1 To halbe_hoehe
    CopyMemory(*obere, *zeilenpuffer, zeilenlaenge)   ; obere Zeile merken
    CopyMemory(*untere, *obere, zeilenlaenge)         ; untere Zeile in obere Zeile
    CopyMemory(*zeilenpuffer, *untere, zeilenlaenge)  ; obere Zeile in untere zeile
    *obere + zeilenlaenge
    *untere - zeilenlaenge
  Next i
  FreeMemory(*zeilenpuffer)
EndProcedure

Procedure vspiegeln(image)
  Protected zeilenlaenge                              ; Länge (in Byte) einer Zeile im Image 
  Protected hoehe                                     ; Image-Höhe
  Protected breite                                    ; Image-Breite
  Protected tiefe                                     ; Farbtiefe des Images in Byte (echte Tiefe im Speicher)
  Protected *linkes.pixel                             ; Adresse des linken Pixels im Speicher
  Protected *rechtes.pixel                            ; Adresse des rechten Pixels im Speicher
  Protected i, j, k                                   ; Laufvariablen 
  Protected halbe_breite                              ; Image-Breite / 2 für optimierten Durchlauf
  Protected farbpuffer                                ; Zwischenspeicher für 1 Pixel
  
  ; Daten über das Image holen
  StartDrawing(ImageOutput(image))
    *linkes.pixel = DrawingBuffer()
    zeilenlaenge = DrawingBufferPitch()
  StopDrawing()
  hoehe = ImageHeight(image)
  breite = ImageWidth(image)
  tiefe = ImageDepth(image) / 8                       ; Bytes pro Pixel
  halbe_breite = breite / 2                           ; in eine Durchlauf linkes und rechtes Pixel tauschen, daher muss nur die halbe Länge durchlaufen werden
  
  If tiefe = 4
    For i = 1 To hoehe
      k = zeilenlaenge                                
      *rechtes = *linkes + (tiefe * (breite-1))       ; Adresse des letzten Pixels in der Zeile
      For j = 1 To halbe_breite
        farbpuffer = *linkes\pix_l                    ; Farbe des linken Pixels merken
        *linkes\pix_l = *rechtes\pix_l                ; Farbe des rechten Pixels in linkes Pixel
        *rechtes\pix_l = farbpuffer                   ; Farbe des linken Pixels in rechtes Pixel
        
        *linkes + tiefe                               ; nächstes Pixel links
        *rechtes - tiefe                              ; nächstes Pixel rechts
        k - tiefe
      Next
      *linkes + k                                     ; Start der nächsten Zeile
    Next
  Else
    Debug "VSpiegeln(): Image-Tiefe ist nicht 32Bit!"
  EndIf
EndProcedure

; --- Beispiel
UseJPEGImageDecoder()
UsePNGImageDecoder()
UseTIFFImageDecoder()

Global dateiname.s
Global bild
Global t

dateiname = OpenFileRequester("Image auswählen...", "", "Image|*.bmp;*.jpg;*.png;*.tif", 0)

If dateiname <> ""
  bild = LoadImage(#PB_Any, dateiname)
  
  If bild
    t = ElapsedMilliseconds()
    hspiegeln(bild)
    t = ElapsedMilliseconds() - t
    MessageRequester("Info", "Horizontales spiegeln: " + Str(t) + "ms")
    SaveImage(bild, GetPathPart(dateiname) + "horizontal.bmp")
    
    hspiegeln(bild)
    t = ElapsedMilliseconds()
    vspiegeln(bild)
    t = ElapsedMilliseconds() - t
    MessageRequester("Info", "Vertikales spiegeln: " + Str(t) + "ms")
    SaveImage(bild, GetPathPart(dateiname) + "vertikal.bmp")
  EndIf
EndIf

End 
Vielleicht kann es ja jemand gebrauchen. :wink:
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

Re: Image spiegeln

Beitrag von Mijikai »

Schön, danke für die Motivation :allright:
Hab mich auch mal an einer Version versucht um alle Images zu unterstützen.

Code:

Code: Alles auswählen

... Entfernt verbuggt!

Viel Spass <)
Zuletzt geändert von Mijikai am 23.09.2018 11:13, insgesamt 1-mal geändert.
fabulouspaul
Beiträge: 120
Registriert: 01.04.2011 21:59

Re: Image spiegeln

Beitrag von fabulouspaul »

:allright: Prima!

Eine Kleinigkeit: kann es sein, dass Du die Spiegelachsen vertauscht hast (Horizontal = 1 / Vertikal = 0)?

Ich habe mein vertikales Spiegeln unter dem Geschwindigkeitsaspekt noch mal bearbeitet. Die Funktion arbeitet jetzt in Abhängigkeit von der Farbtiefe nach der alten (schnellen) Methode bei 32 Bit oder mit CopyMemory() bei 24 Bit.
Da PB intern nur mit 24 oder 32 Bit Farbtiefe arbeitet, kann es nur 3 oder 4 Bytes pro Pixel geben. Bei 3 Bytes sind 2 x Poke() (einmal 2 Bytes + einmal 1 Byte) schneller als CopyMemory() für 3 Bytes. Ist nur ein marginaler Unterschied der selbst bei größeren Bildern nur einige Millisekunden ausmacht, aber immerhin. :wink:

Code: Alles auswählen

Procedure vspiegeln(image)
  Protected zeilenlaenge                              ; Länge (in Byte) einer Zeile im Image
  Protected hoehe                                     ; Image-Höhe
  Protected breite                                    ; Image-Breite
  Protected tiefe                                     ; Farbtiefe des Images in Byte (echte Tiefe im Speicher)
  Protected *linkes.pixel                             ; Adresse des linken Pixels im Speicher
  Protected *rechtes.pixel                            ; Adresse des rechten Pixels im Speicher
  Protected i, j, k, l                                ; Laufvariablen
  Protected halbe_breite                              ; Image-Breite / 2 für optimierten Durchlauf
  Protected farbpuffer                                ; Zwischenspeicher für 1 Pixel bei 32Bit Farbtiefe
  Protected *pixelpuffer                              ; Zwischenspeicher ganzes Image bei 24Bit Farbtiefe
  
  ; Daten über das Image holen
  StartDrawing(ImageOutput(image))
    *linkes.pixel = DrawingBuffer()
    zeilenlaenge = DrawingBufferPitch()
  StopDrawing()
  hoehe = ImageHeight(image)
  breite = ImageWidth(image)
  tiefe = ImageDepth(image) / 8                       ; Bytes pro Pixel
  halbe_breite = breite / 2                           ; in eine Durchlauf linkes und rechtes Pixel tauschen, daher muss nur die halbe Länge durchlaufen werden
  l = ((breite - 1) * tiefe)                          ; Zeilenlänge in Pixel * Farbtiefe
 
  If tiefe = 4                                        ; "Paranoia-Abfrage" - Image sollte immer eine Tiefe von 32Bit haben!
    For i = 1 To hoehe
      k = zeilenlaenge                                
      *rechtes = *linkes + (tiefe * (breite-1))       ; Adresse des letzten Pixels in der Zeile
      For j = 1 To halbe_breite
        farbpuffer = *linkes\pix_l                    ; Farbe des linken Pixels merken
        *linkes\pix_l = *rechtes\pix_l                ; Farbe des rechten Pixels in linkes Pixel
        *rechtes\pix_l = farbpuffer                   ; Farbe des linken Pixels in rechtes Pixel
        
        *linkes + tiefe                               ; nächstes Pixel links
        *rechtes - tiefe                              ; nächstes Pixel rechts
        k - tiefe
      Next
      *linkes + k                                     ; Start der nächsten Zeile
    Next  
    ProcedureReturn -1
    
  ElseIf tiefe = 3
    *pixelpuffer = AllocateMemory(zeilenlaenge * hoehe)
    For i = 0 To hoehe-1
      k = i * zeilenlaenge
      For j = 0 To breite-1
;        CopyMemory(*linkes + k + (j * tiefe), *pixelpuffer + k + (l - j * tiefe), tiefe)
         PokeU(*pixelpuffer + k + (l - j * tiefe), PeekU(*linkes + k + (j * tiefe)))
         PokeA(*pixelpuffer + k + (l - j * tiefe) + 2, PeekA(*linkes + k + (j * tiefe) + 2))
      Next
    Next  
    CopyMemory(*pixelpuffer, *linkes, hoehe * zeilenlaenge)   
    FreeMemory(*pixelpuffer)
  Else
    Debug "VSpiegeln(): Farb-Tiefe muss 24 oder 32 Bit sein!"
  EndIf
EndProcedure
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: Image spiegeln

Beitrag von ccode_new »

Sieht gut aus und ist schnell.
Kann man gebrauchen. 8)

:allright:
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

Re: Image spiegeln

Beitrag von Mijikai »

Hier nochmal mein Code den ich vorübergehend wieder entfernt hatte da mir noch en Bug aufgefallen war.
Unterstützt alle PB (internen) Image - Formate.
Das Bild kann in alle Richtungen gespiegelt werden.

Viel Spaß :)

Code:

Code: Alles auswählen

EnableExplicit

UsePNGImageDecoder()
UseJPEGImageDecoder()

Procedure.i FlipImage(Image.i,Flag.b = #Null);0 = Horizontal / 1 = Vertical / 2 = Horizontal & Vertical
  Protected Width.i
  Protected Height.i
  Protected *Buffer
  Protected BufferSize.i
  Protected *Source
  Protected Pitch.i
  Protected X.i
  Protected Y.i
  Protected Offset.i
  Protected PixelBytes.i
  Protected Result.i
  If IsImage(Image)
    Width = ImageWidth(Image)
    Height = ImageHeight(Image)
    PixelBytes = ImageDepth(Image,#PB_Image_InternalDepth) / 8
    If StartDrawing(ImageOutput(Image))
      Pitch = DrawingBufferPitch()
      BufferSize = Height * Pitch
      *Buffer = AllocateMemory(BufferSize)
      If *Buffer
        *Source = DrawingBuffer()
        Select Flag
          Case 1
            X = BufferSize - Pitch
            For Y = 0 To Height - 1
              Offset = Y * Pitch
              CopyMemory(*Source + Offset,*Buffer + X - Offset,Pitch)
            Next
          Case 2
            For Y = 0 To Height - 1
              Offset = Y * Pitch
              For X = 0 To Width - 1 
                CopyMemory(*Source + Offset + (X * PixelBytes),*Buffer + Offset + ((Width - X) * PixelBytes),PixelBytes)
              Next
            Next
            CopyMemory(*Buffer,*Source,BufferSize)
            X = BufferSize - Pitch
            For Y = 0 To Height - 1
              Offset = Y * Pitch
              CopyMemory(*Source + Offset,*Buffer + X - Offset,Pitch)
            Next
          Default
            For Y = 0 To Height - 1
              Offset = Y * Pitch
              For X = 0 To Width - 1 
                CopyMemory(*Source + Offset + (X * PixelBytes),*Buffer + Offset + ((Width - X) * PixelBytes),PixelBytes)
              Next
            Next
        EndSelect
        CopyMemory(*Buffer,*Source,BufferSize)
        Result = #True 
        FreeMemory(*Buffer)
      EndIf
      StopDrawing()
    EndIf
  EndIf
  ProcedureReturn Result
EndProcedure

Global Image.i

Image = LoadImage(#PB_Any,"XYZ");<- BILD ÄNDERN!
If Image
  Debug FlipImage(Image,1)
  If OpenWindow(0,0,0,800,580,"",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
    If StartVectorDrawing(WindowVectorOutput(0))
      MovePathCursor(0,0)
      DrawVectorImage(ImageID(Image),$FF,800,580)
    EndIf
    Repeat
    Until WaitWindowEvent() = #PB_Event_CloseWindow
    CloseWindow(0)
  EndIf
  FreeImage(Image)
EndIf 

End
Benutzeravatar
RSBasic
Admin
Beiträge: 8022
Registriert: 05.10.2006 18:55
Wohnort: Gernsbach
Kontaktdaten:

Re: Image spiegeln

Beitrag von RSBasic »

Danke auch für deinen Code, Mijikai, aber dein Code ist leider deutlich langsamer, als der von fabulouspaul.
Aus privaten Gründen habe ich leider nicht mehr so viel Zeit wie früher. Bitte habt Verständnis dafür.
Bild
Bild
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

Re: Image spiegeln

Beitrag von Mijikai »

RSBasic hat geschrieben:Danke auch für deinen Code, Mijikai, aber dein Code ist leider deutlich langsamer, als der von fabulouspaul.
:?
Vertikal ist mein Code etwas schneller & horizontal etwas langsamer.
Antworten