原文作者:
目标检测中的IOU
假设,我们有两个矩形框,rect1与rect2,我们要计算其IOU。其中IOU的计算公式为,其交叉面积Intersection除以其并集Union。
IOU的数学公式:
IOU复现代码如下:
def IOU(rect1, rect2):
"""
computing IoU
param rec1: (y0, x0, y1, x1) , which reflects (top, left, bottom, right)
param rec2: (y0, x0, y1, x1) , which reflects (top, left, bottom, right)
return : scale value of IoU
"""
x11 = rect1[0] # first rectangle top left x
y11 = rect1[1] # first rectangle top left y
x12 = rect1[2] # first rectangle bottom right x
y12 = rect1[3] # first rectangle bottom right y
x21 = rect2[0] # second rectangle top left x
y21 = rect2[1] # second rectangle top left y
x22 = rect2[2] # second rectangle bottom right x
y22 = rect2[3] # second rectangle bottom right y
S_rect1 =(x12 -x11) *(y12 -y11)
S_rect2 =(x22 -x21) *(y22 -y21)
#computing the sum area
sum_area =S_rect1 +S_rect2
#find the each edge of interest rectangle
overlap_left_x =max(x11, x21)
overlap_left_y =max(y11, y21)
overlap_right_x =min(x12, x22)
overlap_right_y =min(y12, y22)
#judge if there is an intersect
if overlap_left_x >=overlap_right_x or overlap_left_y >=overlap_right_y:
return 0
else:
intersect =(overlap_right_x -overlap_left_x) *(overlap_right_y -overlap_left_y)
return intersect /(sum_area -intersect)
参考下图可以更好的理解代码:
需要注意的地方是:重合框的一定要满足左上角坐标小于右下角坐标,否者不会出现重合框,那么IOU就是0。IOU的另一种简洁写法如下:
def IOU(rect_1, rect_2):
'''
:param rect_1: list in format [x11, y11, x12, y12, confidence, current_scale]
:param rect_2: list in format [x21, y21, x22, y22, confidence, current_scale]
:return: returns IoU ratio (intersection over union) of two rectangles
'''
x11 = rect_1[0] # first rectangle top left x
y11 = rect_1[1] # first rectangle top left y
x12 = rect_1[2] # first rectangle bottom right x
y12 = rect_1[3] # first rectangle bottom right y
x21 = rect_2[0] # second rectangle top left x
y21 = rect_2[1] # second rectangle top left y
x22 = rect_2[2] # second rectangle bottom right x
y22 = rect_2[3] # second rectangle bottom right y
x_overlap = max(0, min(x12,x22) -max(x11,x21))
y_overlap = max(0, min(y12,y22) -max(y11,y21))
intersection = x_overlap * y_overlap
union = (x12-x11) * (y12-y11) + (x22-x21) * (y22-y21) - intersection
return float(intersection) / union
语义分割中的IOU
先回顾下基础知识:
常常将预测出来的结果分为四个部分:true positive,false positive,ture negative,false negative,其中negative就是指非物体标签的部分(可以直接理解为背景),positive就是指有标签的部分。下图显示了四个部分的区别:
如上图,prediction图(左图为真实标签图,右图为预测图)被分成四个部分,其中大块的白色斜线标记的是true negative(TN,预测正确的真实背景部分),红线部分标记的是false negative(FN,错误的背景预测即将实际不是背景的部分预测为背景),蛋蓝色的斜线是false positive(FP,预测分割中为某标签的部分,但是实际上并不是该标签所属的部分),中间荧光黄色块就是true positive(TP,预测为某标签的部分,实际符合真值)。(分割任务中可能是多目标任务,需要区别多个目标部分和背景部分。)
同样IOU的计算公式如下:
def compute_ious(pred, label, classes):
'''computes iou for one ground truth mask and predicted mask'''
ious = [] # 记录每一类的iou
for c in classes:
label_c = (label == c) # label_c为true/false矩阵
pred_c = (pred == c)
intersection = np.logical_and(pred_c, label_c).sum()
union = np.logical_or(pred_c, label_c).sum()
if union == 0:
ious.append(float('nan'))
else
ious.append(intersection / union)
return np.nanmean(ious) #返回当前图片里所有类的mean iou
其中,对于label与pred有多种形式。
如识别目标为4类,那么label的形式可以是一张图片对应一份,其中0为背景,如果省略,则class可以为
,也可以对应四份二进制
,这四份mask的取值为0或1。也可以参考如下代码进一步理解:
import numpy as np
import os
from skimage import io
'''
该脚本主要实现语义分割中多类结果的评估功能
要求:预测结果文件夹和真值文件夹中各个图像的文件名应该一样,对同一种类像素的灰度表示也应该一样
'''
pre_path = 'Prediction' #预测结果的文件夹
gt_path = 'Label' #ground truth文件夹
img_size = (384, 384) #图像的尺寸(只需要长宽)
classes = np.array([0, 1, 2, 3]).astype('uint8')#每一类的灰度值表示
files = os.listdir(pre_path)
res = []
for clas in classes:
D = np.zeros([len(files), img_size[0], img_size[1], 2]).astype(bool)#存储每一类的二值数据
# print(D.shape)
for i, file in enumerate(files):
img1 = io.imread(os.path.join(pre_path, file), as_gray=True)#以灰度值的形式读取
img2 = io.imread(os.path.join(gt_path, file), as_gray=True)#以灰度值的形式读取
D[i, :, :, 0] = img1 == clas # 通过类别标签转换为二进制表
D[i, :, :, 1] = img2 == clas
res.append(np.sum(D[..., 0] & D[..., 1])/np.sum(D[..., 0] | D[..., 1])) #计算IOU
# print(res)
#结果输出
for i, clas in enumerate(classes):
print("Class "+str(clas)+' :'+str(res[i]))