|
- # 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
|