Skip to content

Commit

Permalink
Remove soft-nms from the project
Browse files Browse the repository at this point in the history
  • Loading branch information
satsin06 committed Oct 4, 2023
1 parent a3ab088 commit 2fed13a
Show file tree
Hide file tree
Showing 3 changed files with 3 additions and 89 deletions.
3 changes: 0 additions & 3 deletions deepforest/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,6 @@ def predict_tile(self,
iou_threshold=0.15,
return_plot=False,
mosaic=True,
use_soft_nms=False,
sigma=0.5,
thresh=0.001,
color=None,
Expand All @@ -427,7 +426,6 @@ def predict_tile(self,
Lower values suppress more boxes at edges.
return_plot: Should the image be returned with the predictions drawn?
mosaic: Return a single prediction dataframe (True) or a tuple of image crops and predictions (False)
use_soft_nms: whether to perform Gaussian Soft NMS or not, if false, default perform NMS.
sigma: variance of Gaussian function used in Gaussian Soft NMS
thresh: the score thresh used to filter bboxes after soft-nms performed
color: color of the bounding box as a tuple of BGR color, e.g. orange annotations is (0, 165, 255)
Expand Down Expand Up @@ -466,7 +464,6 @@ def predict_tile(self,
if mosaic:
results = predict.mosiac(results,
ds.windows,
use_soft_nms=use_soft_nms,
sigma=sigma,
thresh=thresh,
iou_threshold=iou_threshold)
Expand Down
77 changes: 3 additions & 74 deletions deepforest/predict.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ def predict_image(model,

def mosiac(boxes,
windows,
use_soft_nms=False,
sigma=0.5,
thresh=0.001,
iou_threshold=0.1):
Expand All @@ -90,14 +89,9 @@ def mosiac(boxes,
dtype=torch.float32)
scores = torch.tensor(predicted_boxes.score.values, dtype=torch.float32)
labels = predicted_boxes.label.values

if use_soft_nms:
# Performs soft non-maximum suppression (soft-NMS) on the boxes.
bbox_left_idx = soft_nms(boxes=boxes, scores=scores, sigma=sigma, thresh=thresh)
else:
# Performs non-maximum suppression (NMS) on the boxes according to
# their intersection-over-union (IoU).
bbox_left_idx = nms(boxes=boxes, scores=scores, iou_threshold=iou_threshold)
# Performs non-maximum suppression (NMS) on the boxes according to
# their intersection-over-union (IoU).
bbox_left_idx = nms(boxes=boxes, scores=scores, iou_threshold=iou_threshold)

bbox_left_idx = bbox_left_idx.numpy()
new_boxes, new_labels, new_scores = boxes[bbox_left_idx].type(
Expand All @@ -119,71 +113,6 @@ def mosiac(boxes,
return mosaic_df


def soft_nms(boxes, scores, sigma=0.5, thresh=0.001):
"""
Perform python soft_nms to reduce the confidances of the proposals proportional to IoU value
Paper: Improving Object Detection With One Line of Code
Code : https://github.com/DocF/Soft-NMS/blob/master/softnms_pytorch.py
Args:
boxes: predicitons bounding boxes tensor format [x1,y1,x2,y2]
scores: the score corresponding to each box tensors
sigma: variance of Gaussian function
thresh: score thresh
Return:
idxs_keep: the index list of the selected boxes
"""
# indexes concatenate boxes with the last column
N = boxes.shape[0]
indexes = torch.arange(0, N, dtype=torch.float).view(N, 1)

boxes = torch.cat((boxes, indexes), dim=1)

# The order of boxes coordinate is [x1,y1,y2,x2]
x1 = boxes[:, 0]
y1 = boxes[:, 1]
x2 = boxes[:, 2]
y2 = boxes[:, 3]
areas = (x2 - x1 + 1) * (y2 - y1 + 1)

for i in range(N):
# intermediate parameters for later parameters exchange
tscore = scores[i].clone()
pos = i + 1

if i != N - 1:
maxscore, maxpos = torch.max(scores[pos:], dim=0)
if tscore < maxscore:
boxes[i], boxes[maxpos.item() + i +
1] = boxes[maxpos.item() + i +
1].clone(), boxes[i].clone()
scores[i], scores[maxpos.item() + i +
1] = scores[maxpos.item() + i +
1].clone(), scores[i].clone()
areas[i], areas[maxpos + i + 1] = areas[maxpos + \
i + 1].clone(), areas[i].clone()

# IoU calculate
xx1 = np.maximum(boxes[i, 0].numpy(), boxes[pos:, 0].numpy())
yy1 = np.maximum(boxes[i, 1].numpy(), boxes[pos:, 1].numpy())
xx2 = np.minimum(boxes[i, 2].numpy(), boxes[pos:, 2].numpy())
yy2 = np.minimum(boxes[i, 3].numpy(), boxes[pos:, 3].numpy())

w = np.maximum(0.0, xx2 - xx1 + 1)
h = np.maximum(0.0, yy2 - yy1 + 1)
inter = torch.tensor(w * h)
ovr = torch.div(inter, (areas[i] + areas[pos:] - inter))

# Gaussian decay
weight = torch.exp(-(ovr * ovr) / sigma)
scores[pos:] = weight * scores[pos:]

# select the boxes and keep the corresponding indexes
idxs_keep = boxes[:, 4][scores > thresh].int()

return idxs_keep


def across_class_nms(predicted_boxes, iou_threshold=0.15):
"""perform non-max suppression for a dataframe of results (see visualize.format_boxes) to remove boxes that overlap by iou_thresholdold of IoU"""

Expand Down
12 changes: 0 additions & 12 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,18 +175,6 @@ def test_predict_tile(m, raster_path):
assert isinstance(prediction, pd.DataFrame)
assert set(prediction.columns) == {"xmin","ymin","xmax","ymax","label","score","image_path"}
assert not prediction.empty

def test_predict_tile_softnms(m, raster_path):
#test soft-nms method
m.create_trainer()
soft_nms_pred = m.predict_tile(raster_path = raster_path,
patch_size = 300,
patch_overlap = 0.1,
return_plot = False,
use_soft_nms = True)
assert isinstance(soft_nms_pred, pd.DataFrame)
assert set(soft_nms_pred.columns) == {"xmin","ymin","xmax","ymax","label","score","image_path"}
assert not soft_nms_pred.empty

@pytest.mark.parametrize("patch_overlap",[0.1, 0])
def test_predict_tile_from_array(m, patch_overlap, raster_path):
Expand Down

0 comments on commit 2fed13a

Please sign in to comment.