1카메라와 조명 시스템

비전 AI의 성능은 하드웨어에서 시작됩니다. 카메라와 조명 선택이 결함 검출 성능의 80%를 좌우한다고 해도 과언이 아닙니다.

카메라 유형별 비교:

유형특징적용 분야해상도
에어리어 스캔2D 센서, 순간 촬영정지 검사, 로봇 가이드1-60MP
라인 스캔1D 센서, 연속 이동 촬영웹 검사, 컨베이어2K-16K
3D 카메라깊이 정보 포함덴트, 갭/단차 측정1-5MP
열화상온도 분포 영상발열 이상, 용접 품질320×240~640×480
해상도 계산 가이드
필요 해상도 계산
최소 결함 크기: 0.1mm
FOV (Field of View): 100mm x 100mm
결함당 최소 픽셀: 3-5 픽셀
필요 해상도 = FOV / (결함 크기 / 픽셀 수)
= 100mm / (0.1mm / 5 pixels)
= 5000 pixels
5MP 카메라 (2448 x 2048) 이상 필요
조명 선택 가이드
스크래치, 미세 흠 → 로우 앵글 (측면 조명)
먼지, 이물질 → 백라이트 (투과 조명)
균일한 표면 → 돔 라이트 (확산 조명)
3D 형상 → 구조광 (패턴 조명)
반사 표면 → 편광 필터 + 돔 라이트

2이미지 전처리 파이프라인

원본 이미지를 AI 모델에 입력하기 전에 품질을 개선하고 정규화하는 과정입니다.

import cv2 import numpy as np from typing import Tuple class ImagePreprocessor: """제조 비전 이미지 전처리""" def __init__(self, target_size: Tuple[int, int] = (224, 224)): self.target_size = target_size def preprocess(self, image: np.ndarray) -> np.ndarray: """전처리 파이프라인 실행""" # 1. 노이즈 제거 image = cv2.GaussianBlur(image, (3, 3), 0) # 2. 히스토그램 평활화 (대비 개선) if len(image.shape) == 3: lab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB) lab[:,:,0] = cv2.createCLAHE(clipLimit=2.0).apply(lab[:,:,0]) image = cv2.cvtColor(lab, cv2.COLOR_LAB2BGR) # 3. 정규화 image = image.astype(np.float32) / 255.0 # 4. 리사이즈 image = cv2.resize(image, self.target_size) return image def align_roi(self, image: np.ndarray, template: np.ndarray) -> np.ndarray: """템플릿 매칭으로 ROI 정렬""" result = cv2.matchTemplate(image, template, cv2.TM_CCOEFF_NORMED) _, _, _, max_loc = cv2.minMaxLoc(result) h, w = template.shape[:2] roi = image[max_loc[1]:max_loc[1]+h, max_loc[0]:max_loc[0]+w] return roi

1 노이즈 제거

Gaussian Blur, Median Filter로 센서 노이즈 제거. 에지 보존 필터(Bilateral) 선택적 사용

2 대비 개선

CLAHE(적응 히스토그램 평활화)로 조명 불균일 보정. 결함 가시성 향상

3 ROI 추출

검사 대상 영역만 잘라내기. 템플릿 매칭 또는 딥러닝 검출기 활용

4 정규화

픽셀값 0-1 스케일링. ImageNet 평균/표준편차로 정규화 (Transfer Learning시)

3데이터 증강 (Augmentation)

학습 데이터를 인위적으로 늘려 모델의 일반화 성능을 향상시킵니다. 제조 환경의 변동(조명, 위치, 각도)을 시뮬레이션합니다.

import albumentations as A from albumentations.pytorch import ToTensorV2 # 학습용 증강 (강한 증강) train_transform = A.Compose([ A.Resize(224, 224), A.HorizontalFlip(p=0.5), A.VerticalFlip(p=0.5), A.RandomRotate90(p=0.5), A.ShiftScaleRotate(shift_limit=0.1, scale_limit=0.2, rotate_limit=45, p=0.5), # 조명 변동 시뮬레이션 A.RandomBrightnessContrast(brightness_limit=0.3, contrast_limit=0.3, p=0.5), A.RandomGamma(gamma_limit=(80, 120), p=0.3), A.GaussNoise(var_limit=(10, 50), p=0.3), # 블러 (초점 불량 시뮬레이션) A.OneOf([ A.MotionBlur(blur_limit=5), A.GaussianBlur(blur_limit=5), ], p=0.3), A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ToTensorV2(), ]) # 검증/추론용 (증강 없음) val_transform = A.Compose([ A.Resize(224, 224), A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ToTensorV2(), ])

증강 주의사항: 결함의 특성이 손상되지 않도록 증강을 설계해야 합니다. 예: 스크래치의 방향이 중요하면 90도 회전은 피함. 색상 결함 검사에서는 색상 변환 증강 제외.

4라벨링 도구와 전략

고품질 라벨링은 AI 모델 성능의 핵심입니다. 제조 결함 라벨링에 적합한 도구와 전략을 소개합니다.

주요 라벨링 도구:

도구유형특징라이선스
CVAT웹 기반다양한 어노테이션, 팀 협업, AI 보조오픈소스
Label Studio웹 기반ML 통합, 다양한 데이터 타입오픈소스
RoboflowSaaS자동 증강, 데이터셋 버전 관리상용
LabelboxSaaS엔터프라이즈급, 워크플로우 관리상용
라벨링 가이드라인 예시 (결함 분류)
결함 클래스 정의
OK: 정상 제품, 결함 없음
Scratch: 표면 긁힘, 길이 0.5mm 이상
세부: Light Scratch, Deep Scratch
Dent: 표면 찍힘, 면적 1mm² 이상
Stain: 오염, 변색, 이물질
세부: Oil Stain, Water Mark, Foreign Material
Crack: 균열, 깨짐
1. 경계 사례 기준
Scratch 길이 0.3~0.5mm → 'Light Scratch' 또는 'OK'
여러 결함 중첩 → 가장 심각한 결함으로 분류
2. 품질 검증
전문가 2인 이상 교차 검증
불일치율 10% 이상 → 가이드라인 수정
3. 주기적 리뷰
월 1회 라벨링 일관성 감사
신규 결함 유형 발견 시 클래스 추가

5데이터셋 구조와 관리

체계적인 데이터셋 관리는 모델 재현성과 버전 관리에 필수적입니다.

권장 디렉토리 구조
defect_dataset/
raw/ # 원본 이미지
2024-01-15/ (line_A/, line_B/)
2024-01-16/
processed/ # 전처리된 이미지
train/ (OK/, Scratch/, Dent/, Stain/, Crack/)
val/, test/
annotations/ # 라벨 데이터
train.json, val.json (COCO 포맷)
metadata/
class_mapping.json, split_info.json, statistics.json
README.md # 데이터셋 설명서
메타데이터 예시 (statistics.json)
{
  "version": "1.2.0",
  "created_at": "2024-01-20",
  "total_samples": 15000,
  "class_distribution": {
    "OK": 12000,
    "Scratch": 1500,
    "Dent": 800,
    "Stain": 500,
    "Crack": 200
  },
  "split_ratio": {"train": 0.7, "val": 0.15, "test": 0.15}
}

버전 관리: DVC(Data Version Control) 또는 MLflow를 사용하여 데이터셋 버전을 추적하세요. 모델 학습 시 어떤 버전의 데이터로 학습했는지 기록이 필수입니다.

6품질 검증과 데이터 정제

학습 전 데이터 품질을 검증하고 문제가 있는 샘플을 정제하는 과정입니다.

import os import hashlib from PIL import Image from collections import Counter class DatasetValidator: """데이터셋 품질 검증""" def validate(self, data_dir: str) -> dict: """데이터셋 검증 실행""" issues = { 'corrupted': [], 'duplicates': [], 'size_outliers': [], 'class_imbalance': None } hashes = {} sizes = [] labels = [] for root, dirs, files in os.walk(data_dir): for file in files: if not file.lower().endswith(('.jpg', '.png', '.bmp')): continue path = os.path.join(root, file) label = os.path.basename(root) labels.append(label) # 1. 손상된 이미지 검사 try: img = Image.open(path) img.verify() img = Image.open(path) sizes.append(img.size) except: issues['corrupted'].append(path) continue # 2. 중복 이미지 검사 with open(path, 'rb') as f: file_hash = hashlib.md5(f.read()).hexdigest() if file_hash in hashes: issues['duplicates'].append((path, hashes[file_hash])) else: hashes[file_hash] = path # 3. 크기 이상치 검사 avg_size = np.mean([s[0]*s[1] for s in sizes]) for i, size in enumerate(sizes): if size[0]*size[1] < avg_size * 0.5: issues['size_outliers'].append(i) # 4. 클래스 불균형 검사 class_counts = Counter(labels) issues['class_imbalance'] = dict(class_counts) return issues # 사용 예시 validator = DatasetValidator() issues = validator.validate('defect_dataset/processed/train') print(f"손상 이미지: {len(issues['corrupted'])}개") print(f"중복 이미지: {len(issues['duplicates'])}개") print(f"클래스 분포: {issues['class_imbalance']}")