OpenCV 비전 실무18장 · OpenCV 전처리와 YOLO 연계9 / 21← 이전목차다음 →MetaContents

18장. OpenCV 전처리와 YOLO 연계

전처리가 결과에 주는 영향

낮에 운전 연습만 한 사람이 처음으로 밤길을 달리면 표지판을 늦게 알아봅니다. 운전 실력은 그대로인데 보이는 모습이 연습 때와 달라졌기 때문입니다. 모델도 같습니다. 17장의 학습용 사진 45장은 대부분 보통 밝기이고(7장은 어둡게 그렸습니다), 잡음 낀 사진은 없습니다. 실제로 쓸 때 학습 때 보지 못한 모습의 사진이 들어오면 점수가 떨어집니다. 이것을 조건 차이라고 합니다.

학습 조건, 쓸 때 조건, 성능 하락, 손질해 넣기의 네 단계를 이은 흐름도

그림의 네 단계가 조건 차이가 생기고 풀리는 흐름입니다. 학습 때와 다른 사진이 들어오면 놓친 것과 헛것이 늘어나고, 그 사진을 OpenCV 로 손질해 학습 때 본 사진과 비슷하게 맞춰 넣으면 점수가 되살아날 수 있습니다. 여기서 낮의 연습이 학습 조건, 밤길이 쓸 때 조건, 전조등을 켜는 일이 OpenCV 손질입니다.

검증용 그림 하나를 원본, 어둡게, 잡음, 어둡게와 잡음을 함께 넣은 네 조건으로 만든 그림

검증용 그림 part_022.png 를 네 조건으로 만든 것입니다. 어둡게는 모든 칸을 0.3배 해서 평균 밝기가 75.5 에서 21.5 로 내려갔고, 잡음은 6장의 꼴로 표준편차 20 의 잡음을 씨앗 1801 로 더했습니다. 실습 5와 프로젝트에서 이 네 조건을 검증용 사진 11장 모두에 만들어 점수를 잽니다.

결과는 예상과 달랐습니다. 학습한 모델은 어둡게 한 사진에서 점수가 전혀 떨어지지 않았고(F1 1.0), 잡음 낀 사진에서만 F1 이 0.981 에서 0.815 로 떨어졌습니다(실습 5). 17장 실습 1에서 평균 밝기 50 미만으로 고른 어두운 그림 9장 가운데 7장이 학습용에 들어가 있어, 모델이 어두운 모습은 이미 배웠기 때문으로 봅니다. 잡음 낀 사진은 학습 때 한 장도 보지 못했습니다. 조건 차이는 "사진이 나빠 보이는가"가 아니라 "학습 때 본 적이 있는가"로 생깁니다.

조건과 손질의 짝

나쁜 조건만드는 법고치는 손질배운 곳
어둡다모든 칸에 0.3 을 곱한다감마 0.5 로 어두운 쪽을 올린다, CLAHE 로 대비를 키운다5장
잡음이 꼈다표준편차 20 의 정규분포 잡음을 더한다Gaussian 블러, Median 블러6장, 7장
어둡고 잡음도 꼈다어둡게 한 뒤 잡음을 더한다잡음을 먼저 줄이고 밝기를 올린다5장부터 7장까지

어둡고 잡음 낀 사진은 손질의 차례가 중요합니다. 밝기를 먼저 올리면 잡음도 함께 커집니다. 감마 0.5 의 조회표에서 밝기 16 은 64 로, 25 는 80 으로 바뀌어, 9 이던 차이가 16 으로 벌어집니다. 그래서 잡음을 먼저 줄인 뒤 밝기를 올립니다. 프로젝트에서 잡음 낀 사진에 밝기만 올리면 F1 이 0.873 에서 0.737 로 오히려 떨어졌고, 잡음을 먼저 줄인 뒤 올리면 0.920 으로 올랐습니다.

Python
import cv2
import numpy as np

img = cv2.imread("ch17_raw/part_022.png")
def mean_gray(im):
    return round(float(cv2.cvtColor(im, cv2.COLOR_BGR2GRAY).mean()), 1)

# 어둡게: 0.3 배. 소수로 바꿔 곱한 뒤 0~255 로 자르고 uint8 로 되돌린다
dark = np.clip(img.astype(np.float64) * 0.3, 0, 255).astype(np.uint8)

# 감마 0.5 조회표로 어두운 쪽을 올린다(5차시)
lut = np.array([((i / 255) ** 0.5) * 255 for i in range(256)]).round().astype(np.uint8)
bright = cv2.LUT(dark, lut)

# CLAHE 는 밝기 채널(YCrCb 의 Y)에만 건다(5차시)
ycc = cv2.cvtColor(dark, cv2.COLOR_BGR2YCrCb)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
ycc[:, :, 0] = clahe.apply(ycc[:, :, 0])
clahe_img = cv2.cvtColor(ycc, cv2.COLOR_YCrCb2BGR)

print("원본", mean_gray(img), "· 어둡게", mean_gray(dark), "· 감마", mean_gray(bright), "· CLAHE", mean_gray(clahe_img))
print("감마 조회표에서 16, 25 →", int(lut[16]), int(lut[25]))

교안 PC 에서 평균 밝기는 원본 75.5, 어둡게 21.5, 감마 74.0, CLAHE 26.1 입니다. 감마 0.5 는 어둡게 한 그림을 원본과 거의 같은 밝기로 되돌립니다. CLAHE 는 평균을 조금만 올리고, 대신 칸마다 명암 차이를 키웁니다(흑백 표준편차 5.6 → 9.7). 실습 5에서는 두 손질 모두 어두운 판의 F1 을 1.0 그대로 지켰습니다. 이 모델은 어두운 사진을 이미 잘 찾으므로, 밝기 손질이 점수를 올릴 여지가 없었습니다.

주의할 점

  • 1장에서 "학습 때 한 전처리는 쓸 때도 똑같이" 라고 했습니다. 이 장의 모델은 손질하지 않은 사진으로 배웠으므로, 손질은 학습 때 본 사진과 비슷하게 되돌리는 쪽으로 합니다. 학습 때 보지 못한 모습으로 바꾸면 오히려 떨어질 수 있습니다.
  • 손질은 문제가 있다고 점수로 확인한 뒤에 겁니다. 이 장의 모델은 원본에 감마 0.5 를 걸어도(평균 밝기 63.8 → 125.7) 점수가 떨어지지 않았지만(F1 0.981 → 1.000, 프로젝트), 이것은 이 데이터에서 잰 결과일 뿐입니다. 손질이 늘 해가 없다는 뜻은 아니므로, 걸기 전과 뒤의 점수를 재어 견줍니다.
← 이전 절18장 · 맞혔는지 재기다음 절 →18장 · 지나친 전처리의 함정