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:
Then this is the result I get when running the above code:
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