Cut an image into several pieces

Just starting out? Need help? Post your questions and find answers here.
jak64
Enthusiast
Enthusiast
Posts: 502
Joined: Sat Aug 15, 2020 5:02 pm
Location: Ciboure (France)

Cut an image into several pieces

Post by jak64 »

Hello,
I want to program a "hidden object" game.
To do this, I need to write a program that cuts an image into several pieces with random shapes and also being able to choose the number of pieces I want.

See attached photo

Can you help me ?

Image

In this example the image has been cut into 7 pieces (I did it manually but I want to do it automatically programmatically).
Each of these images will be a sprite and by displaying them at the same coordinates, they will reconstitute the complete image.
So I want to write a program that will do this with the ability to choose the number of pieces you want.
Marc56us
Addict
Addict
Posts: 1479
Joined: Sat Feb 08, 2014 3:26 pm

Re: Cut an image into several pieces

Post by Marc56us »

Cutting random shapes is quite easy (Lib Vector)
But cutting complementary random shapes, I don't see how. It's probably possible, but more of a mathematical problem.
If your puzzle was a classic 4x4, 5x5, 6x6 etc it could be conceived by making columns and rows in which you constrain each cut line, but here with an odd number, it is quite (too) complicated (for me anyway).
Don't forget that Sprites are by default rectangular shapes of which a part can be transparent. So I think the Vector lib will be better.
A way: search puzzle cut path
PS. Have a look at Voronoi diagram
:wink:
User avatar
NicTheQuick
Addict
Addict
Posts: 1226
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: Cut an image into several pieces

Post by NicTheQuick »

Maybe you could first create a point cloud, and then triangulate it using my Delaunay code in the German forum.
- You can move single points
- Right click starts the triangulation
- You can also triangulate while moving points
After doing the triangulation you could merge neighbouring triangles to polygons randomly until you are left with the number of pieces you desire.
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8433
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Cut an image into several pieces

Post by netmaestro »

Here's an example for you to try. It just uses boxes but I'm sure you'll be more imaginative. Anyway, it shows the method for creating the cutouts:

Code: Select all

Procedure CustomCallback(x, y, SourceColor, TargetColor)
  ;
  If SourceColor = RGBA(255,0,255,255)
    ResultColor = RGBA(0,0,0,0)
  Else
    ResultColor = SourceColor
  EndIf
  ;
  ProcedureReturn ResultColor
EndProcedure

Macro CheckerBoard(output,blocksize, width, height)
  StartDrawing(output)
    For j=0 To height Step 2*blocksize
      For i=0 To width Step 2*blocksize
        Box(i,j,blocksize,blocksize,#White) : Box(i+blocksize,j,blocksize,blocksize,RGB(200,200,200))
        Box(i,j+blocksize,blocksize,blocksize,RGB(200,200,200)) : Box(i+blocksize,j+blocksize,blocksize,blocksize,#White)
      Next
    Next  
  StopDrawing()
EndMacro

; load the base image and create a disposable copy to cut up. Base image is 0, copy is 1
*buffer = ReceiveHTTPMemory("https://lloydsplace.com/teddy.png")
UsePNGImageDecoder()
CatchImage(0, *buffer)

For i= 1 To 4
  CopyImage(0, i)
Next

; draw a mask on the disposable image which we can use to cut out everything outside target area
StartDrawing(ImageOutput(1))
  DrawingMode(#PB_2DDrawing_AllChannels|#PB_2DDrawing_Outlined)
  Box(-1,-1,102,102,RGBA(255,0,255,255))
  FillArea(103,2,RGBA(255,0,255,255),RGBA(255,0,255,255))
   DrawingMode(#PB_2DDrawing_CustomFilter)
  CustomFilterCallback(@CustomCallback())
  DrawImage(ImageID(1), 0, 0)
StopDrawing()

StartDrawing(ImageOutput(2))
  DrawingMode(#PB_2DDrawing_AllChannels|#PB_2DDrawing_Outlined)
  Box(99,-1,102,101,RGBA(255,0,255,255))
  FillArea(103,103,RGBA(255,0,255,255),RGBA(255,0,255,255))
   DrawingMode(#PB_2DDrawing_CustomFilter)
  CustomFilterCallback(@CustomCallback())
  DrawImage(ImageID(2), 0, 0)
StopDrawing()

StartDrawing(ImageOutput(3))
  DrawingMode(#PB_2DDrawing_AllChannels|#PB_2DDrawing_Outlined)
  Box(-1,98,103,103,RGBA(255,0,255,255))
  FillArea(105,1,RGBA(255,0,255,255),RGBA(255,0,255,255))
   DrawingMode(#PB_2DDrawing_CustomFilter)
  CustomFilterCallback(@CustomCallback())
  DrawImage(ImageID(3), 0, 0)
StopDrawing()

StartDrawing(ImageOutput(4))
  DrawingMode(#PB_2DDrawing_AllChannels|#PB_2DDrawing_Outlined)
  Box(98,98,103,103,RGBA(255,0,255,255))
  FillArea(1,1,RGBA(255,0,255,255),RGBA(255,0,255,255))
   DrawingMode(#PB_2DDrawing_CustomFilter)
  CustomFilterCallback(@CustomCallback())
  DrawImage(ImageID(4), 0, 0)
StopDrawing()

CreateImage(5, 200,200)
StartDrawing(ImageOutput(5))
For i=1 To 4
  DrawAlphaImage(ImageID(i),0,0)
Next
StopDrawing()

OpenWindow(0, 0, 0, 900, 600, "", #PB_Window_ScreenCentered|#PB_Window_SystemMenu)
 TextGadget(#PB_Any,  278, 10, 100, 20, "Original")
 TextGadget(#PB_Any, 598, 10, 300, 20, "Cutouts Put Together")
 TextGadget(#PB_Any, 120, 280, 80, 20, "Cutout 1")
 TextGadget(#PB_Any, 320, 280, 80, 20, "Cutout 2")
 TextGadget(#PB_Any, 520, 280, 80, 20, "Cutout 3")
 TextGadget(#PB_Any, 720, 280, 80, 20, "Cutout 4")

ImageGadget(0,   200, 30, 0, 0, ImageID(0))
CanvasGadget(5, 50, 300, 805, 202, #PB_Canvas_Container)
CheckerBoard(CanvasOutput(5), 10, 805, 202)

StartDrawing(CanvasOutput(5))
  Line(202, 0, 1, 200, #Red)
  Line(402, 0, 1, 200, #Red)
  Line(602, 0, 1, 200, #Red)
  DrawingMode(#PB_2DDrawing_Outlined)
  Box(0,0,805,202,#Red)
StopDrawing()

ImageGadget(1,  1, 1, 0, 0, ImageID(1))
ImageGadget(2, 202, 1, 0, 0, ImageID(2))
ImageGadget(3, 403, 1, 0, 0, ImageID(3))
ImageGadget(4, 604, 1, 0, 0, ImageID(4))
CloseGadgetList()

ImageGadget(6, 550, 30, 0, 0, ImageID(5))

Repeat:Until WaitWindowEvent() = #PB_Event_CloseWindow
BERESHEIT
jak64
Enthusiast
Enthusiast
Posts: 502
Joined: Sat Aug 15, 2020 5:02 pm
Location: Ciboure (France)

Re: Cut an image into several pieces

Post by jak64 »

Hello,
Thanks to Marc56us, NicTheQuick, netmaestro.

I hadn't received an email telling me that I had any answers, that's why I'm only answering now.

I will look at this in detail.

Goodbye
Olli
Addict
Addict
Posts: 1071
Joined: Wed May 27, 2020 12:26 pm

Re: Cut an image into several pieces

Post by Olli »

@jak64

It is normal you did not receive mails. Your subject contains too much violence. You show images of mutilation of teddy bears.
jak64
Enthusiast
Enthusiast
Posts: 502
Joined: Sat Aug 15, 2020 5:02 pm
Location: Ciboure (France)

Re: Cut an image into several pieces

Post by jak64 »

:lol:
jak64
Enthusiast
Enthusiast
Posts: 502
Joined: Sat Aug 15, 2020 5:02 pm
Location: Ciboure (France)

Re: Cut an image into several pieces

Post by jak64 »

Hi there,
I found two programs in Purebasic Voronoi diagram (but also in other programming languages) on the following link

https://rosettacode.org/wiki/Voronoi_diagram
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4660
Joined: Sun Apr 12, 2009 6:27 am

Re: Cut an image into several pieces

Post by RASHAD »

Author : applePi

Code: Select all

DisableDebugger

Procedure.f RandF()
  ProcedureReturn Random(10000) * 0.0001
EndProcedure

If OpenWindow(0, 0, 0, 640, 640, "2DDrawing Example", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  If CreateImage(0, 640, 640) And StartDrawing(ImageOutput(0))
    sq=639:s2.f=sq/2:points=240
    Dim x.f(points):Dim y.f(points):Dim kl.f(points)
    For i = 0 To points
      x(i)=RandF()*sq: y(i)=RandF()*sq
      g.f=127-127*(Abs(s2-x(i))/s2)+127-127*(Abs(s2-y(i))/s2)
      kl(i)=RGB(255-x(i)/sq*255,g,y(i)/sq*255)
    Next
    
    a.f:b.f:q.f
    
    For xx = 0 To sq
      For yy = 0 To sq
        d = 307201
        For i = 0 To points
          a=x(i)-xx: b=y(i)-yy
          q=a*a+b*b
          If q < d
            d = q: kkl = i
          EndIf         
        Next
        Plot(xx, yy, kl(kkl))
      Next
    Next
    
    StopDrawing()
    ImageGadget(0, 0, 0, 640, 640, ImageID(0))
  EndIf
  
  Repeat
    Event = WaitWindowEvent()
  Until Event = #PB_Event_CloseWindow
EndIf
Egypt my love
jak64
Enthusiast
Enthusiast
Posts: 502
Joined: Sat Aug 15, 2020 5:02 pm
Location: Ciboure (France)

Re: Cut an image into several pieces

Post by jak64 »

Great RASHAD !!!
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8433
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Cut an image into several pieces

Post by netmaestro »

Excellent example RASHAD!
And kudos for crediting the original author. Not enough of that happens around here.
BERESHEIT
jak64
Enthusiast
Enthusiast
Posts: 502
Joined: Sat Aug 15, 2020 5:02 pm
Location: Ciboure (France)

Re: Cut an image into several pieces

Post by jak64 »

Hello,
I used the code posted by RASHAD (author of the applePi code).

I want to display an image and above this image, display in black all the areas calculated by the program except one.

1) If we comment out line 12, we see the result

2) If we put line 12 back, we only see the image (Geebee2.bmp) whereas I would like the areas calculated by the code to be displayed above the Geebee2.bmp image, we would then only see a piece of Geebee2.bmp and the rest in black.

Thank you for your help.

Code: Select all

DisableDebugger
Enumeration
  #Picture
  EndEnumeration
Procedure.f RandF()
  ProcedureReturn Random(10000) * 0.0001
EndProcedure

If OpenWindow(0, 0, 0, 640, 640, "2DDrawing Example", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  If CreateImage(0, 128, 128) And StartDrawing(ImageOutput(0))
    ;- Load picture
    ;LoadImage(#Picture, #PB_Compiler_Home + "Examples\Sources\Data\GeeBee2.bmp")
    sq=127:sq1=127:s2.f=sq/2:points=3
    Dim x.f(points):Dim y.f(points):Dim kl.f(points)
    For i = 0 To points
      x(i)=RandF()*sq: y(i)=RandF()*sq1
      g.f=127-127*(Abs(s2-x(i))/s2)+127-127*(Abs(s2-y(i))/s2)
      kl(i)=RGB(255-x(i)/sq*255,g,y(i)/sq*255)
    Next
    
    a.f:b.f:q.f
    
    For xx = 0 To sq
      For yy = 0 To sq1
        d = 307201
        For i = 0 To points
          a=x(i)-xx: b=y(i)-yy
          q=a*a+b*b
          If q < d
            d = q: kkl = i
          EndIf         
        Next
        Plot(xx, yy, kl(kkl))
      Next
    Next
    
    ;- Fill in black all areas except one
    For i=0 To points-1
      FillArea(x(i),y(i),-1,0)
    Next i

    StopDrawing()
    ImageGadget(0, 0, 0, 640, 640, ImageID(0))
  EndIf
  
  Repeat
    Event = WaitWindowEvent()
  Until Event = #PB_Event_CloseWindow
EndIf
jak64
Enthusiast
Enthusiast
Posts: 502
Joined: Sat Aug 15, 2020 5:02 pm
Location: Ciboure (France)

Re: Cut an image into several pieces

Post by jak64 »

Hello,
Here is the code that allows you to cut an image into several .bmp images that can be used as sprites, for example if you want to recompose a broken object in a game or destroyed in several pieces (explosion).

Of course, the program must be optimized if we want to choose any image and choose the number of desired pieces.

I just wanted it to work, at first...

Code: Select all

Enumeration
  #Picture
EndEnumeration

Procedure.f RandF()
  ProcedureReturn Random(10000) * 0.0001
EndProcedure

a.f:b.f:q.f

sq=127:sq1=127:s2.f=sq/2:points=9
Dim x.f(points):Dim y.f(points):Dim kl.f(points)
For i = 0 To points
  x(i)=RandF()*sq: y(i)=RandF()*sq1
  g.f=127-127*(Abs(s2-x(i))/s2)+127-127*(Abs(s2-y(i))/s2)
  kl(i)=RGB(255-x(i)/sq*255,g,y(i)/sq*255)
Next

OpenWindow(0, 0, 0, 800, 600, "DrawImage", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

;= Création des morceaux d'image avec des couleurs différentes
CreateImage(1, 128, 128)
a.f:b.f:q.f
StartDrawing(ImageOutput(1))
For xx = 0 To sq
  For yy = 0 To sq1
    d = 307201
    For i = 0 To points
      a=x(i)-xx: b=y(i)-yy
      q=a*a+b*b
      If q < d
        d = q: kkl = i
      EndIf         
    Next
    Plot(xx, yy, kl(kkl))
  Next
Next
StopDrawing()
ImageGadget(1, 150, 0, 128, 128, ImageID(1))

boucle.b
For boucle=0 To points
  ;= Chargement de l'image à découper
  If IsImage(0)
    FreeImage(0)
  EndIf
  If IsGadget(0)
    FreeGadget(0)
  EndIf
  CreateImage(0, 128, 128)
  StartDrawing(ImageOutput(0))
  LoadImage(#Picture, #PB_Compiler_Home + "Examples\Sources\Data\GeeBee2.bmp")
  StopDrawing() 
  ImageGadget(0, 0, 0, 128, 128, ImageID(#Picture))
  
  ;= Remplissage de tous les morceaux en noir sauf 1
  StartDrawing(ImageOutput(0))
  For xx = 0 To sq
    For yy = 0 To sq1
      d = 307201
      For i = 0 To points
        a=x(i)-xx: b=y(i)-yy
        q=a*a+b*b
        If q < d
          d = q: kkl = i
        EndIf         
      Next
      If kkl <> boucle
        Plot(xx, yy, 0)
      EndIf
    Next
  Next
  StopDrawing()
  ImageGadget(0, 0, 0, 128, 128, ImageID(0))
  
  
  ;= Sauvegarder l'image
  SaveImage(0, "Image" + Right("0"+Str(boucle),2)+".bmp", #PB_ImagePlugin_BMP)
Next boucle

MessageRequester("Découper images", Str(points+1) + " images crées")

Repeat
  Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow

Post Reply