티스토리 뷰

반응형
[영상처리] Histogram Noramlize(정규화), Equalization(평탄화), CLAHE(opencv-python)

Normalization(정규화)

정의

영상에서 특정 부분에 몰려 있는 값을 전체 영역으로 골고루 분포하게 하도록 만드는 방법을 Normalization(정규화) 라고 한다.

적용 공식

IN=(IMin)newMaxnewMinMaxMin+newMinI_N = (I-Min) \dfrac{newMax-newMin}{Max-Min}+newMin

  • II: 노멀라이즈 이전 값
  • Min,MaxMin, Max: 노멀라이즈 이전 범위의 최소값, 최대값
  • newMin,newMaxnewMin, newMax: 노멀라이즈 이후 범위의 최소값, 최대값
  • INI_N: 노멀라이즈 이후 값

적용코드

opencv의 cv2.normalize() 함수를 이용하면 쉽게 구현할 수 있다. 파라미터로 끝에서 3개가 각각 alpha, beta, type_flag인데, normalize할 방법과 구간을 입력하면 된다. 아래 코드는 0~255로 minmax방식으로 normalize하는 방법이다.

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('imgs/abnormal.jpg', cv2.IMREAD_UNCHANGED)
img_norm = cv2.normalize(img, None, 0, 255, cv2.NORM_MINMAX)

cv2.imshow('img', img)
cv2.imshow('img_norm', img_norm)

cv2.waitKey(0)
cv2.destroyAllWindows()

hist = cv2.calcHist([img], [0], None, [256], [0, 255])
hist_norm = cv2.calcHist([img_norm], [0], None, [256], [0, 255])

for i, h in enumerate([hist, hist_norm]):
    plt.subplot(1,2,i+1)
    plt.plot(h)
plt.show()

결과영상

왼쪽의 영상에서 normalize를 시행한 결과, 오른쪽 영상처럼 훨씬 깔끔한 영상이 출력된다. 아래 히스토그램 그래프를 확인해보면 100~200 정도로 분포되어있던 픽셀들이 0~250으로 고루 분포된 것을 확인할 수 있다.

Equalization(평탄화)

정의

이미지의 히스토그램이 전체 영역에 골고루 분포가 되어 있을 때 좋은 이미지라고 할 수 있다. 아래 히스토그램을 보면 왼쪽 그래프에서 가운데에 분포가 집중되어 있는데, 이를 오른쪽 그래프처럼 만들어주는 작업을 Histogram Equalization이라고 한다. 노멀라이즈의 방법에서 한 곳에 집중된 영역으로부터 멀리 떨어진 값이 있을 경우에는 효과가 없는데, 그런 경우에 사용할 수 있다.

이퀄라이즈는 각각의 값이 전체 분포에 차지하는 비중에 따라 분포를 재분배하므로 명암 대비(contrast)를 개선하는데 효과적이다.

적용 공식

H(v)=round(cdf(v)cdfmin(MN)cdfmin(L1))H'(v)=round(\dfrac{cdf(v)-cdf_{min}}{(M*N)-cdf_{min}}*(L-1))

  • cdf(v)cdf(v): 히스토그램 누적 함수
  • cdfmincdf_{min}: 누적 최소 값, 1
  • MNM*N: 픽셀 수, 폭x높이
  • LL: 분포영역, 256
  • round(v)round(v): 반올림
  • H(v)H'(v): 이퀄라이즈된 히스토그램 값

적용 코드

opencv의 cv2.equalizeHist() 함수를 사용하면 쉽게 적용할 수 있다.

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('imgs/yate.jpg', cv2.IMREAD_GRAYSCALE)
img_equalized = cv2.equalizeHist(img)

cv2.imshow('img', img)
cv2.imshow('img_equalized', img_equalized)

cv2.waitKey(0)
cv2.destroyAllWindows()

hist = cv2.calcHist([img], [0], None, [256], [0, 255])
hist_equalized = cv2.calcHist([img_equalized], [0], None, [256], [0, 255])

plt.figure(figsize=(10,5q))
for i, h in enumerate([hist, hist_equalized]):
    plt.subplot(1,2,i+1)
    plt.plot(h)
plt.show()

결과 영상

오른쪽 영상에서 명암이 더 분명하게 출력되는 것을 확인 할 수 있다. 또한 아래 히스토그램 그래프를 확인해보면 히스토그램 분포가 전체적으로 퍼진 것을 알 수 있다.

CLAHE

정의

위의 히스토그램 정규화, 평탄화는 이미지의 전체적인 부분에 균일화를 적용했다. 일반적인 이미지는 밝은 부분과 어두운 부분이 섞여있기 때문에 전체에 적용하는 것은 유용하지 않다.

위 영상에서 보면 어두운 부분은 균일화로 개선되어 밝아졌지만, 가운데 동상 부분은 너무 밝아져 경계선을 알아볼 수 없게 된다. 이 문제를 해결하기 위해 Adaptive histogram equalization을 사용한다.

이미지를 작은 영역으로 구분하여 나우어 그 영역 안에서 각각 Equalization을 적용하는 방식이다. 이때 영역이 작으면 작은 노이즈(매우 어둡거나 밝은 부분)가 있으면 결과에 영향을 미쳐 좋지 않은 영상이 나온다. 이 문제를 피하기 위해 contrast limit 값을 적용하여 이 값을 넘어가는 경우에는 다른 영역에 균일하게 배분하여 적용한다.

적용 코드

cv2.createCLAHE() 함수의 clipLimit, tileGridSize는 경험적으로 영상에 맞게 사용하면 된다. 아래 코드애서는 각각 2.0, (8,8)로 사용했다.

import cv2
import matplotlib.pyplot as plt
img = cv2.imread('imgs/clahe.png', cv2.IMREAD_GRAYSCALE)

# contrast limit가 2이고 영역의 size는 8X8
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
img2 = clahe.apply(img)

cv2.imshow('img', img)
cv2.imshow('clahe', img2)
cv2.waitKey(0)
cv2.destroyAllWindows()

결과 영상

오른쪽 영상에서 볼 수 있듯이, 어두운 부분은 밝게 처리되고 가운데 동상의 윤곽선도 더욱 선명하게 보이는것을 확인 할 수 있다.

참고자료

[도서] 파이썬으로 만드는 OpenCV 프로젝트

[OpenCV] 공식자료

반응형
댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday