在做图像语言分隔的时候,我们往往需要计算出像素精确度,交并比等值来评估我们的算法或者神经网络的表现。本篇文章着重介绍如何用numpy实现像素精确度、平均像素精确度、平均交并比和加权的交并比的计算。 在正式开始之前需要先掌握几个numpy的函数和编程技巧。
bincount函数
功能:实现个数的统计。 示例:假设有numpy数组:
x = np.array([0, 1, 1, 3, 2, 1, 7])
我们想要知道里面0~7这8个数出现的次数是多少,就可以用bincount函数。
y=np.bincount(x)
打印出y得到[1 3 1 1 0 0 0 1],意思是我们有0~7这8个数,按照数组下标排列起来,然后对应的数值则为0~7出现的次数。 需要注意的是这里的数值长度是函数自己给的,也就是说它只会统计到我们放进函数的这个数组中最大的那个值。如果我们想要统计0~9这10个数出现的次数,我们可以通过指定minlength参数实现:
y = np.bincount(x,minlength=10)
输出则为:[1 3 1 1 0 0 0 1 0 0]
diag函数
功能:取出对角线上的值。 示例:假设有numpy数组:
x=np.array([(1,0,0,0,0,4),(0,2,0,2,0,0),(0,0,3,0,0,4),(0,0,4,4,0,0),(0,0,5,0,5,4),(0,0,0,2,0,6)])
[[1 0 0 0 0 4] [0 2 0 2 0 0] [0 0 3 0 0 4] [0 0 4 4 0 0] [0 0 5 0 5 4] [0 0 0 2 0 6]] 我们想要取出对角线上的数,则可以用diag函数。
y=np.diag(x)
输出为:[1 2 3 4 5 6] 如果我们想要把对角线上的数加起来,则写成:
y=np.diag(x).sum()
输出为:21
zip函数
功能:依据多维数组的第一维进行遍历。 示例:假设有numpy数组:
x=np.array([[(0,0,0,0,0,4), (0,0,0,2,0,0)],[(0,0,0,0,0,4), (0,0,0,2,0,0)]])
y=np.array([[(0,0,0,0,0,4), (0,0,0,2,0,0)],[(0,0,0,0,0,1), (0,0,0,2,0,0)]])
它们的形状是:(2, 2, 6) 假设前面的2指代的是不同的图片,而后面的2和6指代的是图片的宽和高 ,而我们希望将图片一张张取出来进行计算,则可以用zip函数来做。
for onex, oney in zip(x, y):
print(onex.shape)
print(oney.shape)
flatten函数
功能:将多维数组直接转化成1维 示例:假设有numpy数组:
x=np.array([[(0,0,0,0,0,4), (0,0,0,2,0,0)],[(0,0,0,0,0,4), (0,0,0,2,0,0)]])
我们希望把数组转为1维的,则可以用flatten函数。
y=x.flatten()
输出为:[0 0 0 0 0 4 0 0 0 2 0 0 0 0 0 0 0 4 0 0 0 2 0 0]
数组感兴趣区域选取
功能:选取感兴趣值进行计算,其他非感兴趣区域置为0 示例:假设有numpy数组:
x = np.array([0, 1, 1, 3, 2, 1, 7])
我们只想计算0~2这个3个数,而无视其他的数,则可以用如下代码实现:
mask = (x >= 0) & (x <= 2)
x=x[mask]
输出为:[0 1 1 2 1] 可以看到,非感兴趣区域被删除掉了。 上面就是所有需要先掌握的点,下面直接放出图像语义分隔评估的实现代码
import numpy as np
# 精确度计算
def _fast_hist(label_true, label_pred, n_class):
#标注计算类别范围以内的数,不在范围内的不考虑
mask = (label_true >= 0) & (label_true < n_class)
# 经过这句话的处理,行数将代表标签的值,而列数将代表预测的值,而具体的值代表个数。
# 也就是说,对角线上的数分别指代第n个类别中,预测值和标签值相同的个数
hist = np.bincount(n_class * label_true[mask].astype(int) +label_pred[mask],
minlength=n_class ** 2).reshape(n_class, n_class)
return hist
def label_accuracy_score(label_trues, label_preds, n_class):
"""Returns accuracy score evaluation result.
- overall accuracy
- mean accuracy
- mean IU
- fwavacc
"""
hist = np.zeros((n_class, n_class))
#将标签和预测图像按行放入函数中
for lt, lp in zip(label_trues, label_preds):
hist += _fast_hist(lt.flatten(), lp.flatten(), n_class)
acc = np.diag(hist).sum() / hist.sum()#总体精确度计算
acc_cls = np.diag(hist) / hist.sum(axis=1)#求得每一类像素精确度的平均值
acc_cls = np.nanmean(acc_cls)#求得总体平均精确度
iu = np.diag(hist) / (hist.sum(axis=1) + hist.sum(axis=0) - np.diag(hist))#按类别求得交并比
mean_iu = np.nanmean(iu)#求得总体平均交并比
freq = hist.sum(axis=1) / hist.sum()#求得标签中各个类别所占的比例
fwavacc = (freq[freq > 0] * iu[freq > 0]).sum()#按权值计算交并比
return acc, acc_cls, mean_iu, fwavacc
label_true=np.array([[(0,0,0,0,0,4), (0,0,0,2,0,0)],[(0,0,0,0,0,4), (0,0,0,2,0,0)]])
label_pred=np.array([[(0,0,0,0,0,4), (0,0,0,2,0,0)],[(0,0,0,0,0,1), (0,0,0,2,0,0)]])
train_acc = 0
train_acc_cls = 0
train_mean_iu = 0
train_fwavacc = 0
#用zip可以遍历多维数组的第一个维度,在本应用中每次返回一张标签和一张预测图像
for lbt, lbp in zip(label_true, label_pred):
acc, acc_cls, mean_iu, fwavacc = label_accuracy_score(lbt, lbp, 5)#5为要计算的类别总数,也就是0~4
train_acc += acc
train_acc_cls += acc_cls
train_mean_iu += mean_iu
train_fwavacc += fwavacc