2

I need to split an RGBA image into an arbitrary number of boxes that are as equally sized as possible

I have attempted to use numpy.array_split, but am unsure of how to do so while preserving the RGBA channels

I have looked the following questions, none of them detail how to split an image into n boxes, they reference splitting the image into boxes of predetermined pixel size, or how to split the image into some shape.

While it seems that it would be some simple math to get number of boxes from box size and image size, I am unsure of how to do so.

How to Split Image Into Multiple Pieces in Python

Cutting one image into multiple images using the Python Image Library

Divide image into rectangles information in Python

While attempting to determine the number of boxes from pixel box size, I used the formula

num_boxes = (img_size[0]*img_size[1])/ (box_size_x * box_size_y)

but that did not result in the image being split up properly

To clarify, I would like to be able to input an image that is a numpy array of size (a,b,4) and a number of boxes and output the images in some form (np array preferred, but whatever works)

I appreciate any help, even if you aren't able to provide the full method, I would appreciate some direction.

I have tried

def split_image(image, n_boxes):
    return numpy.array_split(image,n_boxes)
    #doesn't work with colors

def split_image(image, n_boxes):
    box_size = factor_int(n_boxes)
    M = im.shape[0]//box_size[0]
    N = im.shape[1]//box_size[1]

    return [im[x:x+M,y:y+N] for x in range(0,im.shape[0],M) for y in range(0,im.shape[1],N)]

factor_int returns integer as close to a square as possible from Factor an integer to something as close to a square as possible

H. Khan
  • 111
  • 12
  • 3
    could you edit your question to provide any code you have tried? – DrBwts Jul 05 '19 at 09:49
  • 1x1 pixel boxes are equal size and guarantee to cover any rectangular image. Please state the _real_ limitations you have for your boxes. Computing the box size is the hard part; cutting out sub-images by rectangle coordinates is trivial. – 9000 Jul 05 '19 at 16:32
  • Just find whichever is larger of `a` and `b` and divide that by `N`. – Mark Setchell Jul 05 '19 at 16:46
  • @9000 I'm not sure what you mean by real limitations, I simply wish to cut an image into n boxes (n: 1→ num_pixels). – H. Khan Jul 05 '19 at 18:57
  • @MarkSetchell Are these 'a' and 'b' values the x and y sizes of the pixel box? – H. Khan Jul 05 '19 at 18:58
  • @DrBwts I have added my attempts, thank you. – H. Khan Jul 05 '19 at 19:11
  • It's unclear what you are really trying to do, if your image is 500 pixels wide and 400px tall and you want 4 boxes, you could get them each 125 wide and 400 tall. Or you could get each 500 wide and 100 tall. Both solutions have equal size boxes... what are the actual criteria and what are typical widths/heights and numbers of boxes? – Mark Setchell Jul 08 '19 at 22:20
  • @MarkSetchell I would like the width and height to be as close to each other as possible, which is why I used factor_int. – H. Khan Jul 09 '19 at 13:43
  • You could use Imagemagick's crop into equally sized regions tool. See https://imagemagick.org/Usage/crop/#crop_equal – fmw42 Jul 09 '19 at 23:13
  • Possibly view_as_blocks from skimage? See https://scikit-image.org/docs/dev/api/skimage.util.html#view-as-blocks – fmw42 Jul 09 '19 at 23:24

1 Answers1

2

I am still not sure if your inputs are actually the image and the dimensions of the boxes or the image and the number of boxes. Nor am I sure if your problem is deciding where to chop the image or knowing how to chop a 4-channel image, but maybe something in here will get you started.

I started with this RGBA image - the circles are transparent, not white:

enter image description here

#!/usr/bin/env python3

from PIL import Image
import numpy as np
import math

# Open image and get dimensions
im = Image.open('start.png').convert('RGBA') 

# Make Numpy array from image and get height and width
ni = np.array(im)
h ,w = ni.shape[:2]
print(f'Height: {h}, width: {w}')

BOXES = 4
for i in range(BOXES):
    this = ni[:, i*w//BOXES:(i+1)*w//BOXES, :]
    Image.fromarray(this).save(f'box-{i}.png') 

You can change BOXES but leaving it at 4 gets you these 4 output images:

enter image description here [enter image description here] [enter image description here]4 enter image description here

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
  • here is a version for two dimensions. columns = 3 rows = 4 for j in range(rows): for i in range(columns): elem = ni[ j*w//columns:(j+1)*w//columns, i*h//rows:(i+1)*h//rows,:] id=j*columns+i Image.fromarray(elem).save(f'img-{id}.png') – roarc Jul 11 '20 at 13:27
  • sorry for the post above I wanted to comment here – roarc Jul 11 '20 at 13:36