17장. Batch Processing 과 YOLO 데이터 준비
상자 좌표 형식 세 가지
약속 장소를 알려 주는 방법은 여러 가지입니다. "역 1번 출구에서 사거리까지" 처럼 두 지점을 말할 수도 있고, "1번 출구에서 오른쪽으로 100걸음" 처럼 출발점과 거리를 말할 수도 있습니다. 상자 하나도 적는 법이 셋 있습니다. 같은 상자를 다르게 적을 뿐이라서 서로 바꿀 수 있습니다.
그림은 너트 하나를 감싼 상자에 세 형식의 숫자를 적은 것입니다. 다홍 점이 왼쪽 위 (x1, y1), 보라 점이 오른쪽 아래 (x2, y2), 초록 점이 가운데입니다. 여기서 "두 지점을 말하기"가 (x1, y1, x2, y2), "출발점과 거리"가 (x, y, 너비, 높이), 그리고 YOLO 형식은 가운데 점과 크기를 그림 크기에 대한 비율로 적습니다.
세 형식 견주기
| 형식 | 적는 숫자 | 단위 | 쓰는 곳 |
|---|---|---|---|
| 모서리 두 점 | x1, y1, x2, y2 (왼쪽 위, 오른쪽 아래) | 픽셀 | Pascal VOC, 이 장의 annotations.csv |
| 왼쪽 위와 크기 | x, y, w, h | 픽셀 | COCO, cv2.boundingRect(12장), 2장의 자르기 |
| 가운데와 크기 | xc, yc, w, h | 0~1 의 비율 | YOLO |
이 장의 주석에서 x2, y2 는 상자의 오른쪽 끝과 아래 끝 자리입니다. 그래서 너비는 x2 − x1, 높이는 y2 − y1 입니다.
손으로 바꿔 보기
가로 320, 세로 240 인 그림에 x1 = 40, y1 = 60, x2 = 120, y2 = 100 인 상자가 있다고 해 봅시다.
| 구할 것 | 식 | 계산 | 값 |
|---|---|---|---|
| 가운데 x(픽셀) | (x1 + x2) ÷ 2 | (40 + 120) ÷ 2 | 80 |
| 가운데 y(픽셀) | (y1 + y2) ÷ 2 | (60 + 100) ÷ 2 | 80 |
| 너비(픽셀) | x2 − x1 | 120 − 40 | 80 |
| 높이(픽셀) | y2 − y1 | 100 − 60 | 40 |
| xc | 가운데 x ÷ 그림 가로 | 80 ÷ 320 | 0.25 |
| yc | 가운데 y ÷ 그림 세로 | 80 ÷ 240 | 0.333333 |
| w | 너비 ÷ 그림 가로 | 80 ÷ 320 | 0.25 |
| h | 높이 ÷ 그림 세로 | 40 ÷ 240 | 0.166667 |
거꾸로 되돌릴 때는 곱합니다. 가운데 x 는 0.25 × 320 = 80, 너비는 0.25 × 320 = 80 이므로 x1 = 80 − 80 ÷ 2 = 40, x2 = 80 + 80 ÷ 2 = 120 입니다.
비율로 적는 까닭
그림을 가로 640, 세로 480 으로 두 배 키우면 상자의 픽셀 좌표도 모두 두 배(80, 120, 240, 200)가 됩니다. 그런데 가운데 x 를 비율로 적으면 160 ÷ 640 = 0.25 로 그대로입니다. 비율 좌표는 그림 크기를 바꿔도 라벨을 고칠 필요가 없습니다. YOLO 는 학습할 때 그림 크기를 바꿔 넣으므로 이 성질이 쓸모 있습니다.
x1, y1, x2, y2 = 40, 60, 120, 100 # 모서리 두 점(픽셀)
W, H = 320, 240 # 그림의 가로, 세로
# 왼쪽 위와 크기(픽셀): COCO, boundingRect 와 같은 꼴
print("x, y, w, h =", (x1, y1, x2 - x1, y2 - y1))
# 가운데와 크기(비율): YOLO 형식. 소수 여섯째 자리까지 적는다
xc, yc = (x1 + x2) / 2 / W, (y1 + y2) / 2 / H
w, h = (x2 - x1) / W, (y2 - y1) / H
print("xc, yc, w, h =", [round(v, 6) for v in (xc, yc, w, h)])
# 그림을 두 배로 키워도 비율은 같다
print("두 배 그림의 xc:", (2 * x1 + 2 * x2) / 2 / (2 * W))주의할 점
- 형식마다 넷째 숫자의 뜻이 다릅니다. (x1, y1, x2, y2) 의 셋째 값은 오른쪽 끝 자리이고, (x, y, w, h) 의 셋째 값은 너비입니다. 데이터를 받으면 어느 형식인지 먼저 확인합니다.
- YOLO 형식에서 xc 는 그림의 가로로, yc 는 세로로 나눕니다. 가로와 세로를 바꿔 나누면 상자가 엉뚱한 자리로 갑니다.