IoU란 Intersection over Union의 약자로 말그대로 두 영역의 겹치는 영역을 두 영역의 합으로 나눈 값을 의미합니다. 따라서 두 영역이 완전히 겹친다면 겹치는 영역과 합의 영역이 동일하므로 1이 되고, 전혀 겹치지 않는다면 0이 됩니다.
IoU는 주로 Object Detection에서 예측된 bounding box의 정확도를 평가하는 지표 중 하나로 사용됩니다. 일반적으로 임계값을 지정하여 해당 임계값을 초과하는 경우에는 해당 위치에 대한 예측을 유효한 것으로 간주합니다. 논문 등에서 객체탐지 성능평가표에 mAP@0.5
로 표기되었다면 IoU 임계값을 0.5로 설정했다는 의미입니다. 임계값을 높이면 더 정밀하게 일치한 예측만을 맞는 것으로 간주하는 것이므로 전체적인 성능평가 수치는 하락할 것입니다.
실제 데이터로 IoU를 계산하는 로직을 구현해봅시다.
gt.json
파일에는 여러 이미지의 ground-truth 데이터의 boudning box와 class 정보가 포함되어 있습니다. dictionary 형태 데이터로 key-value 형식입니다. 실제 데이터는 다음과 같습니다.
{"boxes": [[793, 1134, 1001, 1718], [737, 0, 898, 260], [763, 484, 878, 619], [734, 0, 1114, 277], [853, 0, 1280, 250], [820, 1566, 974, 1914], [762, 951, 844, 1175], [748, 197, 803, 363]], "classes": [1, 1, 1, 1, 2, 1, 1, 1], "filename": "0001.png"},
pred.json
파일에는 예측한 데이터의 bounding box와 class 정보가 포함되어 있습니다.
{"boxes": [[783, 1104, 1011, 1700], [853, 0, 1220, 200], [734, 0, 1100, 240], [753, 474, 868, 609], [830, 1500, 1004, 1914]], "classes": [1, 2, 1, 2, 1], "filename": "0001.png"},
먼저 json을 로드합니다.
with open('qt.json) as f:
ground_truth = json.load(f)
with open('pred.json) as f:
predictions = json.load(f)
예측 데이터 중 지금 측정하려고 하는 특정 이미지(0001.png
)에 대한 ground-truth와 prediction의 bounding box들을 numpy array 형태로 추출합니다.
gt_bboxes = np.array([g['boxes'] for g in ground_truth if g['filename'] == '0001.png'][0])
pred_bboxes = np.array([p['boxes'] for p in predictions if p['filename'] == '0001.png'][0])
추출한 numpy array를 순회하면서 각 박스들의 IoU를 계산합니다.
def calculate_ious(gt_bboxes, pred_bboxes):
ious = np.zeros((gt_bboxes.shape[0], pred_bboxes.shape[0]))
for i, gt_bbox in enumerate(gt_bboxes):
for j, pred_bbox in enumerate(pred_bboxes):
ious[i,j] = calculate_iou(gt_bbox, pred_bbox)
return ious
def calculate_iou(gt_bbox, pred_bbox):
box1_area = (gt_bbox[2]-gt_bbox[0]) * (gt_bbox[3]-gt_bbox[1])
box2_area = (pred_bbox[2]-pred_bbox[0]) * (pred_bbox[3]-pred_bbox[1])
# intersection box
x1 = max(gt_bbox[0], pred_bbox[0])
y1 = max(gt_bbox[1], pred_bbox[1])
x2 = min(gt_bbox[2], pred_bbox[2])
y2 = min(gt_bbox[3], pred_bbox[3])
w = max(x2-x1, 0)
h = max(y2-y1, 0)
if w > 0 and h > 0:
intersect = w*h
iou = intersect / (box1_area + box2_area - intersect)
else:
iou = 0
return iou