안녕하세요. 지난 포스팅의 Opencv 제대로 쓰기[5].영상 샤프닝에서는 영상으로부터 엣지를 얻은 뒤 샤프닝을 적용하는 방법에 대해서 알아보았습니다. 오늘은 영상으로부터 opencv를 이용해서 히스토그램을 추출하고 히스토그램 평활화하는 방법에 대해서 알아보겠습니다. 오늘도 전체 코드는 아래의 깃허브를 참조해주시길 바랍니다.
가장 먼저 해볼것은 영상으로부터 히스토그램을 추출하는 것입니다. 디지털 영상에서 히스토그램이란 밝기가 어느정도 분포해있는 지 알 수 있는 방법입니다. 이를 통해서 흔히 말하는 영상의 "대비"를 알 수 있습니다. 이에 대한 자세한 내용은 이전에 제가 정리한 링크를 참조해주시길 바랍니다.
opencv에서는 히스토그램을 추출하는 함수인 cv2.calcHist(images, channels, mask, histSize, ranges)를 지원하고 있습니다. 각 파라미터의 의미를 알아보도록 하겠습니다.
- images(array) : 히스토그램을 추출할 영상
- channels(int) : RGB 영상과 같은 경우 어떤 채널에서 히스토그램을 얻을 것 인지
- mask(array) : 영상에서 특정 영역에 대한 히스토그램을 추출하고 싶다면 영상과 동일한 사이즈의 마스크를 만들어서 입력으로 넣어주기.
- histSize(int) : 히스토그램의 $X$축의 길이. 즉 bin의 갯수와 동일
- ranges(array) : 영상에서 히스토그램을 추출한 강도의 범위
예를 들어서 cv2.calcHist(images, [0], None, [256], [0, 256])은 입력 영상 images에 대해서 첫번째 채널(0)에 대해서 마스크를 적용하지 않고(None) 히스토그램 bin의 개수는 256으로 픽셀 강도는 0부터 255까지 추출하겠다는 의미와 동일합니다. 간단하게 예를 보도록 하겠습니다.
light_image = cv2.imread('./example/Ch3/Fig0320(1)(top_left).tif')
gray_image = cv2.imread('./example/Ch3/Fig0320(2)(2nd_from_top).tif')
high_cont_image = cv2.imread('./example/Ch3/Fig0320(3)(third_from_top).tif')
dark_image = cv2.imread('./example/Ch3/Fig0320(4)(bottom_left).tif')
light_hist = cv2.calcHist(light_image, [0], None, [256], [0, 256])
gray_hist = cv2.calcHist(gray_image, [0], None, [256], [0, 256])
high_cont_hist = cv2.calcHist(high_cont_image, [0], None, [256], [0, 256])
dark_hist = cv2.calcHist(dark_image, [0], None, [256], [0, 256])
위의 결과를 보도록 하겠습니다. 가장 왼쪽 영상은 다른 영상들에 비해서 굉장히 밝다는 것을 알 수 있습니다. 그리고 그에 대응되는 히스토그램 분포를 보면 전체적으로 100 이상의 영역에 분포해있다는 것을 알 수 있죠. 그리고 두번째 영상은 경계와 객체가 크게 뚜렸하지 않은 저대비 영상입니다. 그리고 그 히스토그램은 아주 좁은 영역에 분포해있죠. 그에 반해 세번째 영상은 고대비 영상입니다. 히스토그램을 보면 두번째 영상의 히스토그램과 비교해보았을 때 전체적으로 분포하고 있음을 알 수 있죠. 마지막 영상은 어두운 영상이기 때문에 히스토그램이 전체적으로 100보다 작은 영역에 분포해있다는 것까지 예측을 할 수 있습니다. 저희의 목표는 고대비 영상을 만드는 것입니다. 따라서 영상의 히스토그램을 변환했을 때 전체적으로 분포할 수 있도록 만드는 알고리즘이 필요하죠. 이러한 알고리즘을 "히스토그램 평활화(Histogram Equalization)"이라고 합니다. 이에 대한 수학적 알고리즘은 아래의 링크를 참조하고 여기서는 생략하도록 하겠습니다.
물론 opencv에서는 히스토그램 평활화를 위한 cv2.equalizeHist(img) 역시 제공하고 있습니다. 단순히 입력 영상만 넣어주면 알아서 평활화된 영상이 나오기 때문에 아주 간편한 함수입니다. 다만 입력 영상이 단채널 영상이여야만 합니다. 이 부분만 잘 신경써주시면 됩니다.
image = cv2.imread('./example/low_cont.jpg', cv2.IMREAD_GRAYSCALE)
hist = cv2.calcHist(image, [0], None, [256], [0, 256])
histeq_image = cv2.equalizeHist(image)
histeq_image_hist = cv2.calcHist(histeq_image, [0], None, [256], [0, 256])
입력 영상이 150 근처의 픽셀 강도로 집중되어있었으나 히스토그램 평활화 함수를 적용한 결과 아래와 같이 비교적 넓게 분포된 영상을 얻을 수 있습니다.
'Programming > Python' 카테고리의 다른 글
MMCV Segmentation 입문기 2 (0) | 2022.12.02 |
---|---|
MMCV Segmentation 입문기 1 (0) | 2022.12.02 |
Opencv 제대로 쓰기[5].영상 샤프닝 (0) | 2021.05.31 |
Opencv 제대로 쓰기[4].흐림 처리 (0) | 2021.05.23 |
Opencv 제대로 쓰기[3].외부 카메라 동영상 스크린샷 저장하기 (0) | 2021.05.01 |