How to split an image horizontally into equal-sized pieces?

Viewed 1437

I am trying to split this input image into three/four equal-sized pieces horizontally but I am not getting the desired output. I don't know what I am doing wrong. Here is the code which I wrote to split it:

import os.path
import numpy as np
from PIL import image

input_1 = "/home/task-1/split_operation/111.jpg"
outputPath = "/home/task-1/split_operation/"
im = Image.open(input_1)
x_width, y_height = im.size
split = np.int(x_width / 3)
outputFileFormat = "{0}-{1}.jpg"
baseName = "cropped_1"
for i in range(0, x_width, split):
    x = split + i
    box = (x, 0, x + split, y_height)
    a = im.crop(box)
    a.load()
    outputName = os.path.join(outputPath, outputFileFormat.format(baseName, i + 1))
    a.save(outputName, "JPEG")

The input image:

Itś an input image

The output images I currently get:

As you can see last two images are black. I don't know why I am getting a black image.

2 Answers

Your problem is that when i=0 your first x is split which means you skip the first image. You can actually see that the first image doesn't align with the edge of the original. In addition, you are rounding the pixels to use as a step to the range function but this creates a problematic behaviour: your image's width is 800 pixels. This means that your split is 266. This means that the last i value is going to be 798 and this is why the third image has a thin line of 2 pixels at the left edge.

A better way will be to generate all "edges" using np.linspace. This assures the right amount of pictures in the exact right sizes instead of bothering with range loops and width calculations. Just create the edges list and use it in the loop as follows:

...
pictures = 3
edges = np.linspace(0, x_width, pictures+1)
for start, end in zip(edges[:-1], edges[1:]):
    box = (start, 0, end, y_height)
    ...

The rest stays the same.


Running this with pictures = 3 will produce:

Running with pictures = 4 will produce:

`

I will assume that width of the image is 900px. Then split = 300

Let's look at first few iterations of your for loop:

  1. i = 0; x = 300; x + split = 600
  2. i = 300; x = 300 + 300 = 600; x + split = 900 ...

As you can see, part of the image (0--300px) is missing. It could be easily fixed:

for i in range(0, x_width, split):
    box = (i, 0, i + split, y_height)
    ...

The reason you getting black images is just because you try to access pixels that are not part of the image.

Related