InPeerReview's picture
Upload 3 files
840ef2c verified
import numpy as np
from scipy import stats
import math
class AverageMeter(object):
def __init__(self):
self.initialized = False
self.val = None
self.avg = None
self.sum = None
self.count = None
def initialize(self, val, weight):
self.val = val
self.avg = val
self.sum = val * weight
self.count = weight
self.initialized = True
def update(self, val, weight=1):
if not self.initialized:
self.initialize(val, weight)
else:
self.add(val, weight)
def add(self, val, weight):
self.val = val
self.sum += val * weight
self.count += weight
self.avg = self.sum / self.count
def value(self):
return self.val
def average(self):
return self.avg
def get_scores(self):
scores_dict = cm2score(self.sum)
return scores_dict
def clear(self):
self.initialized = False
class ConfuseMatrixMeter(AverageMeter):
def __init__(self, n_class):
super(ConfuseMatrixMeter, self).__init__()
self.n_class = n_class
def update_cm(self, pr, gt, weight=1):
val = get_confuse_matrix(num_classes=self.n_class, label_gts=gt, label_preds=pr)
self.update(val, weight)
current_score = cm2F1(val)
return current_score
def get_scores(self):
scores_dict = cm2score(self.sum)
return scores_dict
def harmonic_mean(xs):
harmonic_mean = len(xs) / sum((x+1e-6)**-1 for x in xs)
return harmonic_mean
def cm2F1(confusion_matrix):
hist = confusion_matrix
n_class = hist.shape[0]
tp = np.diag(hist)
sum_a1 = hist.sum(axis=1)
sum_a0 = hist.sum(axis=0)
acc = tp.sum() / (hist.sum() + np.finfo(np.float32).eps)
recall = tp / (sum_a1 + np.finfo(np.float32).eps)
precision = tp / (sum_a0 + np.finfo(np.float32).eps)
F1 = 2 * recall * precision / (recall + precision + np.finfo(np.float32).eps)
mean_F1 = np.nanmean(F1)
return mean_F1
def cm2score(confusion_matrix):
hist = confusion_matrix
n_class = hist.shape[0]
if n_class > 2:
hist_fg = hist[1:, 1:]
c2hist = np.zeros((2, 2))
c2hist[0][0] = hist[0][0]
c2hist[0][1] = hist.sum(1)[0] - hist[0][0]
c2hist[1][0] = hist.sum(0)[0] - hist[0][0]
c2hist[1][1] = hist_fg.sum()
hist_n0 = hist.copy()
hist_n0[0][0] = 0
kappa_n0 = cal_kappa(hist_n0)
iu_scd = np.nan_to_num(np.diag(c2hist) / (c2hist.sum(1) + c2hist.sum(0) - np.diag(c2hist)))
IoU_fg = iu_scd[1]
IoU_mean = (iu_scd[0] + iu_scd[1]) / 2
Sek = (kappa_n0 * math.exp(IoU_fg)) / math.e
pixel_sum = hist.sum()
change_pred_sum = pixel_sum - hist.sum(1)[0].sum()
change_label_sum = pixel_sum - hist.sum(0)[0].sum()
change_ratio = change_label_sum / pixel_sum
SC_TP = np.diag(hist[1:, 1:]).sum()
SC_Precision = np.nan_to_num(SC_TP / change_pred_sum) + np.finfo(np.float32).eps
SC_Recall = np.nan_to_num(SC_TP / change_label_sum) + np.finfo(np.float32).eps
Fscd = stats.hmean([SC_Precision, SC_Recall])
tp = np.diag(hist)
sum_a1 = hist.sum(axis=1)
sum_a0 = hist.sum(axis=0)
acc = tp.sum() / (hist.sum() + np.finfo(np.float32).eps)
recall = tp / (sum_a1 + np.finfo(np.float32).eps)
precision = tp / (sum_a0 + np.finfo(np.float32).eps)
F1 = 2*recall * precision / (recall + precision + np.finfo(np.float32).eps)
mean_F1 = np.nanmean(F1)
iu = tp / (sum_a1 + hist.sum(axis=0) - tp + np.finfo(np.float32).eps)
mean_iu = np.nanmean(iu)
freq = sum_a1 / (hist.sum() + np.finfo(np.float32).eps)
fwavacc = (freq[freq > 0] * iu[freq > 0]).sum()
cls_iou = dict(zip(['iou_'+str(i) for i in range(n_class)], iu))
cls_precision = dict(zip(['precision_'+str(i) for i in range(n_class)], precision))
cls_recall = dict(zip(['recall_'+str(i) for i in range(n_class)], recall))
cls_F1 = dict(zip(['F1_'+str(i) for i in range(n_class)], F1))
if n_class > 2:
score_dict = {'acc': acc, 'miou': mean_iu, 'mf1':mean_F1, 'SCD_Sek':Sek, 'Fscd':Fscd, 'SCD_IoU_mean':IoU_mean}
else:
score_dict = {'acc': acc, 'miou': mean_iu, 'mf1':mean_F1}
score_dict.update(cls_iou)
score_dict.update(cls_F1)
score_dict.update(cls_precision)
score_dict.update(cls_recall)
return score_dict
def get_confuse_matrix(num_classes, label_gts, label_preds):
def __fast_hist(label_gt, label_pred):
mask = (label_gt >= 0) & (label_gt < num_classes)
hist = np.bincount(num_classes * label_gt[mask].astype(int) + label_pred[mask],
minlength=num_classes**2).reshape(num_classes, num_classes)
return hist
confusion_matrix = np.zeros((num_classes, num_classes))
for lt, lp in zip(label_gts, label_preds):
confusion_matrix += __fast_hist(lt.flatten(), lp.flatten())
return confusion_matrix
def get_mIoU(num_classes, label_gts, label_preds):
confusion_matrix = get_confuse_matrix(num_classes, label_gts, label_preds)
score_dict = cm2score(confusion_matrix)
return score_dict['miou']
def fast_hist(a, b, n):
k = (a >= 0) & (a < n)
return np.bincount(n * a[k].astype(int) + b[k], minlength=n ** 2).reshape(n, n)
def get_hist(image, label, num_class):
hist = np.zeros((num_class, num_class))
hist += fast_hist(image.flatten(), label.flatten(), num_class)
return hist
def cal_kappa(hist):
if hist.sum() == 0:
po = 0
pe = 1
kappa = 0
else:
po = np.diag(hist).sum() / hist.sum()
pe = np.matmul(hist.sum(1), hist.sum(0).T) / hist.sum() ** 2
if pe == 1:
kappa = 0
else:
kappa = (po - pe) / (1 - pe)
return kappa
def SCDD_eval_all(preds, labels, num_class):
hist = np.zeros((num_class, num_class))
for pred, label in zip(preds, labels):
infer_array = np.array(pred)
unique_set = set(np.unique(infer_array))
assert unique_set.issubset(set([0, 1, 2, 3, 4, 5, 6])), "unrecognized label number"
label_array = np.array(label)
assert infer_array.shape == label_array.shape, "The size of prediction and target must be the same"
hist += get_hist(infer_array, label_array, num_class)
hist_fg = hist[1:, 1:]
c2hist = np.zeros((2, 2))
c2hist[0][0] = hist[0][0]
c2hist[0][1] = hist.sum(1)[0] - hist[0][0]
c2hist[1][0] = hist.sum(0)[0] - hist[0][0]
c2hist[1][1] = hist_fg.sum()
hist_n0 = hist.copy()
hist_n0[0][0] = 0
kappa_n0 = cal_kappa(hist_n0)
iu = np.diag(c2hist) / (c2hist.sum(1) + c2hist.sum(0) - np.diag(c2hist))
IoU_fg = iu[1]
IoU_mean = (iu[0] + iu[1]) / 2
Sek = (kappa_n0 * math.exp(IoU_fg)) / math.e
pixel_sum = hist.sum()
change_pred_sum = pixel_sum - hist.sum(1)[0].sum()
change_label_sum = pixel_sum - hist.sum(0)[0].sum()
SC_TP = np.diag(hist[1:, 1:]).sum()
SC_Precision = SC_TP / change_pred_sum
SC_Recall = SC_TP / change_label_sum
Fscd = stats.hmean([SC_Precision, SC_Recall])
return Fscd, IoU_mean, Sek