Contrast enhancement
Peponi │ 3/24/2025 │ 8m
Contrast enhancement
Peponi
1. Introduction
이미지의 대비 (명암비) 는 밝은 부분과 어두운 부분의 차이로, 대비가 높을 수록 이미지의 세부 사항이 더 뚜렷하게 나타날 수 있다. 주로 histogram을 통해 픽셀 값 분포를 분석하며 이미지가 전체적으로 얼마나 밝은지, 대비가 어느 정도인지 등을 평가한다.
Normalization, equalization은 이미지의 대비를 개선할 수 있는 방법으로, 각각 다음과 같은 특징을 가진다.
- Normalization
- 이미지의 픽셀 값을 특정 범위로 조정한다. 보통 0 ~ 1, 0 ~ 255 사이로 조정한다.
- 이미지의 전체적인 대비가 향상되며 픽셀 값의 분포를 넓혀 세부 사항을 더 잘 드러나게 한다.
- 정규화된 히스토그램은 원본 히스토그램의 형태를 유지한다.
- Equalization
- 이미지의 히스토그램을 균등하게 분포시킨다. 저조도 또는 저대비 이미지에 효과적이다.
- 이미지 처리 과정에서 대비가 극대화되어 눈에 띄지 않는 세부 사항을 드러내는 데 유리하다.
- 정규화된 히스토그램은 원본 히스토그램과는 다른 형태를 가질 수 있다.
이 문서에서는 histogram, normalization, equalization과 함께 equalization의 문제를 보완할 수 있는 CLAHE (Contrast Limited Adaptive Histogram Equalization) 를 소개한다.
실습에 사용할 이미지는 다음과 같다.

2. Histogram
이미지 프로세싱에서는 픽셀 값 (밝기 또는 색상) 분포를 주로 histogram으로 표현한다. 일반적으로 X축은 밝기 또는 색상, Y축은 빈도로 표현된다. 여기서는 그레이스케일 이미지를 사용해 히스토그램을 그리는 예시를 보여준다.


private void GrayscaleHistogram(Mat image)
{
// Grayscale 변환
using var grayscale = image.CvtColor(ColorConversionCodes.BGR2GRAY);
using var histogram = GetHistogram(grayscale);
}
private Mat GetHistogram(Mat grayscale)
{
using var histogram = new Mat();
// Calculate histogram
// Cv2.CalcHist(image, channel, mask, histogram, dims, bins, range)
Cv2.CalcHist([grayscale], [0], null, histogram, 1, [256], [[0, 256]]);
Mat histogramImage = Mat.Zeros(256, 256, MatType.CV_8UC3);
// Normalize histogram's Y axis for display
histogram.MinMaxLoc(out double min, out double max);
if (max != 0)
{
Cv2.Multiply(histogram, 256 / max, histogram);
}
// Draw histogram
for (int i = 0; i < 256; i++)
{
histogramImage.Rectangle(new OpenCvSharp.Point(i, histogramImage.Rows - (int)histogram.Get<float>(i)), new((i + 1), histogramImage.Rows), Scalar.White);
}
return histogramImage;
}
3. Normalization




private void NormalizeHistogram(Mat image)
{
// 도수 분포에 최대, 최소값이 있는 경우에는 normalize 잘 수행되지 않음
// Grayscale 변환
using var grayscale = image.CvtColor(ColorConversionCodes.BGR2GRAY);
// Normalize
using var normalized = grayscale.Normalize(0, 255, NormTypes.MinMax);
using var normalizedHistogram = GetHistogram(normalized);
}
3.1. Color image
Color image에 normalization을 적용하는 경우 색상 공간을 HSV color로 변경, 밝기 채널 (Value) 에 대해 normalization 수행 후 다시 합성한다.



private void NormalizeColorHistogram(Mat image)
{
using var hsvImage = image.CvtColor(ColorConversionCodes.BGR2HSV);
// H, S, V 순으로 분리
var split = hsvImage.Split();
// Normalize
using var valueChannel = split[2].Normalize(0, 255, NormTypes.MinMax);
// Color image로 다시 합성
using var merge = new Mat();
Cv2.Merge([split[0], split[1], valueChannel], merge);
using var normalized = merge.CvtColor(ColorConversionCodes.HSV2BGR);
}
4. Equalization




private void EqualizeHistogram(Mat image)
{
// Grayscale 변환
using var grayscale = image.CvtColor(ColorConversionCodes.BGR2GRAY);
// 전역 histogram 평준화
// Mat.EqualizeHist()
using var equalized = grayscale.EqualizeHist();
using var equalizedHistogram = GetHistogram(equalized);
}
4.1. Color image
Color image에 equalization을 적용하는 경우 색상 공간을 HSV color로 변경, 밝기 채널 (Value) 에 대해 equalization 수행 후 다시 합성한다.



private void EqualizeColorHistogram(Mat image)
{
using var hsvImage = image.CvtColor(ColorConversionCodes.BGR2HSV);
// H, S, V 순으로 분리
var split = hsvImage.Split();
// 밝기 채널에 대해 전역 histogram 평준화
using var valueChannel = split[2].EqualizeHist();
// Color image로 다시 합성
using var merge = new Mat();
Cv2.Merge([split[0], split[1], valueChannel], merge);
using var equalized = merge.CvtColor(ColorConversionCodes.HSV2BGR);
}
5. CLAHE
앞서 CLAHE는 equalization의 문제를 보완할 수 있다 기술하였다. 앞의 예제와 같이, Equalization은 이미지 전역의 대비를 증가시키지만 지역적으로 과도한 대비가 발생하는 경우가 있다. 이를 해결하기 위해 CLAHE는 지역적으로 equalization을 수행하며, 각 커널의 대비 한계가 존재하여 이를 초과하는 경우 다른 픽셀로 분배된다.




private void CLAHEHistogram(Mat image, double clipLimit = 4, OpenCvSharp.Size? gridSize = null)
{
// Grayscale 변환
using var grayscale = image.CvtColor(ColorConversionCodes.BGR2GRAY);
using var claheEqualized = new Mat();
// 지역 histogram 평준화
using var clahe = Cv2.CreateCLAHE(clipLimit, gridSize);
clahe.Apply(grayscale, claheEqualized);
using var claheHistogram = GetHistogram(claheEqualized);
}
5.1. Color image
Color image에 CLAHE를 적용하는 경우 색상 공간을 HSV color로 변경, 밝기 채널 (Value) 에 대해 CLAHE 수행 후 다시 합성한다.



private void CLAHEColorHistogram(Mat image, double clipLimit = 4, OpenCvSharp.Size? gridSize = null)
{
using var hsvImage = image.CvtColor(ColorConversionCodes.BGR2HSV);
// H, S, V 순으로 분리
var split = hsvImage.Split();
using var valueChannel = new Mat();
// 밝기 채널에 대해 지역 histogram 평준화
using var clahe = Cv2.CreateCLAHE(clipLimit, gridSize);
clahe.Apply(split[2], valueChannel);
// Color image로 합성
using var merge = new Mat();
Cv2.Merge([split[0], split[1], valueChannel], merge);
using var claheEqualized = merge.CvtColor(ColorConversionCodes.HSV2BGR);
}