import numpy as np import logging import cv2 def xyxy2xywh(x): y = np.copy(x) y[:, 0] = (x[:, 0] + x[:, 2]) / 2 # x center y[:, 1] = (x[:, 1] + x[:, 3]) / 2 # y center y[:, 2] = x[:, 2] - x[:, 0] # width y[:, 3] = x[:, 3] - x[:, 1] # height return y def xywh2xyxy(x): # Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right y = np.copy(x) y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y return y def nms(bboxes, scores, iou_thresh): """ :param bboxes: 检测框列表 :param scores: 置信度列表 :param iou_thresh: IOU阈值 :return: """ x1 = bboxes[:, 0] y1 = bboxes[:, 1] x2 = bboxes[:, 2] y2 = bboxes[:, 3] areas = (y2 - y1) * (x2 - x1) # 结果列表 result = [] index = scores.argsort()[::-1] # 对检测框按照置信度进行从高到低的排序,并获取索引 # 下面的操作为了安全,都是对索引处理 while index.size > 0: # 当检测框不为空一直循环 i = index[0] result.append(i) # 将置信度最高的加入结果列表 # 计算其他边界框与该边界框的IOU x11 = np.maximum(x1[i], x1[index[1:]]) y11 = np.maximum(y1[i], y1[index[1:]]) x22 = np.minimum(x2[i], x2[index[1:]]) y22 = np.minimum(y2[i], y2[index[1:]]) w = np.maximum(0, x22 - x11 + 1) h = np.maximum(0, y22 - y11 + 1) overlaps = w * h ious = overlaps / (areas[i] + areas[index[1:]] - overlaps) # 只保留满足IOU阈值的索引 idx = np.where(ious <= iou_thresh)[0] index = index[idx + 1] # 处理剩余的边框 # bboxes, scores = bboxes[result], scores[result] # return bboxes, scores return result def non_max_suppression(prediction, conf_thres=0.25, iou_thres=0.45, classes=None, agnostic=False, multi_label=False, max_det=300): max_wh = 7680 # (pixels) maximum box width and height max_nms = 30000 # maximum number of boxes into torchvision.ops.nms() batch_size = prediction.shape[0] class_number = prediction.shape[2]-5 #85-5 xc = prediction[..., 4] > conf_thres output = [np.zeros((0,6))] * batch_size box = prediction[xc == True] print("box.shape:",box.shape) print("box:", sorted(box[...,4], reverse=True)) for xi, x in enumerate(prediction): #对应的元素和索引 xi是索引 x是元素 x = x[xc[xi]] x[:, 5:] *= x[:, 4:5] # conf = obj_conf * cls_conf box = xywh2xyxy(x[:, :4]) # Detections matrix nx6 (xyxy, conf, cls) conf, j = x[:, 5:].max(1, keepdims=True), x[:, 5:].argmax(1)[:,None] #选出25200个框中,每个框概率最大的类别 x = np.concatenate((box, conf, j), 1)[conf.reshape(-1) > conf_thres] # n = x.shape[0] # number of boxes if not n: # no boxes continue elif n > max_nms: # excess boxes x = x[x[:, 4].argsort(descending=True)[:max_nms]] # sort by confidence c = x[:, 5:6] * (0 if agnostic else max_wh) # classes boxes, scores = x[:, :4] + c, x[:, 4] # boxes (offset by class), scores i = nms(boxes, scores, iou_thres) # NMS if len(i) > max_det: # limit detections i = i[:max_det] output[xi] = x[i] return output