|
import numpy as np |
|
import cv2 |
|
|
|
class NanoDet: |
|
def __init__(self, modelPath, prob_threshold=0.35, iou_threshold=0.6, backend_id=0, target_id=0): |
|
self.strides = (8, 16, 32, 64) |
|
self.image_shape = (416, 416) |
|
self.reg_max = 7 |
|
self.prob_threshold = prob_threshold |
|
self.iou_threshold = iou_threshold |
|
self.backend_id = backend_id |
|
self.target_id = target_id |
|
self.project = np.arange(self.reg_max + 1) |
|
self.mean = np.array([103.53, 116.28, 123.675], dtype=np.float32).reshape(1, 1, 3) |
|
self.std = np.array([57.375, 57.12, 58.395], dtype=np.float32).reshape(1, 1, 3) |
|
self.net = cv2.dnn.readNet(modelPath) |
|
self.net.setPreferableBackend(self.backend_id) |
|
self.net.setPreferableTarget(self.target_id) |
|
|
|
self.anchors_mlvl = [] |
|
for i in range(len(self.strides)): |
|
featmap_size = (int(self.image_shape[0] / self.strides[i]), int(self.image_shape[1] / self.strides[i])) |
|
stride = self.strides[i] |
|
feat_h, feat_w = featmap_size |
|
shift_x = np.arange(0, feat_w) * stride |
|
shift_y = np.arange(0, feat_h) * stride |
|
xv, yv = np.meshgrid(shift_x, shift_y) |
|
xv = xv.flatten() |
|
yv = yv.flatten() |
|
cx = xv + 0.5 * (stride-1) |
|
cy = yv + 0.5 * (stride - 1) |
|
|
|
anchors = np.column_stack((cx, cy)) |
|
self.anchors_mlvl.append(anchors) |
|
|
|
@property |
|
def name(self): |
|
return self.__class__.__name__ |
|
|
|
def setBackendAndTarget(self, backendId, targetId): |
|
self.backend_id = backendId |
|
self.target_id = targetId |
|
self.net.setPreferableBackend(self.backend_id) |
|
self.net.setPreferableTarget(self.target_id) |
|
|
|
def pre_process(self, img): |
|
img = img.astype(np.float32) |
|
img = (img - self.mean) / self.std |
|
blob = cv2.dnn.blobFromImage(img) |
|
return blob |
|
|
|
def infer(self, srcimg): |
|
blob = self.pre_process(srcimg) |
|
self.net.setInput(blob) |
|
outs = self.net.forward(self.net.getUnconnectedOutLayersNames()) |
|
preds = self.post_process(outs) |
|
return preds |
|
|
|
def post_process(self, preds): |
|
cls_scores, bbox_preds = preds[::2], preds[1::2] |
|
rescale = False |
|
scale_factor = 1 |
|
bboxes_mlvl = [] |
|
scores_mlvl = [] |
|
for stride, cls_score, bbox_pred, anchors in zip(self.strides, cls_scores, bbox_preds, self.anchors_mlvl): |
|
if cls_score.ndim==3: |
|
cls_score = cls_score.squeeze(axis=0) |
|
if bbox_pred.ndim==3: |
|
bbox_pred = bbox_pred.squeeze(axis=0) |
|
|
|
x_exp = np.exp(bbox_pred.reshape(-1, self.reg_max + 1)) |
|
x_sum = np.sum(x_exp, axis=1, keepdims=True) |
|
bbox_pred = x_exp / x_sum |
|
bbox_pred = np.dot(bbox_pred, self.project).reshape(-1,4) |
|
bbox_pred *= stride |
|
|
|
nms_pre = 1000 |
|
if nms_pre > 0 and cls_score.shape[0] > nms_pre: |
|
max_scores = cls_score.max(axis=1) |
|
topk_inds = max_scores.argsort()[::-1][0:nms_pre] |
|
anchors = anchors[topk_inds, :] |
|
bbox_pred = bbox_pred[topk_inds, :] |
|
cls_score = cls_score[topk_inds, :] |
|
|
|
points = anchors |
|
distance = bbox_pred |
|
max_shape=self.image_shape |
|
x1 = points[:, 0] - distance[:, 0] |
|
y1 = points[:, 1] - distance[:, 1] |
|
x2 = points[:, 0] + distance[:, 2] |
|
y2 = points[:, 1] + distance[:, 3] |
|
|
|
if max_shape is not None: |
|
x1 = np.clip(x1, 0, max_shape[1]) |
|
y1 = np.clip(y1, 0, max_shape[0]) |
|
x2 = np.clip(x2, 0, max_shape[1]) |
|
y2 = np.clip(y2, 0, max_shape[0]) |
|
|
|
|
|
bboxes = np.column_stack([x1, y1, x2, y2]) |
|
bboxes_mlvl.append(bboxes) |
|
scores_mlvl.append(cls_score) |
|
|
|
bboxes_mlvl = np.concatenate(bboxes_mlvl, axis=0) |
|
if rescale: |
|
bboxes_mlvl /= scale_factor |
|
scores_mlvl = np.concatenate(scores_mlvl, axis=0) |
|
bboxes_wh = bboxes_mlvl.copy() |
|
bboxes_wh[:, 2:4] = bboxes_wh[:, 2:4] - bboxes_wh[:, 0:2] |
|
classIds = np.argmax(scores_mlvl, axis=1) |
|
confidences = np.max(scores_mlvl, axis=1) |
|
|
|
indices = cv2.dnn.NMSBoxes(bboxes_wh.tolist(), confidences.tolist(), self.prob_threshold, self.iou_threshold) |
|
|
|
if len(indices)>0: |
|
det_bboxes = bboxes_mlvl[indices] |
|
det_conf = confidences[indices] |
|
det_classid = classIds[indices] |
|
|
|
return np.concatenate([det_bboxes, det_conf.reshape(-1, 1), det_classid.reshape(-1, 1)], axis=1) |
|
else: |
|
return np.array([]) |
|
|