MIoU计算
具体代码可去Bubbliiiing大神的仓库获取,主体逻辑代码如下:
首先拿到所有的label和pre
gt_imgs = [os.path.join(pred_dir, x.split('\\')[-1].split('.')[0] + "_label.png") for x in png_name_list]
pred_imgs = [os.path.join(pred_dir, x.split('\\')[-1].split('.')[0] + "_pre.png") for x in png_name_list]
然后读取每个标签-预测图像对
for ind in range(len(gt_imgs)):
pred = np.array(Image.open(pred_imgs[ind]))
label = np.array(Image.open(gt_imgs[ind]))
对一个图片计算n×n的hist矩阵,n表示预测类别,我这次用的是5。
hist += fast_hist(label.flatten(), pred.flatten(), num_classes)
def fast_hist(a, b, n):
# 剔除异常值,比如分隔5类,标签和预测值的范围应该是0~4
k = (a >= 0) & (a < n)
# np.bincount计算了从0到n**2-1这n**2个数中每个数出现的次数,返回值形状(n, n)
return np.bincount(n * a[k].astype(int) + b[k], minlength=n ** 2).reshape(n, n)
经过计算,就可以得到所有标签-预测图像对中,0到n方-1这n方个数中每个数出现的次数。
这是一种很巧妙的做法,这个矩阵对角线上的数字,意味着每个类别预测值和标签值完全相同的个数。
如果标签值是0,那么n×0=0,0+b的范围是0~4,那么经过统计,取值为0的个数就是预测值和标签值都是0的个数,也就是预测正确的个数,其他都是预测错误的个数。这也就是hist的第一行。
如果标签值是1,那么n×1=5,5+b的范围是5~9,那么经过统计,取值为6的个数就是预测值和标签值都是1的个数,也就是预测正确的个数。这也就是hist的第二行。后面的以此类推。
计算交并比
def per_class_iu(hist):
return np.diag(hist) / np.maximum((hist.sum(1) + hist.sum(0) - np.diag(hist)), 1)
np.diag(hist)
取出矩阵 hist
的对角线上的元素,这些元素表示每个类别的真正例数量。
hist.sum(1)
是按行求和,得到每个预测类别的总数。
hist.sum(0)
是按列求和,得到每个真实类别的总数。
hist.sum(1) + hist.sum(0) - np.diag(hist)
计算的是并集的大小。
通过将真正例数量除以并集大小,并使用 np.maximum
来处理分母可能为 0 的情况,从而得到每个类别的 IoU 值。
结果为每个类别的IoU,在做平均即为mIoU。
计算准确率
def per_class_Precision(hist):
return np.diag(hist) / np.maximum(hist.sum(0), 1)
将真正例数量除以真实类别的总数,并使用 np.maximum
处理分母可能为 0 的情况,就得到了每个类别的精确率。
结果为每个类别的准确率
计算召回率
def per_class_PA_Recall(hist):
return np.diag(hist) / np.maximum(hist.sum(1), 1)
将真正例数量除以预测类别的总数,并通过 np.maximum
处理分母可能为 0 的情况,从而得到每个类别的召回率。
结果为每个类别的召回率