Spaces:
Sleeping
Sleeping
import numpy as np | |
import pandas as pd | |
def box_iou_calc(boxes1, boxes2): | |
# https://github.com/pytorch/vision/blob/master/torchvision/ops/boxes.py | |
""" | |
Return intersection-over-union (Jaccard index) of boxes. | |
Both sets of boxes are expected to be in (x1, y1, x2, y2) format. | |
Arguments: | |
boxes1 (Array[N, 4]) | |
boxes2 (Array[M, 4]) | |
Returns: | |
iou (Array[N, M]): the NxM matrix containing the pairwise | |
IoU values for every element in boxes1 and boxes2 | |
This implementation is taken from the above link and changed so that it only uses numpy. | |
""" | |
def box_area(box): | |
# box = 4xn | |
return (box[2] - box[0]) * (box[3] - box[1]) | |
area1 = box_area(boxes1.T) | |
area2 = box_area(boxes2.T) | |
lt = np.maximum(boxes1[:, None, :2], boxes2[:, :2]) # [N,M,2] | |
rb = np.minimum(boxes1[:, None, 2:], boxes2[:, 2:]) # [N,M,2] | |
inter = np.prod(np.clip(rb - lt, a_min = 0, a_max = None), 2) | |
return inter / (area1[:, None] + area2 - inter) # iou = inter / (area1 + area2 - inter) | |
def mask_iou_calc(mask1, mask2): | |
# build function to take in two masks, compare them and see what their iou is. | |
# similar to above but in mask. | |
return | |
class ConfusionMatrix: | |
def __init__(self, num_classes, CONF_THRESHOLD = 0.2, IOU_THRESHOLD = 0.5): | |
self.matrix = np.zeros((num_classes + 1, num_classes + 1)) | |
self.num_classes = num_classes | |
self.CONF_THRESHOLD = CONF_THRESHOLD | |
self.IOU_THRESHOLD = IOU_THRESHOLD | |
self.got_tpfpfn = False | |
def process_batch(self, detections, labels, return_matches=False): | |
''' | |
Return intersection-over-union (Jaccard index) of boxes. | |
Both sets of boxes are expected to be in (x1, y1, x2, y2) format. | |
Arguments: | |
detections (Array[N, 6]), x1, y1, x2, y2, conf, class | |
labels (Array[M, 5]), class, x1, y1, x2, y2 | |
Returns: | |
None, updates confusion matrix accordingly | |
''' | |
detections = detections[detections[:, 4] > self.CONF_THRESHOLD] | |
gt_classes = labels[:, 0].astype(np.int16) | |
detection_classes = detections[:, 5].astype(np.int16) | |
all_ious = box_iou_calc(labels[:, 1:], detections[:, :4]) | |
# print() | |
# print('=== all_ious ===') | |
# print(all_ious) | |
want_idx = np.where(all_ious > self.IOU_THRESHOLD) | |
# print('=== want_idx ===') | |
# print(want_idx) | |
# print() | |
all_matches = [] | |
for i in range(want_idx[0].shape[0]): | |
all_matches.append([want_idx[0][i], want_idx[1][i], all_ious[want_idx[0][i], want_idx[1][i]]]) | |
all_matches = np.array(all_matches) | |
if all_matches.shape[0] > 0: # if there is match | |
all_matches = all_matches[all_matches[:, 2].argsort()[::-1]] | |
all_matches = all_matches[np.unique(all_matches[:, 1], return_index = True)[1]] | |
all_matches = all_matches[all_matches[:, 2].argsort()[::-1]] | |
all_matches = all_matches[np.unique(all_matches[:, 0], return_index = True)[1]] | |
for i, label in enumerate(labels): | |
if all_matches.shape[0] > 0 and all_matches[all_matches[:, 0] == i].shape[0] == 1: | |
gt_class = gt_classes[i] | |
detection_class = detection_classes[int(all_matches[all_matches[:, 0] == i, 1][0])] | |
self.matrix[(gt_class), detection_class] += 1 | |
else: | |
gt_class = gt_classes[i] | |
self.matrix[(gt_class), self.num_classes] += 1 | |
for i, detection in enumerate(detections): | |
if all_matches.shape[0] and all_matches[all_matches[:, 1] == i].shape[0] == 0: | |
detection_class = detection_classes[i] | |
self.matrix[self.num_classes ,detection_class] += 1 | |
if return_matches: | |
return all_matches | |
def get_tpfpfn(self): | |
self.tp = np.diag(self.matrix).sum() | |
fp = self.matrix.copy() | |
np.fill_diagonal(fp, 0) | |
self.fp = fp[:,:-1].sum() | |
self.fn = self.matrix[:-1, -1].sum() | |
self.got_tpfpfn = True | |
def get_PR(self): | |
if not self.got_tpfpfn: | |
self.get_tpfpfn() | |
# print (tp, fp, fn) | |
self.precision = self.tp / (self.tp+self.fp) | |
self.recall = self.tp/(self.tp+self.fn) | |
def return_matrix(self): | |
return self.matrix | |
def process_full_matrix(self): | |
"""method to process matrix to something more readable | |
""" | |
for idx, i in enumerate(self.matrix): | |
i[0] = idx | |
self.matrix = np.delete(self.matrix, 0, 0) | |
def print_matrix_as_df(self): | |
"""method to print out processed matrix | |
""" | |
df = pd.DataFrame(self.matrix) | |
print (df.to_string(index=False)) | |
# def print_matrix(self): | |
# for i in range(self.num_classes + 1): | |
# print(' '.join(map(str, self.matrix[i]))) | |
def return_as_csv(self, csv_file_path): | |
"""method to print out processed matrix | |
""" | |
df = pd.DataFrame(self.matrix) | |
df.to_csv(csv_file_path, index = False) | |
print (f"saved to: {csv_file_path}") | |
def return_as_df(self): | |
"""method to print out processed matrix | |
""" | |
df = pd.DataFrame(self.matrix) | |
# df = df.set_index(0) | |
# df.set_index(0) | |
# print(df.columns) | |
return df |