Home > Mobile >  Given an image with several bounding boxes, how do I highlight only those bounding boxes that are co
Given an image with several bounding boxes, how do I highlight only those bounding boxes that are co

Time:12-26

I don't want to highlight bounding boxes that are either partly overlapping with others, or not overlapping with any other box. I tried to do this by detecting contours:

import cv2

# Read input image
img = cv2.imread('image.png')

# Convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Apply threshold
_, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY   cv2.THRESH_OTSU)

# Find contours and hierarchy
cnts, hier = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[-2:]

# Draw all contours with green color for testing
cv2.drawContours(img, cnts, -1, (0, 255, 0))

# Hierarchy Representation in OpenCV
# So each contour has its own information regarding what hierarchy it is, 
# who is its child, who is its parent etc. 
# OpenCV represents it as an array of four values : [Next, Previous, First_Child, Parent]

# Iterate contours and hierarchy:
for c, h in zip(cnts, hier[0]):
    # Check if contour has one partent and one at least on child:
    if (h[3] >= 0) and (h[2] >= 0):
        # Get the partent from the hierarchy
        hp = hier[0][h[3]]

        # Check if the parent has a parent:
        if hp[3] >= 0:
            # Get bounding rectange
            x, y, w, h = cv2.boundingRect(c)

            # Draw red rectange for testing
            cv2.rectangle(img, (x, y), (x w, y h), (0, 0, 255), thickness=1)


# Show result for testing
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

But its selecting every contour in the image. For example, if this is the original image:

enter image description here

Then this is the result I get when running the above code:

enter image description here

How do I, firstly, detect only bounding boxes in this image, and secondly, highlight only those bounding boxes that are completely, 100% inside another bounding box?

CodePudding user response:

Step 1. Sort the bounding boxes in increasing order of area using cv2.contourArea. See this question.

Step 2 - For loop - starting with the smallest bounding boxes - Check if a given box's intersection area with bigger boxes = area of given box. If yes, then it is 100% inside other bigger box.

For example we can convert a bounding box into a mask like this:

mask = np.zeros(img.shape[:2], dtype=np.float32)
(x, y, w, h) = [int(v) for v in bounding_box]
mask[y:y h, x:x w] = 1. 

Then to get the area of intersection of two masks:

mask1_f = mask1.flatten()
mask2_f = mask2.flatten()
intersection = np.sum(mask1_f * mask2_f)

CodePudding user response:

For a box to be completely inside another box, each vertex of the box should be inside the bigger box. You can use a nested for loop to filter the boxes to check if all coordinates of the box2 is within range of box1.

collided_boxes = []
for box1 in boxes:
    for box2 in boxes:
        if box1 != box2:
            if (box1[0] < box2[0] < box1[2] and box1[1] < box2[1] < box1[3]) and (box1[0] < box2[2] < box1[2] and box1[1] < box2[1] < box1[3]) and (box1[0] < box2[2] < box1[2] and box1[1] < box2[3] < box1[3]) and (box1[0] < box2[0] < box1[2] and box1[1] < box2[3] < box1[3]): 
                if box2 not in collided_boxes:
                    collided_boxes.append(box2)

In above, I gave values of the coordinates of the two extreme corners of the box which is [(min x value, min y value) and (max x value, max y value)] as: box[0] = min x value, box[1] = min y value, box[2] = max x value, box[3] = max y value

  • Related