Seite 1 von 2

Ringe aus Grafik ausschneiden

Verfasst: 09.01.2012 20:01
von Kiffi
Hallo,

(sorry wg. des umständlichen Betreffs, aber mir fiel nichts sinnvolleres ein.)

Ich bin in Sachen Grafikprogrammierung recht unbeholfen. Deshalb
habe ich bei folgender Aufgabenstellung so meine Probleme. :oops:

Gegeben ist ein Bild. Aus diesem sollen nun (ausgehen vom Zentrum)
immer grösser werdende Ringe ausgeschnitten werden.

Im Prinzip also wie die Ringe bei einer Dartscheibe.

Die Ringe sollen dann als separate Dateien abgespeichert werden, so dass
man hinterher das Ausgangsbild und die Ringe wie Ebenen übereinander
legen kann.

Rechteckige Ausschnitte würde ich mir ja noch zutrauen; aber runde? :freak:

Danke im voraus & Grüße ... Kiffi

Re: Ringe aus Grafik ausschneiden

Verfasst: 09.01.2012 20:27
von DarkDragon
Da gehst du einfach jedes Pixel durch, nimmst die Entfernung zu deinem Zentrum und gibst diese in eine Funktion ein (z.B. y = Round(Cos(Pow(Abs(Dist), 0.25) * #RING_FACTOR + #PI) * 0.5 + 0.5, #PB_Round_Nearest)), also so:

Code: Alles auswählen

Global OriginX.i, OriginY.i

Procedure.d Distance(X1.d, Y1.d, X2.d, Y2.d)
  Protected XDiff.d = X2 - X1
  Protected YDiff.d = Y2 - Y1
  
  ProcedureReturn Sqr(XDiff * XDiff + YDiff * YDiff)
EndProcedure

#RING_FACTOR = 30.0

Procedure.i CircleFunc(Dist.d)
  ProcedureReturn Round(Cos(Pow(Abs(Dist), 0.25) * #RING_FACTOR + #PI) * 0.5 + 0.5, #PB_Round_Nearest)
EndProcedure

Procedure FilterCallback(X, Y, QuellFarbe, ZielFarbe)
  If CircleFunc(Distance(X, Y, OriginX, OriginY))
    ProcedureReturn ZielFarbe
  Else
    ProcedureReturn QuellFarbe
  EndIf
EndProcedure

LoadImage(1, #PB_Compiler_Home + "examples/sources/data/geebee2.bmp")

If OpenWindow(0, 0, 0, ImageWidth(1), ImageHeight(1), "Test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  If CreateImage(0, ImageWidth(1), ImageHeight(1))
    OriginX = ImageWidth(1) / 2
    OriginY = ImageHeight(1) / 2
    
    StartDrawing(ImageOutput(0))
    DrawingMode(#PB_2DDrawing_CustomFilter)      
    CustomFilterCallback(@FilterCallback())
    DrawImage(ImageID(1), 0, 0)
    StopDrawing() 
    
    ImageGadget(0, 0, 0, 400, 200, ImageID(0))
  EndIf
  
  Repeat
    Event = WaitWindowEvent()
  Until Event = #PB_Event_CloseWindow
EndIf
[EDIT]
Ups, hab übersehen, dass die in einzelne Bilder sollen. Sollen sich die Ringe dann auch berühren?

[EDIT]
Hier mit gleich breiten Ringen:

Code: Alles auswählen

Global OriginX.i, OriginY.i
Global MinDist.d, MaxDist.d

Procedure.d Distance(X1.d, Y1.d, X2.d, Y2.d)
  Protected XDiff.d = X2 - X1
  Protected YDiff.d = Y2 - Y1
  
  ProcedureReturn Sqr(XDiff * XDiff + YDiff * YDiff)
EndProcedure

Procedure FilterCallback(X, Y, QuellFarbe, ZielFarbe)
  Protected Distance.d = Distance(X, Y, OriginX, OriginY)
  
  If Distance >= MinDist And Distance < MaxDist
    ProcedureReturn QuellFarbe
  Else
    ProcedureReturn ZielFarbe
  EndIf
EndProcedure

#RING_COUNT = 5

LoadImage(1, #PB_Compiler_Home + "examples/sources/data/geebee2.bmp")

If OpenWindow(0, 0, 0, ImageWidth(1), ImageHeight(1), "Test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  If CreateImage(0, ImageWidth(1), ImageHeight(1))
    OriginX = ImageWidth(1) / 2
    OriginY = ImageHeight(1) / 2
  EndIf
  
  ImageGadget(0, 0, 0, ImageWidth(0), ImageHeight(0), ImageID(0))
  
  Define k.i = 0
  Define RingStep.i = ImageWidth(0) / #RING_COUNT
  Define Time.i = ElapsedMilliseconds()
  Repeat
    If ElapsedMilliseconds() - Time > 1000
      MinDist = MaxDist
      MaxDist + RingStep
      
      StartDrawing(ImageOutput(0))
      Box(0, 0, OutputWidth(), OutputHeight(), RGB(0, 0, 0))
      DrawingMode(#PB_2DDrawing_CustomFilter)
      CustomFilterCallback(@FilterCallback())
      DrawImage(ImageID(1), 0, 0)
      StopDrawing()
      
      SetGadgetState(0, ImageID(0))
      
      k + 1
      If k >= #RING_COUNT
        k = 0
      EndIf
      Time = ElapsedMilliseconds()
    EndIf
    
    Event = WaitWindowEvent(5)
  Until Event = #PB_Event_CloseWindow
EndIf
Und hier mit immer breiter werdenden Ringen:

Code: Alles auswählen

Global OriginX.i, OriginY.i
Global MinDist.d, MaxDist.d

Procedure.d Distance(X1.d, Y1.d, X2.d, Y2.d)
  Protected XDiff.d = X2 - X1
  Protected YDiff.d = Y2 - Y1
  
  ProcedureReturn Sqr(XDiff * XDiff + YDiff * YDiff)
EndProcedure

Procedure FilterCallback(X, Y, QuellFarbe, ZielFarbe)
  Protected Distance.d = Distance(X, Y, OriginX, OriginY)
  
  If Distance >= MinDist And Distance < MaxDist
    ProcedureReturn QuellFarbe
  Else
    ProcedureReturn ZielFarbe
  EndIf
EndProcedure

#RING_COUNT = 5

LoadImage(1, #PB_Compiler_Home + "examples/sources/data/geebee2.bmp")

If OpenWindow(0, 0, 0, ImageWidth(1), ImageHeight(1), "Test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  If CreateImage(0, ImageWidth(1), ImageHeight(1))
    OriginX = ImageWidth(1) / 2
    OriginY = ImageHeight(1) / 2
  EndIf
  
  ImageGadget(0, 0, 0, ImageWidth(0), ImageHeight(0), ImageID(0))
  
  Define k.i = 0
  Define RingStep.i = ImageWidth(0) / #RING_COUNT
  Define Time.i = ElapsedMilliseconds()
  Repeat
    If ElapsedMilliseconds() - Time > 1000
      MinDist = MaxDist
      MaxDist + RingStep / (#RING_COUNT - k)
      
      StartDrawing(ImageOutput(0))
      Box(0, 0, OutputWidth(), OutputHeight(), RGB(0, 0, 0))
      DrawingMode(#PB_2DDrawing_CustomFilter)
      CustomFilterCallback(@FilterCallback())
      DrawImage(ImageID(1), 0, 0)
      StopDrawing()
      
      SetGadgetState(0, ImageID(0))
      
      k + 1
      If k >= #RING_COUNT
        k = 0
        MaxDist = 1
      EndIf
      Time = ElapsedMilliseconds()
    EndIf
    
    Event = WaitWindowEvent(5)
  Until Event = #PB_Event_CloseWindow
EndIf

Re: Ringe aus Grafik ausschneiden

Verfasst: 09.01.2012 21:42
von Danilo
Habe mal meinen Bresenham Circle von HIER genommen und
so modifiziert, dass es nicht den Kreis innen sondern außen zeichnet.
Dabei setzt das den AlphaChannel auf 0, löscht es also. Übrig bleibt das
richtige Bild innen.

neuesBild = CircleCut(originalBild, x, y, radius)

Code: Alles auswählen

UsePNGImageDecoder()

Procedure CircleCut(img,x,y,radius)
    ; Bresenham circle algorithm
    original = GrabImage(img,#PB_Any,x-radius,y-radius,radius*2,radius*2)
    result   = CreateImage(#PB_Any,radius*2,radius*2,32)
    If StartDrawing(ImageOutput(result))
        DrawImage(ImageID(original),0,0)

        ;DrawingMode(#PB_2DDrawing_AlphaChannel)
        DrawingMode(#PB_2DDrawing_AllChannels)

        temp_x = 0
        d = 3 - 2 * radius
        w=ImageWidth(result)
        h=ImageHeight(result)
        x=w*0.5
        y=h*0.5
        color=0;$FFFFFFFF

        While temp_x <= radius
            LineXY(0,y+radius,x-temp_x,y+radius,color)
            LineXY(x+temp_x,y+radius,w,y+radius,color)
            LineXY(0,y+temp_x,x-radius,y+temp_x,color)
            LineXY(x+radius,y+temp_x,w,y+temp_x,color)
        
            LineXY(0,y-temp_x,x-radius,y-temp_x,color)
            LineXY(x+radius,y-temp_x,w,y-temp_x,color)
        
            LineXY(0,y-radius,x-temp_x,y-radius,color)
            LineXY(x+temp_x,y-radius,w,y-radius,color)
            
            If d < 0
              d + 4*temp_x + 6
            Else
              d + 4*(temp_x - radius) + 10
              radius - 1
            EndIf
            temp_x + 1
        Wend
  
        StopDrawing()
    EndIf
    FreeImage(original)
    ProcedureReturn result
EndProcedure

original = LoadImage(#PB_Any,"02.png")
If original

    cut = CircleCut(original,100,100,80)
    
    If OpenWindow(0, 0, 0, 800, 600, "CanvasGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
        CanvasGadget(0, 0, 0, 800, 600)
        
        StartDrawing(CanvasOutput(0))
            Box(0,0,800,800,$FFFF)
            DrawingMode(#PB_2DDrawing_AlphaBlend)
            DrawImage(ImageID(cut),10,10)
        StopDrawing()
        
        Repeat
          Event = WaitWindowEvent()
              
        Until Event = #PB_Event_CloseWindow
    EndIf
EndIf
Ist schön flexibel, da man an jeder Stelle einen Kreis ausschneiden kann.

Re: Ringe aus Grafik ausschneiden

Verfasst: 10.01.2012 00:09
von PMV
Wenns zu kompliziert ist, hier Danilos mit dem Circle-Befehl.
Hier wird auch tatsächlich ein Ring ausgeschnitten. :wink:

Code: Alles auswählen

UsePNGImageDecoder()

Procedure CircleCut(img,x,y,radius1, radius2)
    If radius1 < radius2
      Swap radius1, radius2
    EndIf
    durchmesser = radius1 * 2
    result   = CreateImage(#PB_Any,durchmesser, durchmesser,32)
    If StartDrawing(ImageOutput(result))
        DrawImage(ImageID(img),-x+radius1,-y+radius1, durchmesser, durchmesser)
        DrawingMode(#PB_2DDrawing_AlphaChannel)
        Box(0, 0, durchmesser, durchmesser, $00FFFFFF)
        Circle(radius1, radius1, radius1, $FFFFFFFF)
        Circle(radius1, radius1, radius2, $00FFFFFF)
        StopDrawing()
    EndIf
    ProcedureReturn result
EndProcedure

original = LoadImage(#PB_Any,OpenFileRequester("", "", "*.png", 0))
If original

    cut = CircleCut(original,100,100,80, 40)
    
    If OpenWindow(0, 0, 0, 800, 600, "CanvasGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
        CanvasGadget(0, 0, 0, 800, 600)
        
        StartDrawing(CanvasOutput(0))
            Box(0,0,800,800,$FFFF)
            DrawingMode(#PB_2DDrawing_AlphaBlend)
            DrawImage(ImageID(cut),10,10)
        StopDrawing()
        
        Repeat
          Event = WaitWindowEvent()
              
        Until Event = #PB_Event_CloseWindow
    EndIf
EndIf
MFG PMV

Re: Ringe aus Grafik ausschneiden

Verfasst: 10.01.2012 00:33
von Falko
sollte das nicht so sein und davon mehrere Ringe wie eine Dartscheibe, sodass man diese
Ringe übereinander legen kann, damit ein vollständiges Bild zu sehen ist, aber jeder dieser Ringe in eine eigene Datei gespeichert werden sollte?

Beispiel nur ein Ring mit den obigen Sourcen

Code: Alles auswählen

UsePNGImageDecoder()

Procedure CircleCut(img,x,y,radius)
    durchmesser = radius * 2
    result   = CreateImage(#PB_Any,durchmesser, durchmesser,32)
    If StartDrawing(ImageOutput(result))
        DrawImage(ImageID(img),-x+radius,-y+radius, durchmesser, durchmesser)
        DrawingMode(#PB_2DDrawing_AlphaChannel)
        Box(0, 0, durchmesser, durchmesser, $00FFFFFF)
        Circle(radius, radius, radius, $FFFFFFFF)
        StopDrawing()
    EndIf
    ProcedureReturn result
EndProcedure

original = LoadImage(#PB_Any,OpenFileRequester("", "", "*.png", 0))
If original

    cut = CircleCut(original,100,100,80)
   
    If OpenWindow(0, 0, 0, 800, 600, "CanvasGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
        CanvasGadget(0, 0, 0, 800, 600)
       
        StartDrawing(CanvasOutput(0))
        Box(0,0,800,800,$FFFF)
       
            DrawingMode(#PB_2DDrawing_AlphaBlend)
            DrawImage(ImageID(cut),10,10)
            Circle(90,90,50,$FF00FFFF)
        StopDrawing()
       
        Repeat
          Event = WaitWindowEvent()
             
        Until Event = #PB_Event_CloseWindow
    EndIf
EndIf
Gruß,
Falko

Re: Ringe aus Grafik ausschneiden

Verfasst: 10.01.2012 02:27
von Kiffi
Jungs, Ihr seid spitze! :allright:

Habe was kleines daraus gebastelt. Werde ich
morgen mal vorstellen. Bin jetzt zu müde.

Vielen lieben Dank & Grüße ... Kiffi

Re: Ringe aus Grafik ausschneiden

Verfasst: 10.01.2012 07:42
von Danilo
Ooops, ging ja um Ringe und nicht um Kreise. Sorry, habe das Thema total verfehlt. :oops:

Re: Ringe aus Grafik ausschneiden

Verfasst: 10.01.2012 11:07
von Danilo
PMV hat geschrieben:Wenns zu kompliziert ist, hier Danilos mit dem Circle-Befehl.
Hier wird auch tatsächlich ein Ring ausgeschnitten. :wink:

Code: Alles auswählen

UsePNGImageDecoder()

Procedure CircleCut(img,x,y,radius1, radius2)
    If radius1 < radius2
      Swap radius1, radius2
    EndIf
    durchmesser = radius1 * 2
    result   = CreateImage(#PB_Any,durchmesser, durchmesser,32)
    If StartDrawing(ImageOutput(result))
        DrawImage(ImageID(img),-x+radius1,-y+radius1, durchmesser, durchmesser)
        DrawingMode(#PB_2DDrawing_AlphaChannel)
        Box(0, 0, durchmesser, durchmesser, $00FFFFFF)
        Circle(radius1, radius1, radius1, $FFFFFFFF)
        Circle(radius1, radius1, radius2, $00FFFFFF)
        StopDrawing()
    EndIf
    ProcedureReturn result
EndProcedure

original = LoadImage(#PB_Any,OpenFileRequester("", "", "*.png", 0))
If original

    cut = CircleCut(original,100,100,80, 40)
    
    If OpenWindow(0, 0, 0, 800, 600, "CanvasGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
        CanvasGadget(0, 0, 0, 800, 600)
        
        StartDrawing(CanvasOutput(0))
            Box(0,0,800,800,$FFFF)
            DrawingMode(#PB_2DDrawing_AlphaBlend)
            DrawImage(ImageID(cut),10,10)
        StopDrawing()
        
        Repeat
          Event = WaitWindowEvent()
              
        Until Event = #PB_Event_CloseWindow
    EndIf
EndIf
MFG PMV
Bei Deinem Code sind die Bilddaten noch da, sie werden nur nicht angezeigt
wenn Du Alpha auf 0 setzt. Mach mal beim zeichnen ins CanvasGadget das
DrawingMode(#PB_2DDrawing_AlphaBlend) weg und Du siehst die Daten sind
noch da. Das macht sicherlich einen Unterschied bei der Speicherung der Bilder
mit Kompression.

Ohne 2 Bilder zu benutzen bekomme ich es allerdings gerade nicht hin
das der AlphaChannel und die Bilddaten am Rand komplett auf 0 gesetzt
werden.
Da das ja nur einmalig zum generieren und abspeichern gebraucht wird,
ist die Geschwindigkeit wohl nicht ganz so wichtig. So sind die nicht
benötigten Daten komplett leer ($00000000), was für eine kleinere
Größe nach dem Abspeichern sorgen sollte:

Code: Alles auswählen

UsePNGImageDecoder()

Procedure CircleCut(img,x,y,radius1, radius2)
    If radius1 < radius2
      Swap radius1, radius2
    EndIf
    durchmesser = radius1 * 2
    result2   = CreateImage(#PB_Any,durchmesser, durchmesser,32|#PB_Image_Transparent)
    If StartDrawing(ImageOutput(result2))
        DrawingMode(#PB_2DDrawing_AlphaChannel)
        Circle(radius1, radius1, radius1, $FF000000)
        Circle(radius1, radius1, radius2, $00000000)
        DrawingMode(#PB_2DDrawing_AlphaClip)
        DrawImage(ImageID(img),-x+radius1,-y+radius1)
        StopDrawing()
    EndIf
    result = CreateImage(#PB_Any,durchmesser, durchmesser,32|#PB_Image_Transparent)
    If StartDrawing(ImageOutput(result))
        DrawingMode(#PB_2DDrawing_AlphaBlend)
        DrawImage(ImageID(result2),0,0)
        StopDrawing()
    EndIf
    FreeImage(result2)
    ProcedureReturn result
EndProcedure

;original = LoadImage(#PB_Any,OpenFileRequester("", "", "*.png", 0))
original = LoadImage(#PB_Any,"02.png")
If original

    cut = CircleCut(original,100,100,80, 40)
    
    If OpenWindow(0, 0, 0, 800, 600, "CanvasGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
        CanvasGadget(0, 0, 0, 800, 600)
        
        StartDrawing(CanvasOutput(0))
            Box(0,0,800,800,$FFFF)
            DrawImage(ImageID(cut),10,10)
            DrawingMode(#PB_2DDrawing_AlphaBlend)
            DrawImage(ImageID(cut),10,310)
        StopDrawing()
        
        Repeat
          Event = WaitWindowEvent()
              
        Until Event = #PB_Event_CloseWindow
    EndIf
EndIf

Re: Ringe aus Grafik ausschneiden

Verfasst: 10.01.2012 11:12
von DarkDragon
Falko hat geschrieben:sollte das nicht so sein und davon mehrere Ringe wie eine Dartscheibe, sodass man diese
Ringe übereinander legen kann, damit ein vollständiges Bild zu sehen ist, aber jeder dieser Ringe in eine eigene Datei gespeichert werden sollte?
Jop, das was mein zweiter und dritter Code machen. Aber die Aufgabe ist auch nicht detailliert beschrieben, also könnte es alles sein. Kiffi scheint aber schon eine Antwort für sich gefunden zu haben.

Re: Ringe aus Grafik ausschneiden

Verfasst: 10.01.2012 16:24
von Kiffi
Hallö,

so, hier - wie versprochen - mein kleines Projekt, für das ich
gestern die Schneidefunktion benötigte:

http://tuebbentools.bplaced.net/RotateLayer/

Die Steuerung ist noch ein wenig hakelig aber mit viel
Spucke und Geduld schafft man es wirklich, alle Winkel
auf einen Modulo von 360° zu bekommen.

Ist insgesamt noch viel Platz für Verbesserungen. Mal
schauen, ob ich mich da noch tiefer reinknien werde.

Übrigens habe ich dann doch die Kreisschneide-Funktion
von Danilo verwendet, weil die Ringe nicht sauber genug
ausgeschnitten werden konnten. Da fehlten an den
Schnitträndern immer ein paar wenige Pixel.

Also, nochmals vielen Dank für Eure tolle Hilfe & Grüße ... Kiffi