hasibzunair's picture
add files
1803579
# code borrowed from https://github.com/Hanqer/Evaluate-SOD/blob/master/evaluator.py
import numpy as np
import torch
class SMeasure:
def __init__(self, alpha: float = 0.5):
self.alpha: float = alpha
self.cuda: bool = True
def _centroid(self, gt):
rows, cols = gt.size()[-2:]
gt = gt.view(rows, cols)
if gt.sum() == 0:
if self.cuda:
X = torch.eye(1).cuda() * round(cols / 2)
Y = torch.eye(1).cuda() * round(rows / 2)
else:
X = torch.eye(1) * round(cols / 2)
Y = torch.eye(1) * round(rows / 2)
else:
total = gt.sum()
if self.cuda:
i = torch.from_numpy(np.arange(0, cols)).cuda().float()
j = torch.from_numpy(np.arange(0, rows)).cuda().float()
else:
i = torch.from_numpy(np.arange(0, cols)).float()
j = torch.from_numpy(np.arange(0, rows)).float()
X = torch.round((gt.sum(dim=0) * i).sum() / total)
Y = torch.round((gt.sum(dim=1) * j).sum() / total)
return X.long(), Y.long()
def _ssim(self, pred, gt):
gt = gt.float()
h, w = pred.size()[-2:]
N = h * w
x = pred.mean()
y = gt.mean()
sigma_x2 = ((pred - x) * (pred - x)).sum() / (N - 1 + 1e-20)
sigma_y2 = ((gt - y) * (gt - y)).sum() / (N - 1 + 1e-20)
sigma_xy = ((pred - x) * (gt - y)).sum() / (N - 1 + 1e-20)
aplha = 4 * x * y * sigma_xy
beta = (x * x + y * y) * (sigma_x2 + sigma_y2)
if aplha != 0:
Q = aplha / (beta + 1e-20)
elif aplha == 0 and beta == 0:
Q = 1.0
else:
Q = 0
return Q
def _object(self, pred, gt):
temp = pred[gt == 1]
x = temp.mean()
sigma_x = temp.std()
score = 2.0 * x / (x * x + 1.0 + sigma_x + 1e-20)
return score
def _s_object(self, pred, gt):
fg = torch.where(gt == 0, torch.zeros_like(pred), pred)
bg = torch.where(gt == 1, torch.zeros_like(pred), 1 - pred)
o_fg = self._object(fg, gt)
o_bg = self._object(bg, 1 - gt)
u = gt.mean()
Q = u * o_fg + (1 - u) * o_bg
return Q
def _divide_gt(self, gt, X, Y):
h, w = gt.size()[-2:]
area = h * w
gt = gt.view(h, w)
LT = gt[:Y, :X]
RT = gt[:Y, X:w]
LB = gt[Y:h, :X]
RB = gt[Y:h, X:w]
X = X.float()
Y = Y.float()
w1 = X * Y / area
w2 = (w - X) * Y / area
w3 = X * (h - Y) / area
w4 = 1 - w1 - w2 - w3
return LT, RT, LB, RB, w1, w2, w3, w4
def _divide_prediction(self, pred, X, Y):
h, w = pred.size()[-2:]
pred = pred.view(h, w)
LT = pred[:Y, :X]
RT = pred[:Y, X:w]
LB = pred[Y:h, :X]
RB = pred[Y:h, X:w]
return LT, RT, LB, RB
def _s_region(self, pred, gt):
X, Y = self._centroid(gt)
gt1, gt2, gt3, gt4, w1, w2, w3, w4 = self._divide_gt(gt, X, Y)
p1, p2, p3, p4 = self._divide_prediction(pred, X, Y)
Q1 = self._ssim(p1, gt1)
Q2 = self._ssim(p2, gt2)
Q3 = self._ssim(p3, gt3)
Q4 = self._ssim(p4, gt4)
Q = w1 * Q1 + w2 * Q2 + w3 * Q3 + w4 * Q4
# print(Q)
return Q
def __call__(self, pred_mask: torch.Tensor, gt_mask: torch.Tensor):
assert pred_mask.shape == gt_mask.shape
y = gt_mask.mean()
if y == 0:
x = pred_mask.mean()
Q = 1.0 - x
elif y == 1:
x = pred_mask.mean()
Q = x
else:
gt_mask[gt_mask >= 0.5] = 1
gt_mask[gt_mask < 0.5] = 0
# print(self._S_object(pred, gt), self._S_region(pred, gt))
Q = self.alpha * self._s_object(pred_mask, gt_mask) + (
1 - self.alpha
) * self._s_region(pred_mask, gt_mask)
if Q.item() < 0:
Q = torch.FloatTensor([0.0])
return Q.item()