При обнаружении объекта IOU (пересечение над объединением) - это значение от 0 до 1, которое представляет процент перекрытия между двумя прямоугольниками, нарисованными на объекте на определенном изображении.
Чтобы помочь вам понять, что это есть, вот иллюстрация:
Красная рамка - это реальное значение с координатами x1 (вверху слева), y1 (внизу слева), x2 ( вверху справа), y2 (внизу справа).
Фиолетовая рамка - это прогнозируемое значение с координатами x1_predicted, y1_predicted, x2_predicted, y2_predicted.
Желтый заштрихованный квадрат - это iou, если это значение больше определенного порога (0,5 по соглашению), прогноз оценивается как Истина, в противном случае - Ложь.
Вот код, который вычисляет долговые обязательства для 2 ящиков:
def get_iou(box_true, box_predicted):
x1, y1, x2, y2 = box_true
x1p, y1p, x2p, y2p = box_predicted
if not all([x2 > x1, y2 > y1, x2p > x1p, y2p > y1p]):
return 0
far_x = np.min([x2, x2p])
near_x = np.max([x1, x1p])
far_y = np.min([y2, y2p])
near_y = np.max([y1, y1p])
inter_area = (far_x - near_x + 1) * (far_y - near_y + 1)
true_box_area = (x2 - x1 + 1) * (y2 - y1 + 1)
pred_box_area = (x2p - x1p + 1) * (y2p - y1p + 1)
iou = inter_area / (true_box_area + pred_box_area - inter_area)
return iou
У меня есть прогнозы и фактические данные, содержащиеся в 2 файлах csv, которые я считываю в 2 pandas объектах DataFrame и go оттуда.
Для каждого изображения я извлекаю обнаружения определенного типа объекта (например: автомобиль) и фактические данные, вот пример 1 объекта (автомобиля) на 1 изображении (Beverly_hills1.png)
Actual:
Image Path Object Name X_min Y_min X_max Y_max
3842 Beverly_hills1.png Car 760 432 911 550
3843 Beverly_hills1.png Car 612 427 732 526
3844 Beverly_hills1.png Car 462 412 597 526
3845 Beverly_hills1.png Car 371 432 544 568
Detections:
image object_name x1 y1 x2 y2
594 Beverly_hills1.png Car 612 422 737 539
595 Beverly_hills1.png Car 383 414 560 583
Вот как я бы сравнил:
def calculate_overlaps(self, detections, actual):
calculations = []
detection_groups = detections.groupby('image')
actual_groups = actual.groupby('Image Path')
for item1, item2 in zip(actual_groups, detection_groups):
for detected_index, detected_row in item2[1].iterrows():
detected_coordinates = detected_row.values[2: 6]
detected_overlaps = []
coords = []
for actual_index, actual_row in item1[1].iterrows():
actual_coordinates = actual_row.values[4: 8]
detected_overlaps.append((
self.get_iou(actual_coordinates, detected_coordinates)))
coords.append(actual_coordinates)
detected_row['max_iou'] = max(detected_overlaps)
x1, y1, x2, y2 = coords[int(np.argmax(detected_overlaps))]
for match, value in zip([f'{item}_match'
for item in ['x1', 'y1', 'x2', 'y2']],
[x1, y1, x2, y2]):
detected_row[match] = value
calculations.append(detected_row)
return pd.DataFrame(calculations)
Для каждого типа объекта это будет выполняться, что неэффективно.
Конечный результат будет выглядеть так:
image object_name x1 ... y1_match x2_match y2_match
594 Beverly_hills1.png Car 612 ... 427 732 526
595 Beverly_hills1.png Car 383 ... 432 544 568
1901 Beverly_hills10.png Car 785 ... 432 940 578
2015 Beverly_hills101.png Car 832 ... 483 1240 579
2708 Beverly_hills103.png Car 376 ... 466 1333 741
... ... ... ... ... ... ... ...
618 Beverly_hills93.png Car 922 ... 406 851 659
625 Beverly_hills93.png Car 1002 ... 406 851 659
1081 Beverly_hills94.png Car 398 ... 426 527 559
1745 Beverly_hills95.png Car 1159 ... 438 470 454
1746 Beverly_hills95.png Car 765 ... 441 772 474
[584 rows x 14 columns]
Как упростить / векторизовать это и исключить циклы for? это можно сделать с помощью np.where()
?