WPF OpenCV 프로젝트 #20: CLAHE (Contrast Limiting Adaptive Histogram Equalization)

CLAHE 알고리즘을 WPF OpenCV 프로젝트에 구현하겠습니다. 지난 포스팅(#19)에서는 히스토그램 평활화(Equalize)를 통해 영상의 명암비를 전체적으로 높이는 방법을 다뤘습니다.

확실히 이미지가 밝아지고 선명해지긴 했지만, 혹시 뭔가 “과하다”는 느낌 못 받으셨나요? 너무 어두운 배경에 있던 노이즈(Noise)까지 덩달아 선명해지거나, 밝은 부분이 하얗게 날아가 버리는 현상 말이죠.

오늘은 바로 그 문제를 해결해 주는 ‘업그레이드된 평활화’, CLAHE (Contrast Limiting Adaptive Histogram Equalization)에 대해 간략하게 정리하고, 구현해 보겠습니다.

CLAHE vs Equalize

지난 포스팅(#19)에 쓴 Cv2.EqualizeHist전역(Global) 방식입니다. 이미지 전체를 한 통으로 보고, “어두운 건 밝게, 밝은 건 더 밝게!” 하며 일괄적으로 적용해 버립니다.

이러다 보니 두 가지 문제가 생깁니다.

  1. Detail 손실: 작은 영역마다 밝기 특성이 다른데, 모조리 무시하고 전체 평균으로 맞춰버립니다.
  2. Noise 증폭: 배경처럼 색이 균일한 곳(히스토그램이 뾰족한 곳)을 강제로 펴다 보니, 숨어 있던 자글자글한 노이즈가 눈에 띄게 올라옵니다.

CLAHE (Contrast Limiting Adaptive Histogram Equalization)

CLAHE는 이 문제를 아주 똑똑하게 해결합니다.

  1. 적응형(Adaptive) – 구역 나누기: 이미지를 작은 격자(Tile, 보통 8×8)로 잘게 쪼갭니다. 그리고 각 구역별로 평활화를 따로따로 진행합니다. (Adaptive Threshold와 비슷하죠?)
  2. 대비 제한(Contrast Limiting) – 자르기: 특정 구역에서 히스토그램의 빈도수가 너무 높게 치솟으면(즉, 너무 밋밋한 영역이면), 지정된 한계선(Clip Limit) 위로 튀어나온 부분을 싹둑 잘라냅니다. 그리고 자른 픽셀들을 주변에 골고루 나눠줍니다. 이렇게 하면 과도한 대비 증가(노이즈)를 막을 수 있습니다.
  3. 보간(Interpolation): 구역 별로 따로 놀면 바둑판처럼 경계선이 생기겠죠? 이중 선형 보간법(Bilinear Interpolation)으로 경계를 부드럽게 살살 문질러줍니다.

구현 요약

CLAHEEqualize보다 설정할 게 조금 더 있습니다.

  1. AlgorithmParameters.cs: ClaheParams 클래스 추가. (ClipLimit, TileGridSize)
  2. MainViewModel.cs: 메뉴 등록 및 파라미터 연결.
  3. MainWindow.xaml: 슬라이더 UI 추가.
  4. OpenCVService.cs: Cv2.CreateCLAHE 및 적용하고, 결과에 대한 히스토그램을 계산.

Step 1: Model (AlgorithmParameters)

AlgorithmParameters.cs 파일에 ClaheParams 클래스를 생성하고 CLAHE 설정 값을 정의합니다.

  • ClipLimit: 대비를 얼마나 제한할지 결정합니다. (값이 클수록 Equalize에 가까워집니다.)
  • TileGridSize: 이미지를 몇 개의 타일로 쪼갤지 결정합니다.

Step 2: ViewModel

MainViewModel.cs코드에는 생성자 함수에 CLAHE 메뉴를 추가하고 알고리즘 선택 시 알고리즘 선택 시 ClaheParams 객체를 생성 후 팝업 로직을 연결합니다.

MainViewModel.cs 파일 내에 ApplyAlgorithm () 함수도 아래와 같이 수정해 주세요. 별다른건 아니고 CLAHE 알고리즘 처리 후 히스토그램 그래프를 그리기 위해 필요한 부분입니다. (잘 알죠?)

Step 3: UI(View)

MainWindow.xaml코드에 ClaheParams에서 사용할 UI Element들(ClipLimitTileGridSize)을 아래와 같이 추가합니다.

Step 4: OpenCVService

OpenCVService.cs입니다. CLAHECv2.EqualizeHist처럼 함수 한 번 호출이 아니라, 객체를 생성(CreateCLAHE)하고 적용(Apply)하는 방식입니다.

실행 및 결과 비교: Equalize vs CLAHE

자, 이제 프로젝트 빌드 후 실행해서 차이를 확인해 볼 시간입니다. 같은 이미지를 놓고 비교해 보세요.

먼저 아래 이미지는 로딩 한 원본 이미지와 원본 이미지의 히스토그램을 보여줍니다.

아래의 이미지는 위 이미지를 이전 포스팅(#19)의 Equalize를 적용한 이미지와 히스토그램 그래프입니다.

이제 이번에 구현한 CLAHE 를 적용한 이미지를 봐야겠죠.

분석 결과:

  • Equalize: 전체적으로 밝아졌지만, 기둥 등 원래 밝았던 부분이 하얗게 날아가거나 벽면의 질감이 부자연스럽게 거칠어 보입니다.
  • CLAHE: 훨씬 자연스럽습니다. 어두운 곳의 디테일은 살아나면서도, 밝은 곳의 질감은 유지되고 있습니다. 히스토그램을 봐도 Equalize처럼 한쪽 벽에 붙어버리는(Clipping) 현상 없이 비교적 고르게 분포된 것을 볼 수 있습니다.

항상 하던 이야기 이지만, 세상에 공짜는 없습니다. CLAHEEqualize보다 연산량이 많아 속도는 조금 더 느립니다. 하지만 품질이 훨씬 좋기 때문에 의료 영상(X-ray)이나 정밀 검사에서는 거의 필수적으로 사용됩니다.

다음 포스팅에서는 이미지의 픽셀 값이 아니라, 위치와 모양을 바꾸는 기하학적 변환(Geometry Transform – 이동, 확대/축소, 회전)에 대해 알아보겠습니다.

참조 자료

[Post #19] 히스토그램 평활화: [WPF OpenCV Project #19] – Equalize 구현 및 정규화와의 차이
CLAHE: OpenCV Docs – CLAHE Class – 타일 그리드 및 클립 리밋 설명
Adaptive Histogram Equalization: Wikipedia – AHE – CLAHE의 수학적 원리와 보간법 설명

댓글 남기기