0

I have a 1024x1024 image and I want to slice it with boxes which are different sizes and will be selected randomly. For example 2 pieces 512x512,8 pieces 16x16 etc. Box positions is not important. And I want to use every pixel only one time. Below is my code but when I run it, a lot of pictures are created and same regions are being used. How can I make that each pixel will be used only 1 time. Below picture represents which I want.

'''

from PIL import Image
import random

infile = 'Da Vinci.jpg'

chopsize = [512,256,128,64,32]

img = Image.open(infile)
width, height = img.size

a= random.choice(chopsize)
for x0 in range(0, width):
   for y0 in range(0, height):
      box = (x0, y0,
             x0+random.choice(chopsize) if x0+random.choice(chopsize) <  width else  width - 1,
             y0+random.choice(chopsize) if y0+random.choice(chopsize) < height else height - 1)
      print('%s %s' % (infile, box))
      img.crop(box).save('%s.x%01d.y%01d.jpg' % (infile.replace('.jpg',''), x0, y0))
      a=random.choice(chopsize)

That is what I want:

That is what I want

Christoph Rackwitz
  • 11,317
  • 4
  • 27
  • 36
  • *random* arrangements (or whatever looks "random") might be an NP problem. your problem should go on https://math.stackexchange.com/ – Christoph Rackwitz Dec 23 '21 at 17:53
  • I’m voting to close this question because it's about math, not programming. – Christoph Rackwitz Dec 23 '21 at 17:54
  • I think you could adapt the technique used in my answer to the question [How can I randomly place several non-colliding rects?](https://stackoverflow.com/questions/4373741/how-can-i-randomly-place-several-non-colliding-rects) to do what's needed. It recursively subdivides a rectangle into smaller pieces. – martineau Dec 23 '21 at 17:57

1 Answers1

0

This is a fun problem! How do you randomly tile with your boxes an area but make sure none of the boxes overlap.

You have a couple of issues:

  1. as you've written your code so far you are going to have boxes that spill over the border of your image. I don't know if you care about this - in your example picture the boxes fit perfectly into the space. If you do care you are going to have to figure that part out.

(although this code makes me think you have thought about it and don't care)

x0+random.choice(chopsize) if x0+random.choice(chopsize) <  width else  width - 1
  1. The other issue which is what your question is really about is that you don't save a record of what pixels you have already visited. There are a few different ways you could do this.

One might be something like:

import numpy as np
filled_pixels = np.zeros((width, height))
x = 0
while x < width:
  y=0
  if filled_pixels[x,y] == 1:
       x+=32 #the minimum dimensions of a square
  while y < height:
    chop = random.choice(chopsize)
    if filled_pixels[x,y] == 1:
       y+=1 #the minimum dimensions of a square
    else:
       filled_pixels[x:x+chop,y:y+chop] = 1
       #do your stuff with making the boxes
       y+=chop

you basically could raster through your image making boxes, making sure that you aren't making a square at any pixel where you already have a square (given by your filled value)

  • Thank you for your comment. It gave me a good perspective. But when I tried I faced below error. x[x:x + chop, y:y + chop] = 1 TypeError: 'int' object does not support item assignment – bandit_hilmi Dec 23 '21 at 21:57
  • @bandit_hilmi that's because there was a typo - it should have been filled_pixels[x:x+chop.... - i've fixed it in my answer, but it wasn't supposed to be running code, rather a suggestion for how to solve the problem – Ned Booker Jan 11 '22 at 19:52