18장. OpenCV 전처리와 YOLO 연계
맞혔는지 재기
과녁에 화살을 쏘면 정중앙에 꽂히지 않아도 과녁 안에만 들면 점수를 줍니다. 상자도 정답과 칸 하나까지 똑같을 수는 없습니다. 그래서 "얼마나 겹쳤나"를 재서 기준 이상이면 맞힌 것으로 칩니다. 겹친 정도를 재는 값이 IoU 입니다.
초록 실선이 정답 상자, 다홍 점선이 찾은 상자, 청록으로 칠한 곳이 겹친 부분입니다. 왼쪽은 많이 겹쳐 IoU 가 0.538 이고, 오른쪽은 조금만 겹쳐 0.111 입니다. 여기서 과녁이 정답 상자, 화살이 찾은 상자, "과녁 안에 들었나"가 IoU 0.5 기준입니다.
IoU 손으로 계산하기
왼쪽 그림의 숫자로 계산합니다. 정답은 (40, 40, 140, 120), 찾은 상자는 (60, 50, 160, 130) 입니다.
| 구할 것 | 식 | 계산 | 값 |
|---|---|---|---|
| 정답의 넓이 | 너비 × 높이 | (140 − 40) × (120 − 40) = 100 × 80 | 8000 |
| 찾은 상자의 넓이 | 너비 × 높이 | (160 − 60) × (130 − 50) = 100 × 80 | 8000 |
| 겹친 너비 | 작은 오른쪽 끝 − 큰 왼쪽 끝 | min(140, 160) − max(40, 60) = 140 − 60 | 80 |
| 겹친 높이 | 작은 아래 끝 − 큰 위 끝 | min(120, 130) − max(40, 50) = 120 − 50 | 70 |
| 겹친 넓이 | 겹친 너비 × 겹친 높이 | 80 × 70 | 5600 |
| 합친 넓이 | 두 넓이의 합 − 겹친 넓이 | 8000 + 8000 − 5600 | 10400 |
| IoU | 겹친 넓이 ÷ 합친 넓이 | 5600 ÷ 10400 | 0.538 |
합친 넓이에서 겹친 넓이를 한 번 빼는 까닭은, 두 넓이를 더하면 겹친 곳이 두 번 세어지기 때문입니다. IoU 는 두 상자가 똑같으면 1, 전혀 안 겹치면 0 입니다.
짝짓고 세기
사진 한 장에서 찾은 상자들과 정답 상자들을 짝짓습니다. 신뢰도가 높은 찾은 상자부터, 아직 짝이 없는 같은 클래스의 정답 가운데 IoU 가 가장 큰 것과 짝짓습니다. 그 IoU 가 0.5 이상이면 맞힌 것입니다.
그림의 세 카드가 짝짓기를 마친 뒤 세는 세 가지입니다. 11장의 그물 비유로 말하면, 맞힌 것은 그물에 걸린 물고기, 헛것은 그물에 걸린 깡통, 놓친 것은 그물을 빠져나간 물고기입니다. 점수는 11장에서 본 것과 같은 식으로 냅니다.
| 점수 | 식 | 뜻 |
|---|---|---|
| 정밀도 | 맞힌 것 ÷ (맞힌 것 + 헛것) | 찾은 상자 가운데 맞은 비율 |
| 재현율 | 맞힌 것 ÷ (맞힌 것 + 놓친 것) | 정답 가운데 찾아낸 비율 |
| F1 | 2 × 정밀도 × 재현율 ÷ (정밀도 + 재현율) | 둘을 하나로 합친 점수 |
def iou(a, b):
"""두 상자 (x1, y1, x2, y2) 의 IoU = 겹친 넓이 ÷ 합친 넓이."""
w = min(a[2], b[2]) - max(a[0], b[0]) # 겹친 너비(음수면 안 겹침)
h = min(a[3], b[3]) - max(a[1], b[1]) # 겹친 높이
inter = max(0, w) * max(0, h)
union = (a[2] - a[0]) * (a[3] - a[1]) + (b[2] - b[0]) * (b[3] - b[1]) - inter
return inter / union
print(round(iou((40, 40, 140, 120), (60, 50, 160, 130)), 3)) # 결과: 0.538
print(round(iou((40, 40, 140, 120), (100, 80, 200, 160)), 3)) # 결과: 0.111
# 맞힌 것 3, 헛것 1, 놓친 것 2 일 때의 점수
tp, fp, fn = 3, 1, 2
precision, recall = tp / (tp + fp), tp / (tp + fn)
print(round(precision, 3), round(recall, 3), round(2 * precision * recall / (precision + recall), 3))맞힌 것 3, 헛것 1 이면 정밀도는 3 ÷ 4 = 0.75, 놓친 것이 2 면 재현율은 3 ÷ 5 = 0.6 입니다. F1 은 2 × 0.75 × 0.6 ÷ 1.35 = 0.667 로, 11장의 그물 예와 같은 값이 나옵니다.
주의할 점
- 정답 하나에 찾은 상자 둘이 겹치면, 먼저 짝지은 하나만 맞힌 것이고 나머지는 헛것입니다. 정답 하나에 점수를 두 번 주지 않습니다.
- 상자가 잘 겹쳐도 클래스가 다르면(너트를 와셔라고 하면) 맞힌 것이 아닙니다. 그 상자는 헛것이 되고, 그 정답은 놓친 것이 됩니다.