Home > OS >  Crop image borders dynamically
Crop image borders dynamically

Time:12-24

How can I crop images that looks like this and save as 3 different images?

The issue is that images are different in size and non-proportional, so I want to make a code that dynamically cuts black borders but not the black part which is inside the picture.

Here is the desired outcome:

Desired outcome

Below is the sample code I've made which works only for one specific image.

from PIL import Image
im = Image.open(r"image.jpg")

# Setting the points for cropped image1
# im1 = im.crop((left, top, right, bottom))
im1 = im.crop((...))
im2 = im.crop((...))
im3 = im.crop((...))

im1 = im1.save(r"image1.jpg")
im2 = im2.save(r"image2.jpg")
im3 = im3.save(r"image3.jpg")

CodePudding user response:

Finally I've found the solution. Here is what I did:

from PIL import Image, ImageChops

def RemoveBlackBorders(img):
    bg = Image.new(img.mode, img.size, img.getpixel((0,0)))
    diff = ImageChops.difference(img, bg)
    diff = ImageChops.add(diff, diff, 2.0, -100)
    bbox = diff.getbbox()
    if bbox:
        return img.crop(bbox)

# Opens a image in RGB mode
im = Image.open(r"C:\Path\Image.jpg")

# removing borders

im = RemoveBlackBorders(im)

# getting midpoint from size

width, height = im.size
mwidth = width/2

# assign shape of figure from the midpoint

     #crop((x,y of top left, x, y of bottom right))
im1 = im.crop((0, 0, mwidth-135, height))
im2 = im.crop((mwidth-78, 0, mwidth 84, height))
im3 = im.crop((mwidth 135, 0, width, height))

The function to remove borders I've found from here.

Although the solution is not completely dynamic, it still solves my problem with ~90% accuracy. But I believe there should be a more universal approach for this problem.

CodePudding user response:

If the areas have always the same size and the same top and bottom coordinates the following should work:

The coordinates for the crops can be retrieved by calculating the sums per rows and per columns, then analyzing them.

import cv2
import numpy as np
im = cv2.imread(image_path)
sum_of_rows = np.sum(im, axis=(1,2))
sum_of_cols = np.sum(im, axis=(0,2))

The top and bottom can be calculated by calculating the sum for each row (each sum value being calculated R G B, the value should be zero for black). Then looking for the first value being different form zero and the last value being different than zero. Both indicating the top and bottom.

top = np.argmax(sum_of_rows > 0)
bottom = top   np.argmax(sum_of_rows[top:]==0)

The same can be done for the sum for each column, but here checking for multiple left and right values.

  • Related