19장. Vision 데이터 파이프라인
기록과 재현
요리 대회에 나가는 사람은 연습할 때 조리법 공책을 씁니다. 재료의 양, 불 세기, 시간, 그날의 맛을 적어 두어야 잘된 날의 맛을 다시 낼 수 있습니다. 파이프라인도 같습니다. 어떤 설정으로 돌렸는지, 그림마다 어떻게 됐는지, 각 단계가 얼마나 걸렸는지 적어 두어야 결과를 다시 만들고 고칠 곳을 찾습니다.
그림의 네 걸음이 다시 만들 수 있는 파이프라인의 조건입니다. CONFIG 를 JSON 파일로 저장하고, 무작위로 고르는 곳은 씨앗을 고정하고(16장), 그림마다 단계와 결과와 이유를 처리 기록 csv 로 남기고(17장), 단계마다 걸린 시간을 잽니다. 여기서 조리법 공책의 재료 양이 CONFIG, 그날의 맛이 처리 기록, 조리 시간이 단계별 시간입니다. 비유와 다른 점은, 요리는 같은 조리법이라도 맛이 조금씩 다르지만, 이 장의 OpenCV 단계는 같은 입력과 설정이면 칸 하나까지 같은 결과가 나온다는 것입니다.
무엇을 남기나
| 남길 것 | 파일 | 쓰임 |
|---|---|---|
| 설정 | out_ch19_config.json | 어떤 기준으로 돌렸는지 |
| 처리 기록 | out_ch19_pipeline_log.csv | 그림마다 마지막 단계, 결과, 이유 |
| 보고서 | out_ch19_report.csv, out_ch19_report.png | 결과 요약 |
| 단계별 시간 | 출력에 찍기 | 병목 찾기. 컴퓨터마다 다르다 |
짧은 예시
import hashlib
import time
import cv2
import numpy as np
def prep(img):
"""다듬기 한 가지: 감마 0.7."""
lut = np.array([((i / 255) ** 0.7) * 255 for i in range(256)]).round().astype(np.uint8)
return cv2.LUT(img, lut)
img = cv2.imread("ch19_incoming/belt_004.png")
# 같은 입력을 두 번 다듬어 결과 배열의 MD5 지문(16차시)을 견준다
first = hashlib.md5(prep(img).tobytes()).hexdigest()
second = hashlib.md5(prep(img).tobytes()).hexdigest()
print("같은 결과:", first == second) # 결과: 같은 결과: True
# 씨앗을 고정하면 무작위로 고른 그림도 언제나 같다
names = [f"belt_{k:03d}.png" for k in range(1, 21)]
pick1 = np.random.default_rng(19).choice(names, 3, replace=False).tolist()
pick2 = np.random.default_rng(19).choice(names, 3, replace=False).tolist()
print("같은 고르기:", pick1 == pick2) # 결과: 같은 고르기: True
# 걸린 시간: 컴퓨터마다, 돌릴 때마다 조금씩 다르다
start = time.perf_counter()
for _ in range(100):
prep(img)
print("감마 100번(초):", round(time.perf_counter() - start, 3))tobytes() 는 그림 배열의 칸 값을 바이트로 펴서, 파일 없이도 MD5 지문을 구하게 해 줍니다. 마지막 줄의 시간은 컴퓨터마다 다르므로 원고에 숫자를 적지 않았습니다. 시간은 "어느 단계가 몇 배 오래 걸리는가"로 견줍니다.
주의할 점
- 이 장의 OpenCV 단계는 같은 결과를 내지만, YOLO 추론은 컴퓨터(CPU 종류, 패키지 판)에 따라 신뢰도의 끝자리가 조금 다를 수 있습니다. 보고서에 실행 환경(파이썬, ultralytics 판)을 함께 적습니다.
- 기록 csv 는 원본 폴더 밖(
data/의out_파일)에 저장합니다. 입고 폴더 안에 쓰면 다음 수집 단계에서 그 파일까지 모으게 됩니다.