text: """
  Script from https://github.com/warmspringwinds/pytorch-segmentation-detection
  """
  
  import numpy as np
  from sklearn.metrics import confusion_matrix
  
  
  class RunningConfusionMatrix():
      """Running Confusion Matrix class that enables computation of confusion matrix
      on the go and has methods to compute such accuracy metrics as Mean Intersection over
      Union MIOU.
      
      Attributes
      ----------
      labels : list[int]
          List that contains int values that represent classes.
      overall_confusion_matrix : sklean.confusion_matrix object
          Container of the sum of all confusion matrices. Used to compute MIOU at the end.
      ignore_label : int
          A label representing parts that should be ignored during
          computation of metrics
          
      """
      
      def __init__(self, labels, ignore_label=255):
          
          self.labels = labels
          self.ignore_label = ignore_label
          self.overall_confusion_matrix = None
          
      def update_matrix(self, ground_truth, prediction):
          """Updates overall confusion matrix statistics.
          If you are working with 2D data, just .flatten() it before running this
          function.
  
          Parameters
          ----------
          groundtruth : array, shape = [n_samples]
              An array with groundtruth values
          prediction : array, shape = [n_samples]
              An array with predictions
          """
          
          # Mask-out value is ignored by default in the sklearn
          # read sources to see how that was handled
          # But sometimes all the elements in the groundtruth can
          # be equal to ignore value which will cause the crush
          # of scikit_learn.confusion_matrix(), this is why we check it here
          if (ground_truth == self.ignore_label).all():
              
              return
          
          current_confusion_matrix = confusion_matrix(y_true=ground_truth,
                                                      y_pred=prediction,
                                                      labels=self.labels)
          
          if self.overall_confusion_matrix is not None:
              
              self.overall_confusion_matrix += current_confusion_matrix
          else:
              
              self.overall_confusion_matrix = current_confusion_matrix
      
      def compute_current_mean_intersection_over_union(self):
          
          intersection = np.diag(self.overall_confusion_matrix)
          ground_truth_set = self.overall_confusion_matrix.sum(axis=1)
          predicted_set = self.overall_confusion_matrix.sum(axis=0)
          union =  ground_truth_set + predicted_set - intersection
  
          intersection_over_union = intersection / union.astype(np.float32)
          mean_intersection_over_union = np.nanmean(intersection_over_union)
          
          return mean_intersection_over_union
  
      def get_nclasses(self):
          predicted_set = self.overall_confusion_matrix.sum(axis=0)
          return len(np.where(predicted_set != 0)[0])
  