Skip to content

Commit c3b8e3d

Browse files
authored
add cm code
1 parent 5caba2d commit c3b8e3d

File tree

1 file changed

+93
-0
lines changed

1 file changed

+93
-0
lines changed

confusion_matrix.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import numpy as np
2+
3+
4+
def box_iou_calc(boxes1, boxes2):
5+
# https://github.com/pytorch/vision/blob/master/torchvision/ops/boxes.py
6+
"""
7+
Return intersection-over-union (Jaccard index) of boxes.
8+
Both sets of boxes are expected to be in (x1, y1, x2, y2) format.
9+
Arguments:
10+
boxes1 (Array[N, 4])
11+
boxes2 (Array[M, 4])
12+
Returns:
13+
iou (Array[N, M]): the NxM matrix containing the pairwise
14+
IoU values for every element in boxes1 and boxes2
15+
16+
This implementation is taken from the above link and changed so that it only uses numpy..
17+
"""
18+
19+
def box_area(box):
20+
# box = 4xn
21+
return (box[2] - box[0]) * (box[3] - box[1])
22+
23+
24+
area1 = box_area(boxes1.T)
25+
area2 = box_area(boxes2.T)
26+
27+
lt = np.maximum(boxes1[:, None, :2], boxes2[:, :2]) # [N,M,2]
28+
rb = np.minimum(boxes1[:, None, 2:], boxes2[:, 2:]) # [N,M,2]
29+
30+
inter = np.prod(np.clip(rb - lt, a_min = 0, a_max = None), 2)
31+
return inter / (area1[:, None] + area2 - inter) # iou = inter / (area1 + area2 - inter)
32+
33+
34+
class ConfusionMatrix:
35+
def __init__(self, num_classes, CONF_THRESHOLD = 0.3, IOU_THRESHOLD = 0.5):
36+
self.matrix = np.zeros((num_classes + 1, num_classes + 1))
37+
self.num_classes = num_classes
38+
self.CONF_THRESHOLD = CONF_THRESHOLD
39+
self.IOU_THRESHOLD = IOU_THRESHOLD
40+
41+
def process_batch(self, detections, labels):
42+
'''
43+
Return intersection-over-union (Jaccard index) of boxes.
44+
Both sets of boxes are expected to be in (x1, y1, x2, y2) format.
45+
Arguments:
46+
detections (Array[N, 6]), x1, y1, x2, y2, conf, class
47+
labels (Array[M, 5]), x1, y1, x2, y2, class
48+
Returns:
49+
None, updates confusion matrix accordingly
50+
'''
51+
detections = detections[detections[:, 4] > self.CONF_THRESHOLD]
52+
gt_classes = labels[:, 0].astype(np.int16)
53+
detection_classes = detections[:, 5].astype(np.int16)
54+
55+
all_ious = box_iou_calc(labels[:, 1:], detections[:, :4])
56+
want_idx = np.where(all_ious > self.IOU_THRESHOLD)
57+
58+
all_matches = []
59+
for i in range(want_idx[0].shape[0]):
60+
all_matches.append([want_idx[0][i], want_idx[1][i], all_ious[want_idx[0][i], want_idx[1][i]]])
61+
62+
all_matches = np.array(all_matches)
63+
if all_matches.shape[0] > 0: # if there is match
64+
all_matches = all_matches[all_matches[:, 2].argsort()[::-1]]
65+
66+
all_matches = all_matches[np.unique(all_matches[:, 1], return_index = True)[1]]
67+
68+
all_matches = all_matches[all_matches[:, 2].argsort()[::-1]]
69+
70+
all_matches = all_matches[np.unique(all_matches[:, 0], return_index = True)[1]]
71+
72+
73+
for i, label in enumerate(labels):
74+
if all_matches.shape[0] > 0 and all_matches[all_matches[:, 0] == i].shape[0] == 1:
75+
gt_class = gt_classes[i]
76+
detection_class = detection_classes[int(all_matches[all_matches[:, 0] == i, 1][0])]
77+
self.matrix[(gt_class), detection_class] += 1
78+
else:
79+
gt_class = gt_classes[i]
80+
self.matrix[(gt_class), self.num_classes] += 1
81+
82+
for i, detection in enumerate(detections):
83+
if all_matches.shape[0] and all_matches[all_matches[:, 1] == i].shape[0] == 1:
84+
detection_class = detection_classes[i]
85+
self.matrix[self.num_classes ,detection_class] += 1
86+
87+
def return_matrix(self):
88+
return self.matrix
89+
90+
def print_matrix(self):
91+
for i in range(self.num_classes + 1):
92+
print(' '.join(map(str, self.matrix[i])))
93+

0 commit comments

Comments
 (0)