# Copyright (c) 2019 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. from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals import numpy as np import matplotlib matplotlib.use('Agg') from matplotlib import pyplot as plt from PIL import Image def coco_anno_box_to_center_relative(box, img_height, img_width): """ Convert COCO annotations box with format [x1, y1, w, h] to center mode [center_x, center_y, w, h] and divide image width and height to get relative value in range[0, 1] """ assert len(box) == 4, "box should be a len(4) list or tuple" x, y, w, h = box x1 = max(x, 0) x2 = min(x + w - 1, img_width - 1) y1 = max(y, 0) y2 = min(y + h - 1, img_height - 1) x = (x1 + x2) / 2 / img_width y = (y1 + y2) / 2 / img_height w = (x2 - x1) / img_width h = (y2 - y1) / img_height return np.array([x, y, w, h]) def clip_relative_box_in_image(x, y, w, h): """Clip relative box coordinates x, y, w, h to [0, 1]""" x1 = max(x - w / 2, 0.) x2 = min(x + w / 2, 1.) y1 = min(y - h / 2, 0.) y2 = max(y + h / 2, 1.) x = (x1 + x2) / 2 y = (y1 + y2) / 2 w = x2 - x1 h = y2 - y1 def box_xywh_to_xyxy(box): shape = box.shape assert shape[-1] == 4, "Box shape[-1] should be 4." box = box.reshape((-1, 4)) box[:, 0], box[:, 2] = box[:, 0] - box[:, 2] / 2, box[:, 0] + box[:, 2] / 2 box[:, 1], box[:, 3] = box[:, 1] - box[:, 3] / 2, box[:, 1] + box[:, 3] / 2 box = box.reshape(shape) return box def box_iou_xywh(box1, box2): assert box1.shape[-1] == 4, "Box1 shape[-1] should be 4." assert box2.shape[-1] == 4, "Box2 shape[-1] should be 4." b1_x1, b1_x2 = box1[:, 0] - box1[:, 2] / 2, box1[:, 0] + box1[:, 2] / 2 b1_y1, b1_y2 = box1[:, 1] - box1[:, 3] / 2, box1[:, 1] + box1[:, 3] / 2 b2_x1, b2_x2 = box2[:, 0] - box2[:, 2] / 2, box2[:, 0] + box2[:, 2] / 2 b2_y1, b2_y2 = box2[:, 1] - box2[:, 3] / 2, box2[:, 1] + box2[:, 3] / 2 inter_x1 = np.maximum(b1_x1, b2_x1) inter_x2 = np.minimum(b1_x2, b2_x2) inter_y1 = np.maximum(b1_y1, b2_y1) inter_y2 = np.minimum(b1_y2, b2_y2) inter_w = inter_x2 - inter_x1 + 1 inter_h = inter_y2 - inter_y1 + 1 inter_w[inter_w < 0] = 0 inter_h[inter_h < 0] = 0 inter_area = inter_w * inter_h b1_area = (b1_x2 - b1_x1 + 1) * (b1_y2 - b1_y1 + 1) b2_area = (b2_x2 - b2_x1 + 1) * (b2_y2 - b2_y1 + 1) return inter_area / (b1_area + b2_area - inter_area) def box_iou_xyxy(box1, box2): assert box1.shape[-1] == 4, "Box1 shape[-1] should be 4." assert box2.shape[-1] == 4, "Box2 shape[-1] should be 4." b1_x1, b1_y1, b1_x2, b1_y2 = box1[:, 0], box1[:, 1], box1[:, 2], box1[:, 3] b2_x1, b2_y1, b2_x2, b2_y2 = box2[:, 0], box2[:, 1], box2[:, 2], box2[:, 3] inter_x1 = np.maximum(b1_x1, b2_x1) inter_x2 = np.minimum(b1_x2, b2_x2) inter_y1 = np.maximum(b1_y1, b2_y1) inter_y2 = np.minimum(b1_y2, b2_y2) inter_w = inter_x2 - inter_x1 inter_h = inter_y2 - inter_y1 inter_w[inter_w < 0] = 0 inter_h[inter_h < 0] = 0 inter_area = inter_w * inter_h b1_area = (b1_x2 - b1_x1) * (b1_y2 - b1_y1) b2_area = (b2_x2 - b2_x1) * (b2_y2 - b2_y1) return inter_area / (b1_area + b2_area - inter_area) def box_crop(boxes, labels, scores, crop, img_shape): x, y, w, h = map(float, crop) im_w, im_h = map(float, img_shape) boxes = boxes.copy() boxes[:, 0], boxes[:, 2] = (boxes[:, 0] - boxes[:, 2] / 2) * im_w, (boxes[:, 0] + boxes[:, 2] / 2) * im_w boxes[:, 1], boxes[:, 3] = (boxes[:, 1] - boxes[:, 3] / 2) * im_h, (boxes[:, 1] + boxes[:, 3] / 2) * im_h crop_box = np.array([x, y, x + w, y + h]) centers = (boxes[:, :2] + boxes[:, 2:]) / 2.0 mask = np.logical_and(crop_box[:2] <= centers, centers <= crop_box[2:]).all(axis=1) boxes[:, :2] = np.maximum(boxes[:, :2], crop_box[:2]) boxes[:, 2:] = np.minimum(boxes[:, 2:], crop_box[2:]) boxes[:, :2] -= crop_box[:2] boxes[:, 2:] -= crop_box[:2] mask = np.logical_and(mask, (boxes[:, :2] < boxes[:, 2:]).all(axis=1)) boxes = boxes * np.expand_dims(mask.astype('float32'), axis=1) labels = labels * mask.astype('float32') scores = scores * mask.astype('float32') boxes[:, 0], boxes[:, 2] = (boxes[:, 0] + boxes[:, 2]) / 2 / w, (boxes[:, 2] - boxes[:, 0]) / w boxes[:, 1], boxes[:, 3] = (boxes[:, 1] + boxes[:, 3]) / 2 / h, (boxes[:, 3] - boxes[:, 1]) / h return boxes, labels, scores, mask.sum() def draw_boxes_on_image(image_path, boxes, scores, labels, label_names, score_thresh=0.5): image = np.array(Image.open(image_path)) plt.figure() _, ax = plt.subplots(1) ax.imshow(image) image_name = image_path.split('/')[-1] print("Image {} detect: ".format(image_name)) colors = {} for box, score, label in zip(boxes, scores, labels): if score < score_thresh: continue if box[2] <= box[0] or box[3] <= box[1]: continue label = int(label) if label not in colors: colors[label] = plt.get_cmap('hsv')(label / len(label_names)) x1, y1, x2, y2 = box[0], box[1], box[2], box[3] rect = plt.Rectangle((x1, y1), x2 - x1, y2 - y1, fill=False, linewidth=2.0, edgecolor=colors[label]) ax.add_patch(rect) ax.text(x1, y1, '{} {:.4f}'.format(label_names[label], score), verticalalignment='bottom', horizontalalignment='left', bbox={'facecolor': colors[label], 'alpha': 0.5, 'pad': 0}, fontsize=8, color='white') print("\t {:15s} at {:25} score: {:.5f}".format(label_names[int(label)], map(int, list(box)), score)) image_name = image_name.replace('jpg', 'png') plt.axis('off') plt.gca().xaxis.set_major_locator(plt.NullLocator()) plt.gca().yaxis.set_major_locator(plt.NullLocator()) plt.savefig("./output/{}".format(image_name), bbox_inches='tight', pad_inches=0.0) print("Detect result save at ./output/{}\n".format(image_name)) plt.cla() plt.close('all')