np实现图像分割评价指标之PA、MPA、MIoU、FWIoU

tech2023-01-24  53

n p 实 现 图 像 分 割 评 价 指 标 之 P A 、 M P A 、 M I o U 、 F W I o U np实现图像分割评价指标之PA、MPA、MIoU、FWIoU npPAMPAMIoUFWIoU


什么是评测函数?

有了loss函数为什么还要有评测函数?loss函数不就是评测函数? loss其实就是一种评测函数,但是在实际中我们需要的某种指标是不能变成可导的loss函数的。 评测函数对模型能力的评测,是对我们所需指标的计算。


如下图所示,红色圆代表真实值,黄色圆代表预测值。橙色部分红色圆与黄色圆的交集,即真正(预测为1,真实值为1)的部分,红色部分表示假负(预测为0,真实为1)的部分,黄色表示假正(预测为1,真实为0)的部分,两个圆之外的白色区域表示真负(预测为0,真实值为0)的部分。

MP计算橙色与(橙色与红色)的比例。MIoU计算的是计算A与B的交集(橙色部分)与A与B的并集(红色+橙色+黄色)之间的比例,在理想状态下A与B重合,两者比例为1 。


像素精确度(pixel accuracy,PA)

这是最简单的指标,用来计算被正确分类的像素个数和总像素数之间的比例


平均像素精确度(Mean pixel Accuracy,MPA)

这是在PA基础上做了微整提升,为类别内像素正确分类概率的平均值:


平均交并比(Mean Intersection over Union,MIoU)

这是一个标准的衡量metric ,计算两个集合之间交集和并集的比例,在图像分割中,就是真实值(Ground Truth)和预测值两个集合。可以转换为TP(intersection)与TP ,FN ,FP之和(union)的比值。先计算每个类内的交并比,然后计算均值。


加权交并比(Frequency Weighted Intersection over Union,FWIoU)

这是在MIoU上的基础上做稍微的提升,对每一个类根据出现的频率为其设置权重



综述:图像分割的各项一般指标的计算一般分两步,一是计算混淆矩阵,二是计算各项指标


数据准备 gt_image = np.array([ [0,1,2,4], [0,0,0,0], [0,0,0,0], [0,0,0,0] ]) pre_image = np.array([ [0,1,2,4], [0,1,0,0], [0,1,0,0], [0,0,1,0] ]) def generate_matrix(gt_image, pre_image,num_class=8): mask = (gt_image >= 0) & (gt_image < num_class)#ground truth中所有正确(值在[0, classe_num])的像素label的mask label = num_class * gt_image[mask].astype('int') + pre_image[mask] # np.bincount计算了从0到n**2-1这n**2个数中每个数出现的次数,返回值形状(n, n) count = np.bincount(label, minlength=num_class**2) confusion_matrix = count.reshape(num_class, num_class)#21 * 21(for pascal) return confusion_matrix matrix =generate_matrix(gt_image,pre_image) matrix


PA def Pixel_Accuracy(confusion_matrix): Acc = np.diag(confusion_matrix).sum() / confusion_matrix.sum() return Acc Pixel_Accuracy(matrix)


MPA def Pixel_Accuracy_Class(confusion_matrix): Acc = np.diag(confusion_matrix) / confusion_matrix.sum(axis=1) Acc = np.nanmean(Acc) return Acc Pixel_Accuracy_Class(matrix)


MIoU def Mean_Intersection_over_Union(confusion_matrix): MIoU = np.diag(confusion_matrix) / ( np.sum(confusion_matrix, axis=1) + np.sum(confusion_matrix, axis=0) - np.diag(confusion_matrix)) MIoU = np.nanmean(MIoU) #跳过0值求mean,shape:[21] return MIoU Mean_Intersection_over_Union(matrix)

def Class_IOU(confusion_matrix): MIoU = np.diag(confusion_matrix) / ( np.sum(confusion_matrix, axis=1) + np.sum(confusion_matrix, axis=0) - np.diag(confusion_matrix)) return MIoU Class_IOU(matrix)


FWIoU def Frequency_Weighted_Intersection_over_Union(confusion_matrix): freq = np.sum(confusion_matrix, axis=1) / np.sum(confusion_matrix) iu = np.diag(confusion_matrix) / ( np.sum(confusion_matrix, axis=1) + np.sum(confusion_matrix, axis=0) - np.diag(confusion_matrix)) FWIoU = (freq[freq > 0] * iu[freq > 0]).sum() return FWIoU Frequency_Weighted_Intersection_over_Union(matrix)


补充:

MeanIoU

class Evaluator(object): def __init__(self, num_class): self.num_class = num_class self.confusion_matrix = np.zeros((self.num_class,)*2)#21*21的矩阵,行代表ground truth类别,列代表preds的类别,值代表 ''' 正确的像素占总像素的比例 ''' def Pixel_Accuracy(self): Acc = np.diag(self.confusion_matrix).sum() / self.confusion_matrix.sum() return Acc ''' 分别计算每个类分类正确的概率 ''' def Pixel_Accuracy_Class(self): Acc = np.diag(self.confusion_matrix) / self.confusion_matrix.sum(axis=1) Acc = np.nanmean(Acc) return Acc ''' Mean Intersection over Union(MIoU,均交并比):为语义分割的标准度量。其计算两个集合的交集和并集之比. 在语义分割的问题中,这两个集合为真实值(ground truth)和预测值(predicted segmentation)。 这个比例可以变形为正真数(intersection)比上真正、假负、假正(并集)之和。在每个类上计算IoU,之后平均。 对于21个类别,分别求IOU: 例如,对于类别1的IOU定义如下: (1)统计在ground truth中属于类别1的像素数 (2)统计在预测结果中每个类别1的像素数 (1) + (2)就是二者的并集像素数(类比于两块区域的面积加和, 注:二者交集部分的面积加重复了) 再减去二者的交集(既在ground truth集合中又在预测结果集合中的像素),得到的就是二者的并集(所有跟类别1有关系的像素:包括TP,FP,FN) 扩展提示: TP(真正): 预测正确, 预测结果是正类, 真实是正类 FP(假正): 预测错误, 预测结果是正类, 真实是负类 FN(假负): 预测错误, 预测结果是负类, 真实是正类 TN(真负): 预测正确, 预测结果是负类, 真实是负类 #跟类别1无关,所以不包含在并集中 (本例中, 正类:是类别1, 负类:不是类别1) mIoU: 对于每个类别计算出的IoU求和取平均 ''' def Mean_Intersection_over_Union(self): MIoU = np.diag(self.confusion_matrix) / ( np.sum(self.confusion_matrix, axis=1) + np.sum(self.confusion_matrix, axis=0) - np.diag(self.confusion_matrix)) MIoU = np.nanmean(MIoU) #跳过0值求mean,shape:[21] return MIoU def Class_IOU(self): MIoU = np.diag(self.confusion_matrix) / ( np.sum(self.confusion_matrix, axis=1) + np.sum(self.confusion_matrix, axis=0) - np.diag(self.confusion_matrix)) return MIoU def Frequency_Weighted_Intersection_over_Union(self): freq = np.sum(self.confusion_matrix, axis=1) / np.sum(self.confusion_matrix) iu = np.diag(self.confusion_matrix) / ( np.sum(self.confusion_matrix, axis=1) + np.sum(self.confusion_matrix, axis=0) - np.diag(self.confusion_matrix)) FWIoU = (freq[freq > 0] * iu[freq > 0]).sum() return FWIoU ''' 参数的传入: evaluator = Evaluate(4) #只需传入类别数4 evaluator.add_batch(target, preb) #target:[batch_size, 512, 512] , preb:[batch_size, 512, 512] 在add_batch中统计这个epoch中所有图片的预测结果和ground truth的对应情况, 累计成confusion矩阵(便于之后求mean) 参数列表对应: gt_image: target 图片的真实标签 [batch_size, 512, 512] per_image: preb 网络生成的图片的预测标签 [batch_size, 512, 512] parameters: mask: ground truth中所有正确(值在[0, classe_num])的像素label的mask---为了保证ground truth中的标签值都在合理的范围[0, 20] label: 为了计算混淆矩阵, 混淆矩阵中一共有num_class*num_class个数, 所以label中的数值也是在0与num_class**2之间. [batch_size, 512, 512] cout(reshape): 记录了每个类别对应的像素个数,行代表真实类别,列代表预测的类别,count矩阵中(x, y)位置的元素代表该张图片中真实类别为x,被预测为y的像素个数 np.bincount: https://blog.csdn.net/xlinsist/article/details/51346523 confusion_matrix: 对角线上的值的和代表分类正确的像素点个数(preb与target一致),对角线之外的其他值的和代表所有分类错误的像素的个数 ''' # 计算混淆矩阵 def _generate_matrix(self, gt_image, pre_image): mask = (gt_image >= 0) & (gt_image < self.num_class)#ground truth中所有正确(值在[0, classe_num])的像素label的mask label = self.num_class * gt_image[mask].astype('int') + pre_image[mask] # np.bincount计算了从0到n**2-1这n**2个数中每个数出现的次数,返回值形状(n, n) count = np.bincount(label, minlength=self.num_class**2) confusion_matrix = count.reshape(self.num_class, self.num_class)#21 * 21(for pascal) return confusion_matrix # -------------------------------------------------------------------------------- def add_batch(self, gt_image, pre_image): assert gt_image.shape == pre_image.shape tmp = self._generate_matrix(gt_image, pre_image) #矩阵相加是各个元素对应相加,即21*21的矩阵进行pixel-wise加和 self.confusion_matrix += self._generate_matrix(gt_image, pre_image) def reset(self): self.confusion_matrix = np.zeros((self.num_class,) * 2)

转载

补充: 系统的多个方面需要被测试以评估其有效性,包括:执行时间、内存占用、和精确度。
最新回复(0)