cvtools.utils.iou 源代码

# -*- encoding:utf-8 -*-
# @Time    : 2019/4/18 21:21
# @Author  : gfjiang
# @Site    :
# @File    : iou.py
# @Software: PyCharm
import numpy as np


[文档]def bbox_overlaps(bboxes1, bboxes2, mode='iou'): """Calculate the ious between each bbox of bboxes1 and bboxes2. Args: bboxes1(ndarray): shape (n, 4) bboxes2(ndarray): shape (k, 4) mode(str): iou (intersection over union) or iof (intersection over foreground) Returns: ious(ndarray): shape (n, k) """ assert mode in ['iou', 'iof'] bboxes1 = bboxes1.astype(np.float32) bboxes2 = bboxes2.astype(np.float32) rows = bboxes1.shape[0] cols = bboxes2.shape[0] ious = np.zeros((rows, cols), dtype=np.float32) if rows * cols == 0: return ious exchange = False if bboxes1.shape[0] > bboxes2.shape[0]: bboxes1, bboxes2 = bboxes2, bboxes1 ious = np.zeros((cols, rows), dtype=np.float32) exchange = True area1 = (bboxes1[:, 2] - bboxes1[:, 0] + 1) * ( bboxes1[:, 3] - bboxes1[:, 1] + 1) area2 = (bboxes2[:, 2] - bboxes2[:, 0] + 1) * ( bboxes2[:, 3] - bboxes2[:, 1] + 1) for i in range(bboxes1.shape[0]): x_start = np.maximum(bboxes1[i, 0], bboxes2[:, 0]) y_start = np.maximum(bboxes1[i, 1], bboxes2[:, 1]) x_end = np.minimum(bboxes1[i, 2], bboxes2[:, 2]) y_end = np.minimum(bboxes1[i, 3], bboxes2[:, 3]) overlap = np.maximum(x_end - x_start + 1, 0) * np.maximum( y_end - y_start + 1, 0) if mode == 'iou': union = area1[i] + area2 - overlap else: union = area1[i] if not exchange else area2 ious[i, :] = overlap / union if exchange: ious = ious.T return ious
# 两种box形式均已测试
[文档]def box_ious(b1, b2, center=False): """Return iou tensor Parameters ---------- b1: array, shape=(i1,...,iN, 4), xywh or x1y1x2y2 b2: array, shape=(j, 4), xywh or x1y1x2y2 center: box format Returns ------- iou: array, shape=(i1,...,iN, j)""" if not isinstance(b1, np.ndarray): b1 = np.array([b1]) if not isinstance(b2, np.ndarray): b2 = np.array([b2]) # 这是学习数组广播一个非常好的例子 # 当两个数组维度无法广播时,不要尝试手动扩展复制数据, # 而应该在需要广播的方向插入一个维度,这样数据就会顺着这个插入的1维度进行广播 # Expand dim to apply broadcasting. b1 = b1[:, np.newaxis, :] b1_wh = b1[..., [2, 3]] - b1[..., [0, 1]] b1_mins = b1[..., :2] b1_maxes = b1[..., 2:4] if center: b1_wh = b1[..., 2:4] b1_mins = b1[..., :2] - b1_wh / 2. b1_maxes = b1[..., :2] + b1_wh / 2. # Expand dim to apply broadcasting. b2 = b2[np.newaxis, :, :] b2_wh = b2[..., [2, 3]] - b2[..., [0, 1]] b2_mins = b2[..., :2] b2_maxes = b2[..., 2:4] if center: b2_wh = b2[..., 2:4] b2_mins = b2[..., :2] - b2_wh / 2. b2_maxes = b2[..., :2] + b2_wh / 2. intersect_mins = np.maximum(b1_mins, b2_mins) intersect_maxes = np.minimum(b1_maxes, b2_maxes) intersect_wh = np.maximum(intersect_maxes - intersect_mins, 0.) intersect_area = intersect_wh[..., 0] * intersect_wh[..., 1] b1_area = b1_wh[..., 0] * b1_wh[..., 1] b2_area = b2_wh[..., 0] * b2_wh[..., 1] iou = intersect_area / (b1_area + b2_area - intersect_area) return iou
if __name__ == "__main__": BB = np.array([[100, 200, 120, 240], [140, 220, 150, 280], [180, 260, 200, 300]]) BBGT = np.array([[108, 220, 130, 260], [130, 210, 145, 270]]) # center = False # [100, 200, 120, 240] VS [108, 220, 130, 260] # intersect_x1y1x2y2 = 108, 220, 120, 240 intersect_wh = 12, 20 # BB_area = 20*40, BBGT_area = 22*40 # iou = 240 / (800 + 880 - 240) = 240 / 1440 = 0.16666 # [140, 220, 150, 280] VS [130, 210, 145, 270] # intersect_x1y1x2y2 = 140, 220, 145, 270 intersect_wh = 5, 50 # BB_area = 10*60, BBGT_area = 15*60 # iou = 250 / (600 + 900 - 250) = 250 / 1250 = 0.2 # center = True # [100, 200, 120, 240] VS [108, 220, 130, 260] # convert to xiyix2y2 format [40, 80, 160, 320] VS [43, 90, 173, 350] # intersect_x1y1x2y2 = 43, 90, 160, 320 intersect_wh = 117, 230 # BB_area = 120*240, BBGT_area = 130*260 # iou = 117*230 / (120*240 + 130*260 - 117*230) = 0.7539 # [140, 220, 150, 280] VS [130, 210, 145, 270] # convert to xiyix2y2 format [65, 80, 215, 360] VS [57.5, 75, 202.5, 345] # intersect_x1y1x2y2 = 65, 80, 202.5, 345 intersect_wh = 137.5, 265 # BB_area = 150*280, BBGT_area = 145*270 # iou = 137.5*265 / (150*280 + 145*270 - 137.5*265) = 36437.5 / 44712.5 = 0.8149 box_ious(BB, BBGT, center=True)