I am implementing a Faster RCNN v2 Inception in Tensorflow Object Detection API. To remove redundant overlapping detections, I read that NMS should be applied.
One way of doing this is adjusting the NMS IOU Threshold in the config file first_stage_nms_iou_threshold
.
Questions
- What is this parameter exactly? To what value should this parameter be adjusted to (default value is 0.7)
- Why is it called
first_stage_nms_iou_threshold
? Why first stage only?
- Is there another easy and more effective way of removing redundant detections?
I can't anwser your first and second question but i had the same problem with overlapping bounding boxes and use the following code to fix them manually... You have to know the x1,y1,x2,y2 coordinates of your bounding boxes which are overlapping...
# import the necessary packages
from nms import non_max_suppression_slow
import numpy as np
import cv2
# path to your image
# and the coordinates x1,x2,y1,y2 of the overlapping bounding boxes
images = [
("path/to/your/image", np.array([
(664, 0, 988, 177),
(670, 10, 1000, 188),
(685, 20, 1015, 193),
(47, 100, 357, 500),
(55, 105, 362, 508),
(68, 120, 375, 520),
(978, 80, 1093, 206)]))]
# loop over the images
for (imagePath, boundingBoxes) in images:
# load the image and clone it
print("[x] %d initial bounding boxes" % (len(boundingBoxes)))
image = cv2.imread(imagePath)
orig = image.copy()
# loop over the bounding boxes for each image and draw them
for (startX, startY, endX, endY) in boundingBoxes:
cv2.rectangle(orig, (startX, startY), (endX, endY), (0, 0, 255), 2)
# perform non-maximum suppression on the bounding boxes
pick = non_max_suppression_slow(boundingBoxes, 0.3)
print("[x] after applying non-maximum, %d bounding boxes" % (len(pick)))
# loop over the picked bounding boxes and draw them
for (startX, startY, endX, endY) in pick:
cv2.rectangle(image, (startX, startY), (endX, endY), (0, 255, 0), 2)
# display the images
cv2.imshow("Original", orig)
cv2.imshow("After NMS", image)
cv2.waitKey(0)
and still need this :
# import the necessary packages
import numpy as np
def non_max_suppression_slow(boxes, overlapThresh):
# if there are no boxes, return an empty list
if len(boxes) == 0:
return []
# initialize the list of picked indexes
pick = []
# grab the coordinates of the bounding boxes
x1 = boxes[:,0]
y1 = boxes[:,1]
x2 = boxes[:,2]
y2 = boxes[:,3]
# compute the area of the bounding boxes and sort the bounding
# boxes by the bottom-right y-coordinate of the bounding box
area = (x2 - x1 + 1) * (y2 - y1 + 1)
idxs = np.argsort(y2)
# keep looping while some indexes still remain in the indexes
# list
while len(idxs) > 0:
# grab the last index in the indexes list, add the index
# value to the list of picked indexes, then initialize
# the suppression list (i.e. indexes that will be deleted)
# using the last index
last = len(idxs) - 1
i = idxs[last]
pick.append(i)
suppress = [last]
# loop over all indexes in the indexes list
for pos in range(0, last):
# grab the current index
j = idxs[pos]
# find the largest (x, y) coordinates for the start of
# the bounding box and the smallest (x, y) coordinates
# for the end of the bounding box
xx1 = max(x1[i], x1[j])
yy1 = max(y1[i], y1[j])
xx2 = min(x2[i], x2[j])
yy2 = min(y2[i], y2[j])
# compute the width and height of the bounding box
w = max(0, xx2 - xx1 + 1)
h = max(0, yy2 - yy1 + 1)
# compute the ratio of overlap between the computed
# bounding box and the bounding box in the area list
overlap = float(w * h) / area[j]
# if there is sufficient overlap, suppress the
# current bounding box
if overlap > overlapThresh:
suppress.append(pos)
# delete all indexes from the index list that are in the
# suppression list
idxs = np.delete(idxs, suppress)
# return only the bounding boxes that were picked
return boxes[pick]