forked from mindspore-Ecosystem/mindspore
147 lines
4.9 KiB
Python
147 lines
4.9 KiB
Python
|
# Copyright 2020 Huawei Technologies Co., Ltd
|
||
|
#
|
||
|
# 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.
|
||
|
# ============================================================================
|
||
|
"""metrics utils"""
|
||
|
|
||
|
import numpy as np
|
||
|
from config import ConfigYOLOV3ResNet18
|
||
|
|
||
|
|
||
|
def calc_iou(bbox_pred, bbox_ground):
|
||
|
"""Calculate iou of predicted bbox and ground truth."""
|
||
|
x1 = bbox_pred[0]
|
||
|
y1 = bbox_pred[1]
|
||
|
width1 = bbox_pred[2] - bbox_pred[0]
|
||
|
height1 = bbox_pred[3] - bbox_pred[1]
|
||
|
|
||
|
x2 = bbox_ground[0]
|
||
|
y2 = bbox_ground[1]
|
||
|
width2 = bbox_ground[2] - bbox_ground[0]
|
||
|
height2 = bbox_ground[3] - bbox_ground[1]
|
||
|
|
||
|
endx = max(x1 + width1, x2 + width2)
|
||
|
startx = min(x1, x2)
|
||
|
width = width1 + width2 - (endx - startx)
|
||
|
|
||
|
endy = max(y1 + height1, y2 + height2)
|
||
|
starty = min(y1, y2)
|
||
|
height = height1 + height2 - (endy - starty)
|
||
|
|
||
|
if width <= 0 or height <= 0:
|
||
|
iou = 0
|
||
|
else:
|
||
|
area = width * height
|
||
|
area1 = width1 * height1
|
||
|
area2 = width2 * height2
|
||
|
iou = area * 1. / (area1 + area2 - area)
|
||
|
|
||
|
return iou
|
||
|
|
||
|
|
||
|
def apply_nms(all_boxes, all_scores, thres, max_boxes):
|
||
|
"""Apply NMS to bboxes."""
|
||
|
x1 = all_boxes[:, 0]
|
||
|
y1 = all_boxes[:, 1]
|
||
|
x2 = all_boxes[:, 2]
|
||
|
y2 = all_boxes[:, 3]
|
||
|
areas = (x2 - x1 + 1) * (y2 - y1 + 1)
|
||
|
|
||
|
order = all_scores.argsort()[::-1]
|
||
|
keep = []
|
||
|
|
||
|
while order.size > 0:
|
||
|
i = order[0]
|
||
|
keep.append(i)
|
||
|
|
||
|
if len(keep) >= max_boxes:
|
||
|
break
|
||
|
|
||
|
xx1 = np.maximum(x1[i], x1[order[1:]])
|
||
|
yy1 = np.maximum(y1[i], y1[order[1:]])
|
||
|
xx2 = np.minimum(x2[i], x2[order[1:]])
|
||
|
yy2 = np.minimum(y2[i], y2[order[1:]])
|
||
|
|
||
|
w = np.maximum(0.0, xx2 - xx1 + 1)
|
||
|
h = np.maximum(0.0, yy2 - yy1 + 1)
|
||
|
inter = w * h
|
||
|
|
||
|
ovr = inter / (areas[i] + areas[order[1:]] - inter)
|
||
|
|
||
|
inds = np.where(ovr <= thres)[0]
|
||
|
|
||
|
order = order[inds + 1]
|
||
|
return keep
|
||
|
|
||
|
|
||
|
def metrics(pred_data):
|
||
|
"""Calculate precision and recall of predicted bboxes."""
|
||
|
config = ConfigYOLOV3ResNet18()
|
||
|
num_classes = config.num_classes
|
||
|
count_corrects = [1e-6 for _ in range(num_classes)]
|
||
|
count_grounds = [1e-6 for _ in range(num_classes)]
|
||
|
count_preds = [1e-6 for _ in range(num_classes)]
|
||
|
|
||
|
for i, sample in enumerate(pred_data):
|
||
|
gt_anno = sample["annotation"]
|
||
|
box_scores = sample['box_scores']
|
||
|
boxes = sample['boxes']
|
||
|
mask = box_scores >= config.obj_threshold
|
||
|
boxes_ = []
|
||
|
scores_ = []
|
||
|
classes_ = []
|
||
|
max_boxes = config.nms_max_num
|
||
|
for c in range(num_classes):
|
||
|
class_boxes = np.reshape(boxes, [-1, 4])[np.reshape(mask[:, c], [-1])]
|
||
|
class_box_scores = np.reshape(box_scores[:, c], [-1])[np.reshape(mask[:, c], [-1])]
|
||
|
nms_index = apply_nms(class_boxes, class_box_scores, config.nms_threshold, max_boxes)
|
||
|
class_boxes = class_boxes[nms_index]
|
||
|
class_box_scores = class_box_scores[nms_index]
|
||
|
classes = np.ones_like(class_box_scores, 'int32') * c
|
||
|
boxes_.append(class_boxes)
|
||
|
scores_.append(class_box_scores)
|
||
|
classes_.append(classes)
|
||
|
|
||
|
boxes = np.concatenate(boxes_, axis=0)
|
||
|
classes = np.concatenate(classes_, axis=0)
|
||
|
|
||
|
|
||
|
# metric
|
||
|
count_correct = [1e-6 for _ in range(num_classes)]
|
||
|
count_ground = [1e-6 for _ in range(num_classes)]
|
||
|
count_pred = [1e-6 for _ in range(num_classes)]
|
||
|
|
||
|
for anno in gt_anno:
|
||
|
count_ground[anno[4]] += 1
|
||
|
|
||
|
for box_index, box in enumerate(boxes):
|
||
|
bbox_pred = [box[1], box[0], box[3], box[2]]
|
||
|
count_pred[classes[box_index]] += 1
|
||
|
|
||
|
for anno in gt_anno:
|
||
|
class_ground = anno[4]
|
||
|
|
||
|
if classes[box_index] == class_ground:
|
||
|
iou = calc_iou(bbox_pred, anno)
|
||
|
if iou >= 0.5:
|
||
|
count_correct[class_ground] += 1
|
||
|
break
|
||
|
|
||
|
count_corrects = [count_corrects[i] + count_correct[i] for i in range(num_classes)]
|
||
|
count_preds = [count_preds[i] + count_pred[i] for i in range(num_classes)]
|
||
|
count_grounds = [count_grounds[i] + count_ground[i] for i in range(num_classes)]
|
||
|
|
||
|
precision = np.array([count_corrects[ix] / count_preds[ix] for ix in range(num_classes)])
|
||
|
recall = np.array([count_corrects[ix] / count_grounds[ix] for ix in range(num_classes)])
|
||
|
return precision, recall
|