语义分割指标—MIoU详细介绍(原理及代码)

语义分割指标—MIoU详细介绍(原理及代码)一 IOU 理解在语义分割的问题中 交并比就是该类的真实标签和预测值的交和并的比值单类的交并比可以理解为下图 TP 预测正确 真正例 模型预测为正例 实际是正例 FP 预测错误 假正例 模型预测

大家好,欢迎来到IT知识分享网。

一.IOU理解

二.MIoU

三.混淆矩阵

1.原理

2.代码

其大致的意思是,给一个向量x,x中最大的元素记为j,返回一个向量1行j+1列的向量y,y[i]代表i在x中出现的次数。

x中最大的数为7,那么它的索引值为0->7 x = np.array([0, 1, 1, 3, 2, 1, 7]) 索引0出现了1次,索引1出现了3......索引5出现了0...... np.bincount(x) 因此,输出结果为:array([1, 3, 1, 1, 0, 0, 0, 1]) 

如果minlength被指定,那么输出数组中的索引至少为它指定的数。即下标为0->minlength-1

我们可以看到x中最大的数为3,那么它的索引值为0->3 x = np.array([3, 2, 1, 3, 1]) 本来bin的数量为4,现在我们指定了参数为7,因此现在bin的数量为7,所以现在它的索引值为0->6 np.bincount(x, minlength=7) 因此,输出结果为:array([0, 2, 1, 2, 0, 0, 0]) 

再来看混淆矩阵计算的代码

''' 产生n×n的分类统计表 参数a:标签图(转换为一行输入),即真实的标签 参数b:score层输出的预测图(转换为一行输入),即预测的标签 参数n:类别数 ''' def fast_hist(a, b, n): #k为掩膜(去除了255这些点(即标签图中的白色的轮廓),其中的a>=0是为了防止bincount()函数出错) k = (a >= 0) & (a < n) return np.bincount(n * a[k].astype(int) + b[k], minlength=n2).reshape(n, n) 

输入a为标签图的向量,b为预测出的向量。n是类别个数。以如下这个例子举列,左边为真实的标签图,右边为预测的结果标签。

在这里插入图片描述

a=np.array([0,1,0,2,1,0,2,2,1]) b=np.array([0,2,0,2,1,0,1,2,1]) k = (a >= 0) & (a < 3) 
n=3 n * a[k].astype(int) b[k] y=n * a[k].astype(int) + b[k] 
x=np.bincount(n * a[k].astype(int) + b[k], minlength=n2).reshape(n, n) 

这里为什么要先对真实标签*n然后加上预测标签,再进行bincount。个人理解:
对真实标签*3可以将最后的结果每三个看成一组,从前到后分别代表该类真实为i类别,预测为0,1,2类别的个数,方便最后resize成3*3。
以真实标签中的0类别为例,真实标签中的0x3后还是0,与预测标签对位相加后,如果预测的也是0,那结果也是0,通过bincount,得到的最终向量第一个数是相加向量中0的个数,也就是代表预测为0真实也为0的个数。如果预测的是1,0x3+1=1,通过bincount会统计所有为1的个数放在结果的第二位,代表真实为0预测为1的个数。
其他分类同理。


四.利用混淆矩阵求iou和miou

计算每一个分类的iou代码,参数hist是混淆矩阵

def per_class_iu(hist): # 矩阵的对角线上的值组成的一维数组/矩阵的所有元素之和,返回值形状(n,) return np.diag(hist) / (hist.sum(1) + hist.sum(0) - np.diag(hist)) 
np.mean(per_class_iu(hist) 

实际项目中的代码

# 设标签宽W,长H def fast_hist(a, b, n): #--------------------------------------------------------------------------------# # a是转化成一维数组的标签,形状(H×W,);b是转化成一维数组的预测结果,形状(H×W,) #--------------------------------------------------------------------------------# k = (a >= 0) & (a < n) #--------------------------------------------------------------------------------# # np.bincount计算了从0到n2-1这n2个数中每个数出现的次数,返回值形状(n, n) # 返回中,写对角线上的为分类正确的像素点 #--------------------------------------------------------------------------------# return np.bincount(n * a[k].astype(int) + b[k], minlength=n  2).reshape(n, n) def per_class_iu(hist): return np.diag(hist) / np.maximum((hist.sum(1) + hist.sum(0) - np.diag(hist)), 1) def per_class_PA(hist): return np.diag(hist) / np.maximum(hist.sum(1), 1) def compute_mIoU(gt_dir, pred_dir, png_name_list, num_classes, name_classes): print('Num classes', num_classes) #-----------------------------------------# # 创建一个全是0的矩阵,是一个混淆矩阵 #-----------------------------------------# hist = np.zeros((num_classes, num_classes)) #------------------------------------------------# # 获得验证集标签路径列表,方便直接读取 # 获得验证集图像分割结果路径列表,方便直接读取 #------------------------------------------------# gt_imgs = [join(gt_dir, x + ".png") for x in png_name_list] pred_imgs = [join(pred_dir, x + ".png") for x in png_name_list] #------------------------------------------------# # 读取每一个(图片-标签)对 #------------------------------------------------# for ind in range(len(gt_imgs)): #------------------------------------------------# # 读取一张图像分割结果,转化成numpy数组 #------------------------------------------------# pred = np.array(Image.open(pred_imgs[ind])) #------------------------------------------------# # 读取一张对应的标签,转化成numpy数组 #------------------------------------------------# label = np.array(Image.open(gt_imgs[ind])) # 如果图像分割结果与标签的大小不一样,这张图片就不计算 if len(label.flatten()) != len(pred.flatten()): print( 'Skipping: len(gt) = {:d}, len(pred) = {:d}, {:s}, {:s}'.format( len(label.flatten()), len(pred.flatten()), gt_imgs[ind], pred_imgs[ind])) continue #------------------------------------------------# # 对一张图片计算21×21的hist矩阵,并累加 #------------------------------------------------# hist += fast_hist(label.flatten(), pred.flatten(),num_classes) # 每计算10张就输出一下目前已计算的图片中所有类别平均的mIoU值 if ind > 0 and ind % 10 == 0: print('{:d} / {:d}: mIou-{:0.2f}; mPA-{:0.2f}'.format(ind, len(gt_imgs), 100 * np.nanmean(per_class_iu(hist)), 100 * np.nanmean(per_class_PA(hist)))) #------------------------------------------------# # 计算所有验证集图片的逐类别mIoU值 #------------------------------------------------# mIoUs = per_class_iu(hist) mPA = per_class_PA(hist) #------------------------------------------------# # 逐类别输出一下mIoU值 #------------------------------------------------# for ind_class in range(num_classes): print('===>' + name_classes[ind_class] + ':\tmIou-' + str(round(mIoUs[ind_class] * 100, 2)) + '; mPA-' + str(round(mPA[ind_class] * 100, 2))) #-----------------------------------------------------------------# # 在所有验证集图像上求所有类别平均的mIoU值,计算时忽略NaN值 #-----------------------------------------------------------------# print('===> mIoU: ' + str(round(np.nanmean(mIoUs) * 100, 2)) + '; mPA: ' + str(round(np.nanmean(mPA) * 100, 2))) return mIoUs 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/110312.html

(0)
上一篇 2026-02-01 13:33
下一篇 2026-02-01 14:00

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信