计算机视觉CV中的IOU计算(目标检测与图像分割)

原文作者: 灿视,来源:灿视学长,优化校准:xiaoxingxing,如有侵权,请联系删除!

目标检测中的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]))

给TA买糖
共{{data.count}}人
人已赞赏
文章计算机视觉

常用激活函数详细介绍

2021-5-27 23:44:18

文章

PyTorch 常用代码段

2021-6-16 0:14:01

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
搜索