히스토그램(histogram) 처리

Seungpil Choi·2022년 7월 21일
0
post-thumbnail

히스토그램(histogram) 처리

히스토그램이란?

히스토그램이란 특정한 값을 가진 화소가 영상 안에 몇 개나 있는지를 막대그래프로 표시한 것이다. 히스트로그램은 화소값들의 분포르 한눈에 볼 수 있어서 영상처리에서 중요하게 사용된다. 예를 들어 화소값들이 최소값 근처에 몰려있다면 이것은 사진을 촬영할 때 노출이 적었다는 것을 의미한다. 반대로 화소값들이 최대값 근처에 몰려 있다면 노출이 너무 많았다는 것을 의미한다. 히스토그램의 정보를 이용하면 영상의 콘트라스트를 향상시킬 수 있다. 특히 히스토그램 평활화라는 기법을 사용하면 인간의 개입 없이도 자동적으로 영상의 콘트라스트를 최적으로 조정할 수 이다. 히스토그램은 이진화에 필요한 임계값을 자동으로 결정하는 데도 사용할 수 있다.

히스토그램 계산하기

OpenCV에서 히스토그램을 계산할 때는 calcHist() 를 사용한다. 매개변수를 보면 매우 복잡하다. 매개 변수가 복잡해진 이유는 calcHist() 함수가 하나의 영상이 아닌 여러 개의 영상을 받아서 한 번에 처리할 수 있도록 되어 있기 때문이다.

  • 매개변수
    1. images : 소스 영상 행렬
    2. nimages : 소스 영상 행렬의 개수
    3. channels : 히스토그램을 계산하는데 사용되는 채널의 개수
    4. mask : 소스 배열에서 사용할 마스크 영상. 마스크 영상은 무시할 화소르 나타내며, 정의되지않은 경우 사용되지 않는다.
    5. hist : 히스토그램이 저장될 Mat 객체
    6. dims : 히스토그램의 차원
    7. histSize : 사용된 차원당 상자(bin)수
    8. ranges : 측정할 값의 범위
    9. uniform : 히스토그램이 균일한지를 표시하는 플래그
    10. accumlate : true가 되면 히스토그램을 계산하기 전에 0으로 만들지 않는다. 즉, 누적된다.
gray_img = cv2.imread('lena.png', 0)
color_img = cv2.imread('lena.png')
color_img = cv2.cvtColor(color_img, cv2.COLOR_BGR2RGB)

plt.imshow(gray_img, cmap='gray')
plt.imshow(color_img)

gray_img_hist = cv2.calcHist([gray_img], [0], None, [256], [0,256])
plt.plot(gray_img_hist)

color = ('b', 'g', 'r')

for i, col in enumerate(color):
  hist = cv2.calcHist([color_img], [i], None, [256], [0,256])
  plt.plot(hist, color=col)
  plt.xlim([0,256])


히스토그램 스트레칭

히스토그램을 변경하여서 영상의 콘트라스트를 증가시킬 수 있다. 히스토그램의 전체적인 형태를 변경하지 않으면서 히스토그램의 범위를 늘리는 것이 목표이다.
cv2.normalize() 함수를 통해 히스토그램 스트레칭을 할 수 있다.
이미지의 최댓값이 255가 있거나 최솟값이 0 이라면 함수가 제대로 작동을 안할 수도 있다.

gray_img = cv2.imread('lena.png', 0)
plt.imshow(gray_img, cmap='gray')
hist = cv2.calcHist([gray_img], [0], None, [256], [0,256])
plt.plot(hist)

dst = cv2.normalize(gray_img, None, 0, 255, cv2.NORM_MINMAX)
plt.imshow(dst, cmap='gray')

hist = cv2.calcHist([dst], [0], None, [256], [0,256])
plt.plot(hist)
 


히스토그램 평활화(histogram equalization)

히스토그램 평활화는 화소값의 분포를 나타내는 히스토그램이 균일하게 되도록 변환하는 처리이다. 즉, 출력영상의 히스토그램에서 각 밝기값들이 거의 동일한 개수의 화소를 가지도록 입력 영상의 화소값을 매핑하는 것을 의미한다. 히스토그램 평활화는 기본적으로 화소 처리 기법이다. 즉, 입력 영상의 화소에 어떤 함수를 적용하여서 출력 영상을 얻는다. 히스토그램 평활화는 누적 히스토그램을 변환 함수로 사용한다. 히스토그램 평활화는 너무 밝거나 어두운 영상, 또는 어느 한편으로 치우쳐 있는 영상의 개선에는 유효한 방법으로 사용된다. 특히, 이방법은 X선 영상의 뼈 구조를 보다 잘 볼 수 있게 해주며 과다 노출 또는 과소 노출된 사진을 정상 노출의 사진으로 만들 수 있다. 히스토그램 평활화에는 우리가 입력하는 매개변수가 없다. 즉, 인간의 개입이 필요없이 자동적으로 처리할 수 있어서 상당히 권장되는 처리이다. 또한 히스토그램 평활화 함수를 알고 있으면 언제든지 역변환이 가능하다.

히스토그램 평활화를 이해하려면 먼저 영상의 콘트라스트 개념을 정확하게 이해해야한다.
콘트라스트는 영상의 두 객체 사이의 밝기나 색상의 차이로 정의된다. 만약 콘트라스트가 너무 낮으면 두 객체를 구분할 수 없다. 사용가능한 화소값의 일부만 사용되는 영상 역시 콘트라스트가 낮다. 이 와 같은 히스토그램을 갖는 영상은 인간의 눈이 식별하기 어려울 수 있다. 왜냐하면 인간의 눈은 비선형 방식으로 밝기에 민감하기 때문이다. 인간이 보기 편하게 하려면 영상에서 모든 밝기값이 사용되어야한다. 모든 밝기값을 사용하도록 만드는 작업이 바로 히스토그램 평활화이다.

히스토그램 스트레칭과 히스토그램 평활화의 차이점

히스토그램 평활화가 히스토그램 막대의 높이를 균일하게 하는것이라면 히스토그램 스트레칭은 막대의 높이는 변경하지 않으면서 막대들을 펼쳐 놓는 것이다. 히스토그램 분포가 좁지는 않지만 특정한 값에 몰리는 경우도 있는데 이런 경우에는 히스토그램 스트레칭보다는 히스토그램 평활화가 유리하다.

OpenCV에서의 히스토그램 평활화

OpenCV는 히스토그램 평활화를 수행하는 함수 cv2.equalizeHist() 를 제공한다.
컬러영상에 히스토그램 평활화를 적용할 때에는 RGB값에 바로 적용하면 색이 변할 수 있다. RGB로 받은 이미지를 HSV또는 YCrCb형태의 이미지로 변경한 다음에 밝기값 채널을 변경해야 색을 변경하지 않고 선명하게 만들 수 있다.

img = cv2.imread('car_plate.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img)

color = ('r', 'g', 'b')

for i, col in enumerate(color):
  hist = cv2.calcHist([img], [i], None, [256], [0,256])
  plt.plot(hist, color=col)
  plt.xlim(0,256)
 
img = cv2.cvtColor(img, cv2.COLOR_RGB2HSV) ## HSV영상을 변경
img[:,:,2] = cv2.equalizeHist(img[:,:,2])  ## 평활화
img = cv2.cvtColor(img, cv2.COLOR_HSV2RGB) ## 다시 영상을 RGB로 변경
plt.imshow(img)

color = ('r', 'g', 'b')

for i, col in enumerate(color):
  hist = cv2.calcHist([img], [i], None, [256], [0,256])
  plt.plot(hist, color=col)
  plt.xlim(0,256)
  


히스토그램을 이용한 전경과 배경 분리

img = cv2.imread('plane.jpg', 0)
plt.imshow(img, cmap='gray')

hist = cv2.calcHist([img], [0], None, [256], [0,256])
plt.plot(hist)

threshold() 함수를 이용하면 편리하게 이진화가 가능하다. 위의 히스토그램을 보면 대략 140쯤에서 봉우리들이 등장한다. 그 부분을 임계점으로 잡고 분리를 한다.

ret, threshold_img = cv2.threshold(img, 133, 255, cv2.THRESH_BINARY)
plt.imshow(threshold_img,cmap='gray')

향상된 이진화 방법

앞의 방법은 이진화 시에 가장 중요한 임계값을 인간이 결정하여야 한다. 히스토그램에서 각 봉우리 들을 가우시안 분포로 가정하고 가우시안 함수를 봉우리에 근사시킨 후에 중간 부분을 임계값으로 하는 것이다. 이러한 방식으로 컴퓨터가 영상을 분석하여 자동으로 임계값을 결정할 수 있다. 이것은 Otsu의 이진화 방법으로 알려져 있다. OpenCV의 threshold()함수에서도 Otsu의 방법을 지원한다.

ret, threshold_img = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
plt.imshow(threshold_img,cmap='gray')
print(ret) # 126

0개의 댓글