Search code examples
pythonimagepython-imaging-librarycrop

Crop Multiple Parts from a List of Images with python


this is my code

#crop images
import numpy as np # linear algebra
import xml.etree.ElementTree as ET # for parsing XML
import matplotlib.pyplot as plt # to show images
from PIL import Image # to read images
import os
import glob

root_images="../img"
root_annots="../xmls"

all_images=os.listdir("../img")
print(f"Total images : {len(all_images)}")

breeds = glob.glob('../xmls')
annotation=[]
for b in breeds:
   annotation+=glob.glob(b+"/*")
print(f"Total annotation : {len(annotation)}")

breed_map={}
for annot in annotation:
   breed=annot.split("../")[-2]
   index=breed.split("-")[0]
   breed_map.setdefault(index,breed)

print(f"Total Breeds : {len(breed_map)}")

def bounding_box(image):
   bpath=root_annots+"/"+str(image.split(".")[0]+".xml")
   tree = ET.parse(bpath)
   root = tree.getroot()
   objects = root.findall('object')
   
   for o in objects:
       bndbox = o.find('bndbox') # reading bound box
       xmin = int(bndbox.find('xmin').text)
       ymin = int(bndbox.find('ymin').text)
       xmax = int(bndbox.find('xmax').text)
       ymax = int(bndbox.find('ymax').text)
    
    
   return (xmin,ymin,xmax,ymax)

plt.figure(figsize=(10,10))
bbox=[]
for i,image in enumerate(all_images):
   bbox=bounding_box(image) 
   print(box)  
   im=Image.open(os.path.join(root_images,image))
   im=im.crop(bbox)
   im.save('../result_imgs/{}.jpeg'.format(i,im)) 

this piece of code works for a list of images but it only crops one bounding box per image while there is multiple bounding boxes present in the XML files. But I want to crop multiple bounding boxes per image from a list of image. So can anyone help me out with this? Thanks.


Solution

  • your bounding_box(image) function only return 1 bounding box. (each time a new bounding box is found for a given image, it overwrite the previous one) i think you yould do something like this in the bounding_box() function:

    bboxes = [] #a list of all the bounding boxes for an image
    for o in objects:
           bndbox = o.find('bndbox') # reading bound box
           xmin = int(bndbox.find('xmin').text)
           ymin = int(bndbox.find('ymin').text)
           xmax = int(bndbox.find('xmax').text)
           ymax = int(bndbox.find('ymax').text)
           bboxes.append(xmin,ymin,xmax,ymax)
    return(bboxes)
    

    and in your image loop:

    bboxes=bounding_boxes(image) 
    j = 0
    for bbox in bboxes:
       im=Image.open(os.path.join(root_images,image))
       im=im.crop(bbox)
       im.save('../result_imgs/{}.jpeg'.format(i,im,j))
       j += 1