Ringe aus Grafik ausschneiden

Probleme beim Erstellen von 3D-Modellen und Texturen, keine Ahnung womit man Musik macht? Dies ist dein Forum.
Benutzeravatar
Kiffi
Beiträge: 10621
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Ringe aus Grafik ausschneiden

Beitrag 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
Hygge
DarkDragon
Beiträge: 6267
Registriert: 29.08.2004 08:37
Computerausstattung: Hoffentlich bald keine mehr
Kontaktdaten:

Re: Ringe aus Grafik ausschneiden

Beitrag 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
Angenommen es gäbe einen Algorithmus mit imaginärer Laufzeit O(i * n), dann gilt O((i * n)^2) = O(-1 * n^2) d.h. wenn man diesen Algorithmus verschachtelt ist er fertig, bevor er angefangen hat.
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Re: Ringe aus Grafik ausschneiden

Beitrag 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.
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
Benutzeravatar
PMV
Beiträge: 2765
Registriert: 29.08.2004 13:59
Wohnort: Baden-Württemberg

Re: Ringe aus Grafik ausschneiden

Beitrag 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
alte Projekte:
TSE, CWL, Chatsystem, GameMaker, AI-Game DLL, Fileparser, usw. -.-
Benutzeravatar
Falko
Admin
Beiträge: 3531
Registriert: 29.08.2004 11:27
Computerausstattung: PC: MSI-Z590-GC; 32GB-DDR4, ICore9; 2TB M2 + 2x3TB-SATA2 HDD; Intel ICore9 @ 3600MHZ (Win11 Pro. 64-Bit),
Acer Aspire E15 (Win11 Home X64). Purebasic LTS 6.0
Kontaktdaten:

Re: Ringe aus Grafik ausschneiden

Beitrag 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
Bild
Win10 Pro 64-Bit, PB_5.4,GFA-WinDOS, Powerbasic9.05-Windows, NSBasic/CE, NSBasic/Desktop, NSBasic4APP, EmergenceBasic
Benutzeravatar
Kiffi
Beiträge: 10621
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: Ringe aus Grafik ausschneiden

Beitrag 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
Hygge
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Re: Ringe aus Grafik ausschneiden

Beitrag von Danilo »

Ooops, ging ja um Ringe und nicht um Kreise. Sorry, habe das Thema total verfehlt. :oops:
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Re: Ringe aus Grafik ausschneiden

Beitrag 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
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
DarkDragon
Beiträge: 6267
Registriert: 29.08.2004 08:37
Computerausstattung: Hoffentlich bald keine mehr
Kontaktdaten:

Re: Ringe aus Grafik ausschneiden

Beitrag 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.
Angenommen es gäbe einen Algorithmus mit imaginärer Laufzeit O(i * n), dann gilt O((i * n)^2) = O(-1 * n^2) d.h. wenn man diesen Algorithmus verschachtelt ist er fertig, bevor er angefangen hat.
Benutzeravatar
Kiffi
Beiträge: 10621
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: Ringe aus Grafik ausschneiden

Beitrag 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
Hygge
Antworten