seg_eval.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. # copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. import os
  15. import sys
  16. import numpy as np
  17. from scipy.sparse import csr_matrix
  18. class ConfusionMatrix(object):
  19. """
  20. Confusion Matrix for segmentation evaluation
  21. """
  22. def __init__(self, num_classes=2, streaming=False):
  23. self.confusion_matrix = np.zeros(
  24. [num_classes, num_classes], dtype='int64')
  25. self.num_classes = num_classes
  26. self.streaming = streaming
  27. def calculate(self, pred, label, ignore=None):
  28. # If not in streaming mode, clear matrix everytime when call `calculate`
  29. if not self.streaming:
  30. self.zero_matrix()
  31. label = np.transpose(label, (0, 2, 3, 1))
  32. ignore = np.transpose(ignore, (0, 2, 3, 1))
  33. mask = np.array(ignore) == 1
  34. label = np.asarray(label)[mask]
  35. pred = np.asarray(pred)[mask]
  36. one = np.ones_like(pred)
  37. # Accumuate ([row=label, col=pred], 1) into sparse matrix
  38. spm = csr_matrix(
  39. (one, (label, pred)), shape=(self.num_classes, self.num_classes))
  40. spm = spm.todense()
  41. self.confusion_matrix += spm
  42. def zero_matrix(self):
  43. """ Clear confusion matrix """
  44. self.confusion_matrix = np.zeros(
  45. [self.num_classes, self.num_classes], dtype='int64')
  46. def mean_iou(self):
  47. iou_list = []
  48. avg_iou = 0
  49. # TODO: use numpy sum axis api to simpliy
  50. vji = np.zeros(self.num_classes, dtype=int)
  51. vij = np.zeros(self.num_classes, dtype=int)
  52. for j in range(self.num_classes):
  53. v_j = 0
  54. for i in range(self.num_classes):
  55. v_j += self.confusion_matrix[j][i]
  56. vji[j] = v_j
  57. for i in range(self.num_classes):
  58. v_i = 0
  59. for j in range(self.num_classes):
  60. v_i += self.confusion_matrix[j][i]
  61. vij[i] = v_i
  62. for c in range(self.num_classes):
  63. total = vji[c] + vij[c] - self.confusion_matrix[c][c]
  64. if total == 0:
  65. iou = 0
  66. else:
  67. iou = float(self.confusion_matrix[c][c]) / total
  68. avg_iou += iou
  69. iou_list.append(iou)
  70. avg_iou = float(avg_iou) / float(self.num_classes)
  71. return np.array(iou_list), avg_iou
  72. def accuracy(self):
  73. total = self.confusion_matrix.sum()
  74. total_right = 0
  75. for c in range(self.num_classes):
  76. total_right += self.confusion_matrix[c][c]
  77. if total == 0:
  78. avg_acc = 0
  79. else:
  80. avg_acc = float(total_right) / total
  81. vij = np.zeros(self.num_classes, dtype=int)
  82. for i in range(self.num_classes):
  83. v_i = 0
  84. for j in range(self.num_classes):
  85. v_i += self.confusion_matrix[j][i]
  86. vij[i] = v_i
  87. acc_list = []
  88. for c in range(self.num_classes):
  89. if vij[c] == 0:
  90. acc = 0
  91. else:
  92. acc = self.confusion_matrix[c][c] / float(vij[c])
  93. acc_list.append(acc)
  94. return np.array(acc_list), avg_acc
  95. def kappa(self):
  96. vji = np.zeros(self.num_classes)
  97. vij = np.zeros(self.num_classes)
  98. for j in range(self.num_classes):
  99. v_j = 0
  100. for i in range(self.num_classes):
  101. v_j += self.confusion_matrix[j][i]
  102. vji[j] = v_j
  103. for i in range(self.num_classes):
  104. v_i = 0
  105. for j in range(self.num_classes):
  106. v_i += self.confusion_matrix[j][i]
  107. vij[i] = v_i
  108. total = self.confusion_matrix.sum()
  109. # avoid spillovers
  110. # TODO: is it reasonable to hard code 10000.0?
  111. total = float(total) / 10000.0
  112. vji = vji / 10000.0
  113. vij = vij / 10000.0
  114. tp = 0
  115. tc = 0
  116. for c in range(self.num_classes):
  117. tp += vji[c] * vij[c]
  118. tc += self.confusion_matrix[c][c]
  119. tc = tc / 10000.0
  120. pe = tp / (total * total)
  121. po = tc / total
  122. kappa = (po - pe) / (1 - pe)
  123. return kappa
  124. def f1_score(self):
  125. f1score_list = []
  126. # TODO: use numpy sum axis api to simpliy
  127. vji = np.zeros(self.num_classes, dtype=int)
  128. vij = np.zeros(self.num_classes, dtype=int)
  129. for j in range(self.num_classes):
  130. v_j = 0
  131. for i in range(self.num_classes):
  132. v_j += self.confusion_matrix[j][i]
  133. vji[j] = v_j
  134. for i in range(self.num_classes):
  135. v_i = 0
  136. for j in range(self.num_classes):
  137. v_i += self.confusion_matrix[j][i]
  138. vij[i] = v_i
  139. for c in range(self.num_classes):
  140. if vji[c] == 0:
  141. precision = 0
  142. else:
  143. precision = self.confusion_matrix[c][c] / vji[c]
  144. if vij[c] == 0:
  145. recall = 0
  146. else:
  147. recall = self.confusion_matrix[c][c] / vij[c]
  148. if recall + precision <= 1e-06:
  149. f1_score = 0
  150. else:
  151. f1score = 2 * precision * recall / (recall + precision)
  152. f1score_list.append(f1score)
  153. return np.array(f1score_list)