Source code for gluoncv.utils.metrics.segmentation

"""Evaluation Metrics for Semantic Segmentation"""
import threading
import numpy as np
import mxnet as mx
try:
    from mxnet.metric import EvalMetric
except ImportError:
    from mxnet.gluon.metric import EvalMetric

__all__ = ['SegmentationMetric', 'batch_pix_accuracy', 'batch_intersection_union',
           'pixelAccuracy', 'intersectionAndUnion']

[docs]class SegmentationMetric(EvalMetric): """Computes pixAcc and mIoU metric scores """ def __init__(self, nclass): super(SegmentationMetric, self).__init__('pixAcc & mIoU') self.nclass = nclass self.lock = threading.Lock() self.reset()
[docs] def update(self, labels, preds): """Updates the internal evaluation result. Parameters ---------- labels : 'NDArray' or list of `NDArray` The labels of the data. preds : 'NDArray' or list of `NDArray` Predicted values. """ def evaluate_worker(self, label, pred): correct, labeled = batch_pix_accuracy( pred, label) inter, union = batch_intersection_union( pred, label, self.nclass) with self.lock: self.total_correct += correct self.total_label += labeled self.total_inter += inter self.total_union += union if isinstance(preds, mx.nd.NDArray): evaluate_worker(self, labels, preds) elif isinstance(preds, (list, tuple)): threads = [threading.Thread(target=evaluate_worker, args=(self, label, pred), ) for (label, pred) in zip(labels, preds)] for thread in threads: thread.start() for thread in threads: thread.join()
[docs] def get(self): """Gets the current evaluation result. Returns ------- metrics : tuple of float pixAcc and mIoU """ pixAcc = 1.0 * self.total_correct / (np.spacing(1) + self.total_label) IoU = 1.0 * self.total_inter / (np.spacing(1) + self.total_union) mIoU = IoU.mean() return pixAcc, mIoU
[docs] def reset(self): """Resets the internal evaluation result to initial state.""" self.total_inter = 0 self.total_union = 0 self.total_correct = 0 self.total_label = 0
def batch_pix_accuracy(output, target): """PixAcc""" # inputs are NDarray, output 4D, target 3D # the category -1 is ignored class, typically for background / boundary predict = np.argmax(output.asnumpy(), 1).astype('int64') + 1 target = target.asnumpy().astype('int64') + 1 pixel_labeled = np.sum(target > 0) pixel_correct = np.sum((predict == target)*(target > 0)) assert pixel_correct <= pixel_labeled, "Correct area should be smaller than Labeled" return pixel_correct, pixel_labeled def batch_intersection_union(output, target, nclass): """mIoU""" # inputs are NDarray, output 4D, target 3D # the category -1 is ignored class, typically for background / boundary mini = 1 maxi = nclass nbins = nclass predict = np.argmax(output.asnumpy(), 1).astype('int64') + 1 target = target.asnumpy().astype('int64') + 1 predict = predict * (target > 0).astype(predict.dtype) intersection = predict * (predict == target) # areas of intersection and union area_inter, _ = np.histogram(intersection, bins=nbins, range=(mini, maxi)) area_pred, _ = np.histogram(predict, bins=nbins, range=(mini, maxi)) area_lab, _ = np.histogram(target, bins=nbins, range=(mini, maxi)) area_union = area_pred + area_lab - area_inter assert (area_inter <= area_union).all(), \ "Intersection area should be smaller than Union area" return area_inter, area_union def pixelAccuracy(imPred, imLab): """ This function takes the prediction and label of a single image, returns pixel-wise accuracy To compute over many images do: for i = range(Nimages): (pixel_accuracy[i], pixel_correct[i], pixel_labeled[i]) = \ pixelAccuracy(imPred[i], imLab[i]) mean_pixel_accuracy = 1.0 * np.sum(pixel_correct) / (np.spacing(1) + np.sum(pixel_labeled)) """ # Remove classes from unlabeled pixels in gt image. # We should not penalize detections in unlabeled portions of the image. pixel_labeled = np.sum(imLab > 0) pixel_correct = np.sum((imPred == imLab)*(imLab > 0)) pixel_accuracy = 1.0 * pixel_correct / pixel_labeled return (pixel_accuracy, pixel_correct, pixel_labeled) def intersectionAndUnion(imPred, imLab, numClass): """ This function takes the prediction and label of a single image, returns intersection and union areas for each class To compute over many images do: for i in range(Nimages): (area_intersection[:,i], area_union[:,i]) = intersectionAndUnion(imPred[i], imLab[i]) IoU = 1.0 * np.sum(area_intersection, axis=1) / np.sum(np.spacing(1)+area_union, axis=1) """ # Remove classes from unlabeled pixels in gt image. # We should not penalize detections in unlabeled portions of the image. imPred = imPred * (imLab > 0) # Compute area intersection: intersection = imPred * (imPred == imLab) (area_intersection, _) = np.histogram(intersection, bins=numClass, range=(1, numClass)) # Compute area union: (area_pred, _) = np.histogram(imPred, bins=numClass, range=(1, numClass)) (area_lab, _) = np.histogram(imLab, bins=numClass, range=(1, numClass)) area_union = area_pred + area_lab - area_intersection return (area_intersection, area_union)