-1

Iam using an object detection algorithm to detect objects in an image. The code is as below. Image used is of a car as below.

I would like to crop the original image to keep only the object detected in the image PLUS whatever is necessary to maintain aspect ratio between 4/3 and 16/9.

The box around the car is already deduced from below algorithm [variable is box] and the image dimensions are [variable is height,width] in below code.

If we were to do this manually, it would be cumbersome due to the multiple iterations required, as an example: we have to ensure that resizing does not extend beyond the original image size.

There are 3 images included below, the original image, the modified image with car detected, and the resized image to meet a aspect ratio range.(4/3 to 16/9)

Is there an existing function within python to accomplish this task. Hence, resizing/increasing box dimensions from [91, 90, 226, 158] to the minimum necessary amount to be within the limits of original image size 183x275 while maintaining the aspect ratio

Thanks in advance.

CODE:

import cv2
import matplotlib.pyplot as plt
import cvlib as cv
from cvlib.object_detection import draw_bbox
imagepath='/home/usr/Desktop/car.jpeg'
img = cv2.imread(imagepath)


####STEP 1
img1 = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)

box, label, count = cv.detect_common_objects(img)
output = draw_bbox(img, box, label, count)    
output = cv2.cvtColor(output,cv2.COLOR_BGR2RGB)
plt.figure(figsize=(10,10))
plt.axis('off')
plt.imshow(output)
plt.show()

print("Number of objects in this image are " +str(len(label)))

height,width,_=img1.shape

print(height,width)

print(box)
#box size is [91, 90, 226, 158] (w1,h1,w2,h2)
#image size is 183x275 (heightxwidth)



#STEP2 (cropping original image to car dimensions as per box size)
crop_img = img[90:158, 91:226]
cv2.imshow("cropped", crop_img)
cv2.waitKey(0)

Image Example:

enter image description here

Detect Object (Step1)

enter image description here

Crop Image (Step2)

enter image description here

Expected Outcome(Step3)

enter image description here

Christoph Rackwitz
  • 11,317
  • 4
  • 27
  • 36
The Oracle
  • 388
  • 1
  • 9
  • 23
  • If you have the dimensions of the bounding rectangle you could use [numpy slicing to crop the image](https://stackoverflow.com/questions/15589517/how-to-crop-an-image-in-opencv-using-python). That takes care of your first requirement. It is not clear for me if you then want to resize the cropped image after - to resize it to a scale of what? Or do you want the bounding rectangle to maintain a certain aspect ratio? – stateMachine Dec 21 '21 at 08:40
  • I have added an image and modified the image tags for clearer explanation, I want to go from step2 to step3. That is, increase the image size such that it is within aspect ratio between 4/3 and 16/9. – The Oracle Dec 21 '21 at 08:50
  • 1
    this sounds like trivial calculations. take the bbox (that shouldn't go outside the image!), enlarge to desired aspect ratio, move into view if outside (which will always keep the original bbox inside of it). -- what *precisely* is the trouble with that? write code as far as you can go. – Christoph Rackwitz Dec 21 '21 at 09:19
  • Its doable for 1 image, but i want to perform such operation for many images without manually evaluating each image. is there an available function available suitable for this task. thanks!! – The Oracle Dec 21 '21 at 09:33
  • uh, you just need a few functions, and then you can apply them to each of your bboxes, right? `enlarge_bbox_to_aspect_ratio(bbox, aspect_ratio)` and `move_bbox_into_view(bbox, width, height)` – Christoph Rackwitz Dec 21 '21 at 11:39

1 Answers1

0

The below code crops the image to required coordinates, then increases its size to match the aspect ratio depending if its >16/9 or <4/3. Advantage of this method is that it will not crop the centre object (car) when it resizes the image and corrects aspect ratio, and will increase left side of image if there is no space to increase in right side (and viceversa,for height and width) to achieve the Aspect ratio

import cv2
import math
import sys
imagepath=('/home/usr/Desktop/filename.jpeg')
img=cv2.imread(imagepath)
h,w,_=img.shape#height and width of original image


#Dimensions of car or object you want to crop (See step 2 in question)
crop_dimensions=[96, 56, 602, 686] #w1,h1,w2,h2

def cropimage(crop_dimensions,imgx):
    crop_img = imgx[crop_dimensions[1]:crop_dimensions[3], crop_dimensions[0]:crop_dimensions[2]]
    return crop_img

crop_img=cropimage(crop_dimensions,img)
height,width,_=crop_img.shape #height and width of cropped image



if width/height>16/9 or width/height<4/3:
    crop_centrepoint = ((crop_dimensions[2] - crop_dimensions[0])/2, (crop_dimensions[3] - crop_dimensions[1])/2) 
    print(crop_centrepoint) #Centre point of cropped image 

    if width/height<4/3:
        print('<4/3')

        newwidth=4/3*height
        newheight=height

        additionalwidth=newwidth-width

        w1maxadditional = crop_dimensions[0] - 0 #distance from cropped image to left edge (0) 
        w2maxadditional=w-crop_dimensions[2]#distance between cropped image and right end

        if w2maxadditional > additionalwidth/2:
            correction2=0
            w2=(additionalwidth/2)
        else:
            correction2=abs(w2maxadditional-(additionalwidth/2))
            w2=w2maxadditional

        if w1maxadditional > additionalwidth/2:
            correction1=0
            w1=(additionalwidth/2)+correction1
        else:
            correction1=abs(w2maxadditional-(additionalwidth/2))
            w1=w1maxadditional

        w1=w1+correction2
        w2 = w2+correction1
        if w1>w1maxadditional:
            w1=w1maxadditional
        if w2>w2maxadditional:
            w2=w2maxadditional

        w1 = crop_dimensions[0] - w1
        w2 = w2 + crop_dimensions[2]
        h1=crop_dimensions[1]
        h2=crop_dimensions[3]

    if width / height > 16/9:
        print('>16/9')

        newheight = width * 9 / 16
        newwidth = width

        additionalheight = newheight - height

        h1maxadditional = crop_dimensions[1] - 0  # distance from cropped image to top edge

        h2maxadditional = h - crop_dimensions[3]  # distance between cropped image to bottom end

        if h2maxadditional > additionalheight / 2:
            correction2 = 0
            h2 = (additionalheight / 2)
        else:
            correction2 = abs(h2maxadditional - (additionalheight / 2))
            h2 = h2maxadditional

        if h1maxadditional > additionalheight / 2:
            correction1 = 0
            h1 = (additionalheight / 2) + correction1
        else:
            correction1 = abs(h2maxadditional - (additionalheight / 2))
            h1 = h1maxadditional

        h1 = h1 + correction2
        h2 = h2 + correction1
        if h1 > h1maxadditional:
            h1 = h1maxadditional
        if h2 > h2maxadditional:
            h2 = h2maxadditional


        h1 = crop_dimensions[1] - h1
        h2 = h2 + crop_dimensions[3]

        w1 = crop_dimensions[0]
        w2 = crop_dimensions[2]

else:
    [w1,h1,w2,h2]=crop_dimensions 

#Rounding down because cropimage function takes integers
w1=math.trunc(w1)
h1=math.trunc(h1)
w2=math.trunc(w2)
h2=math.trunc(h2)




new_image=cropimage([w1,h1,w2,h2],img)

cv2.imshow('img',new_image)
cv2.waitKey(0)
The Oracle
  • 388
  • 1
  • 9
  • 23