# Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Based on: # -------------------------------------------------------- # Detectron # Copyright (c) 2017-present, Facebook, Inc. # Licensed under the Apache License, Version 2.0; # Written by Ross Girshick # -------------------------------------------------------- from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals import numpy as np def xywh_to_xyxy(xywh): """Convert [x1 y1 w h] box format to [x1 y1 x2 y2] format.""" if isinstance(xywh, (list, tuple)): # Single box given as a list of coordinates assert len(xywh) == 4 x1, y1 = xywh[0], xywh[1] x2 = x1 + np.maximum(0., xywh[2] - 1.) y2 = y1 + np.maximum(0., xywh[3] - 1.) return (x1, y1, x2, y2) elif isinstance(xywh, np.ndarray): # Multiple boxes given as a 2D ndarray return np.hstack( (xywh[:, 0:2], xywh[:, 0:2] + np.maximum(0, xywh[:, 2:4] - 1))) else: raise TypeError('Argument xywh must be a list, tuple, or numpy array.') def xyxy_to_xywh(xyxy): """Convert [x1 y1 x2 y2] box format to [x1 y1 w h] format.""" if isinstance(xyxy, (list, tuple)): # Single box given as a list of coordinates assert len(xyxy) == 4 x1, y1 = xyxy[0], xyxy[1] w = xyxy[2] - x1 + 1 h = xyxy[3] - y1 + 1 return (x1, y1, w, h) elif isinstance(xyxy, np.ndarray): # Multiple boxes given as a 2D ndarray return np.hstack((xyxy[:, 0:2], xyxy[:, 2:4] - xyxy[:, 0:2] + 1)) else: raise TypeError('Argument xyxy must be a list, tuple, or numpy array.') def clip_xyxy_to_image(x1, y1, x2, y2, height, width): """Clip coordinates to an image with the given height and width.""" x1 = np.minimum(width - 1., np.maximum(0., x1)) y1 = np.minimum(height - 1., np.maximum(0., y1)) x2 = np.minimum(width - 1., np.maximum(0., x2)) y2 = np.minimum(height - 1., np.maximum(0., y2)) return x1, y1, x2, y2 def nms(dets, thresh): """Apply classic DPM-style greedy NMS.""" if dets.shape[0] == 0: return [] x1 = dets[:, 0] y1 = dets[:, 1] x2 = dets[:, 2] y2 = dets[:, 3] scores = dets[:, 4] areas = (x2 - x1 + 1) * (y2 - y1 + 1) order = scores.argsort()[::-1] ndets = dets.shape[0] suppressed = np.zeros((ndets), dtype=np.int) # nominal indices # _i, _j # sorted indices # i, j # temp variables for box i's (the box currently under consideration) # ix1, iy1, ix2, iy2, iarea # variables for computing overlap with box j (lower scoring box) # xx1, yy1, xx2, yy2 # w, h # inter, ovr for _i in range(ndets): i = order[_i] if suppressed[i] == 1: continue ix1 = x1[i] iy1 = y1[i] ix2 = x2[i] iy2 = y2[i] iarea = areas[i] for _j in range(_i + 1, ndets): j = order[_j] if suppressed[j] == 1: continue xx1 = max(ix1, x1[j]) yy1 = max(iy1, y1[j]) xx2 = min(ix2, x2[j]) yy2 = min(iy2, y2[j]) w = max(0.0, xx2 - xx1 + 1) h = max(0.0, yy2 - yy1 + 1) inter = w * h ovr = inter / (iarea + areas[j] - inter) if ovr >= thresh: suppressed[j] = 1 return np.where(suppressed == 0)[0]