V2 로직(OpenCV Laplacian Variance) - 100-hours-a-week/5-yeosa-wiki GitHub Wiki

1. 기존 로직의 문제점

a. 기존 로직 요약

  • CLIP 프롬프트 기반 임베딩을 사용하여 sharp, good 점수를 추출
  • 아래 두 기준을 적용하여 통과 여부 판단:
    • sharp ≥ 0.4880
    • combined = good × 0.25 + sharp × 0.75 ≥ 0.490

b. 문제점

  • Recall이 27.1%로 매우 낮음 (정상 이미지도 누락)
    • 예: motion_blurred 중 27.1%가 neither로 분류됨 (통과 실패)
    • 즉, 실제로 통과 가능한 이미지도 걸러짐 (False Negative)

2. 개선된 방식: CLIP(기존) + Laplacian

a. Laplacian variance란?

가. 정의

  • 이미지의 선명도(blur 여부) 를 측정하기 위한 객관적인 수치 지표
  • OpenCV의 Laplacian() 함수는 이미지에서 경계(Edge) 를 강조하는 필터
  • 이 필터를 적용한 결과의 분산(Variance) 을 계산하면,
    • 값이 클수록 → 경계가 뚜렷함 → 선명한 이미지

    • 값이 작을수록 → 경계가 흐림 → 흐릿한 이미지

      laplacian_var = cv2.Laplacian(gray_image, cv2.CV_64F).var()
      

나. 사용 예

  • 일반적으로 var < 80이면 흐릿한 이미지로 간주

b. 고려 사항

가. Grayscale 변환

항목 설명
Laplacian은 채널 독립 필터 컬러 이미지(BGR)는 각 채널마다 경계값이 다르기 때문에, Laplacian을 채널 단위로 적용하면 불안정하고 해석이 어려움
단일 경계 추출을 위해 회색조 변환을 통해 모든 색상 정보를 하나의 밝기 스케일로 통합하면, 경계(Edge) 추출에 더욱 일관된 결과를 얻을 수 있음
노이즈 제거 효과 불필요한 색상 차이로 인한 잡음을 줄이고, 윤곽선 중심의 분석이 가능해짐

→ 즉, Laplacian을 정확하고 안정적으로 적용하기 위해선 grayscale 변환은 사실상 필수

나. 이미지 Resize의 필요성과 전략

  • 고해상도 이미지와 저해상도 이미지는 Laplacian 분산값이 크게 차이날 수 있음

    • 같은 정도의 blur라도, 고해상도는 더 높은 분산을 가질 수 있음 → 비교 불가능
  • Resize 전략

    def resize_for_laplacian(image: np.ndarray, target_long_side: int = 300):
        h, w = image.shape
        scale = target_long_side / max(h, w)
        new_size = (int(w * scale), int(h * scale))
        return cv2.resize(image, new_size, interpolation=cv2.INTER_AREA)
    
    • target_long_side=300 : 긴 변 기준으로 크기 정규화 → 전체 이미지 크기를 균일하게 맞춤
    • cv2.INTER_AREA : 이미지 축소 시 가장 보존력이 뛰어난 보간 방식 사용
    • (int(w * scale), int(h * scale)) : 세로/가로 비율을 유지
    • 테스트 결과
      • Threshold 50 기준

        Resize O Resize X
        Precision 1.0 0.86
        Recall 0.54 0.89
      • Threshold 100 기준

        Resize O Resize X
        Precision 0.99 0.77
        Recall 0.63 0.95

3. 개선 로직(CLIP + Laplacian 병합)

a. CLIP 기반 점수 평가 유지

  • 기존처럼 sharp, good 점수 기반으로 "both"가 아닌 이미지를 저품질로 판단

b. Laplacian Filter 추가

def laplacian_filter(image: np.ndarray, threshold=80.0) -> bool:
    resized = resize_for_laplacian(image)
    var = cv2.Laplacian(resized, cv2.CV_64F).var()
    return var < threshold  # threshold 미만이면 저품질
  • 이미지 자체의 선명도를 수학적으로 분석
    • 회색조 변환 → 리사이즈 → Laplacian variance 계산
  • var < 80이면 저품질로 판단

c. 두 방식 결과 병합

  • CLIP 결과 ∪ Laplacian 결과 → 둘 중 하나라도 저품질이면 제거
  • CLIP 임베딩이 없는 경우에도 Laplacian만으로 필터링 가능

4. 개선 효과

기존 방식 개선 방식(Threshold 80)
Precision 1.0 1.0
Recall 0.28 0.63