18장. OpenCV 전처리와 YOLO 연계
지나친 전처리의 함정
얼룩이 묻은 안경을 닦을 때 너무 세게 문지르면 얼룩과 함께 렌즈 코팅까지 벗겨집니다. 깨끗해 보이지만 오히려 잘 안 보입니다. 사진 손질도 그렇습니다. 잡음을 줄이려고 블러를 세게 걸면 잡음과 함께 너트의 모서리와 구멍 테두리도 뭉개집니다. YOLO 는 이런 모서리와 테두리를 보고 볼트, 너트, 와셔를 가립니다.
왼쪽 카드의 알맞은 손질은 잡음만 줄이고 모서리와 구멍은 남깁니다. 오른쪽 카드의 지나친 손질은 둘 다 지웁니다. 여기서 얼룩이 잡음, 렌즈 코팅이 모서리와 구멍 테두리입니다.
윗줄은 어둡게와 잡음을 함께 넣은 그림을 네 가지로 손질한 것이고, 아랫줄은 윗줄의 다홍 네모 안의 너트를 크게 본 것입니다. 밝기만 올리면 잡음이 함께 커져 알록달록한 점투성이가 됩니다. 블러 5×5 뒤에 밝기를 올리면 잡음이 줄고 육각형 모서리가 남습니다. 블러 15×15 는 잡음이 거의 없지만 육각형의 모서리가 둥글어지고 구멍 테두리가 흐려집니다.
점수로 드러난 함정은 "밝기만" 쪽이었습니다. 프로젝트에서 잡음 낀 사진에 밝기만 올리면 헛것이 5개에서 10개로 늘어 F1 이 0.873 에서 0.737 로 떨어졌고, 어둡게+잡음 판은 밝기만 올려서는 하나도 맞히지 못했습니다(F1 0). 잡음을 그대로 둔 채 밝기를 키운 손질이 오히려 해가 된 경우입니다.
눈에 보기 좋은 것과 모델에 좋은 것
6장에서는 원본과의 차이(MAE)로 잡음 제거를 견줬습니다. 그런데 MAE 가 작다고 모델에 좋은 것은 아닙니다. 교안 PC 에서 잰 값입니다.
| 깨끗한 원본에 건 블러 | Canny(50, 150) 경계 칸 수 | 비고 |
|---|---|---|
| 없음 | 754 | 너트와 와셔의 테두리가 다 남는다 |
| 5×5 | 762 | 거의 그대로 |
| 9×9 | 741 | 거의 그대로 |
| 15×15 | 110 | 경계가 대부분 사라진다 |
잡음 낀 그림을 블러로 고친 뒤 원본과의 MAE 는 5×5 가 4.89, 15×15 가 3.34 로 15×15 가 더 원본에 가깝게 나옵니다. 그러나 위 표처럼 15×15 는 경계를 대부분 지웁니다. MAE 는 넓은 바탕이 원본과 비슷해진 것을 높게 치고, 작은 물체의 모서리가 사라진 것은 거의 따지지 않기 때문입니다. 다만 실습 5에서 잡음 판에 블러 15×15 를 건 결과는 F1 1.0 으로, 이 장의 부품에서는 점수가 떨어지지 않았습니다. 볼트, 너트, 와셔는 크기와 생김새가 크게 달라 테두리가 흐려져도 가릴 수 있었던 것으로 봅니다. 크기가 비슷한 물체나 더 작은 물체에서는 같은 블러가 해가 될 수 있습니다.
import cv2
import numpy as np
img = cv2.imread("ch17_raw/part_022.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
for k in (5, 9, 15):
blurred = cv2.GaussianBlur(gray, (k, k), 0) # 창 크기 k×k, 표준편차는 창 크기에 맞춰 자동
edges = cv2.Canny(blurred, 50, 150) # 11차시의 Canny
print(f"블러 {k}x{k}: 경계 칸 {int((edges > 0).sum())}개")
print("블러 없음: 경계 칸", int((cv2.Canny(gray, 50, 150) > 0).sum()), "개")
# 잡음 낀 그림을 블러로 고친 뒤 원본과의 MAE(6차시): 작을수록 원본에 가깝다
rng = np.random.default_rng(1801)
noisy = np.clip(img.astype(np.float64) + rng.normal(0, 20, img.shape), 0, 255).astype(np.uint8)
for k in (5, 15):
fixed = cv2.GaussianBlur(noisy, (k, k), 0)
print(f"블러 {k}x{k} 뒤 MAE:", round(float(cv2.absdiff(fixed, img).mean()), 2))주의할 점
- 손질의 세기는 "사진이 보기 좋은가"가 아니라 "모델의 점수가 오르는가"로 정합니다. 실습 5에서 블러 15×15 는 경계 칸을 754 에서 110 으로 줄이는 세기인데도 점수는 떨어지지 않았습니다. 데이터가 바뀌면 결과도 바뀌므로 그때마다 점수로 확인합니다.
- 이 장의 부품은 작습니다(너트가 가로세로 20칸 남짓). 물체가 작을수록 같은 블러에도 모양이 더 많이 뭉개집니다.