OpenCV-Python

OpenCV Python 영상 명암비 조절(정규화)

rkftks22 2021. 8. 29. 15:35

명암비 : 밝은 곳, 어두운 곳 사이의 밝기 정도 차이

 

1) 명암비 조절 : dst(x, y) = saturate(s*src(x, y))

기울기가 작아 확 어두워지거나 기울기가 커서 값들이 대부분의 픽셀 값이 255가 되어 너무 밝아지겠네요.


2) 효과적인 명암비 조절 : dst(x, y) = saturate(src(x, y) + (src(x, y)-128)*a)

위 식의 경우 모든 픽셀 값이 128을 지나게 됩니다. 

※ 이 방법도 너무 밝은(대부분의 픽셀 값이 255쪽), 너무 어두운(대부분의 픽셀 값이 0쪽) 일 경우엔 원하는 결과가 안 나올 수도 있습니다.

import cv2
import numpy as np

src = cv2.imread('imgs/dog.jpg', cv2.IMREAD_GRAYSCALE)

alpha1 = -0.5 # 명암 조정값
alpha2 = 1.0 # 명암 조정값

dst1 = np.clip((1+alpha1) * src - 128 * alpha1, 0, 255).astype(np.uint8)

dst2 = np.clip((1+alpha2) * src - 128 * alpha2, 0, 255).astype(np.uint8)

cv2.imshow('src', src)
cv2.imshow('dst1', dst1)
cv2.imshow('dst2', dst2)

cv2.waitKey(0)

cv2.destroyAllWindows()


영상의 자동 명암비 조절

히스토그램 스트레칭 : 영상의 히스토그램이 그레이 스케일 전 구간에 걸쳐 나타나도록 변경하는 선형 변환 기법

정규화 함수 사용 : cv2.nomalize(src, dst, alpha, beta [, norm_type [, dtype [, mask]]])

정규화 함수를 사용하면 집중되어있던 히스토그램이 균일하게 분포된다고 생각하시면 될 것 같습니다.
히스토그램 그래프를 확인해보면 분포는 각 값의 중간을 비워서 간격을 벌리는 것으로 보이네요.

import cv2
import numpy as np
import matplotlib.pyplot as plt

src = cv2.imread('imgs/Lenna.png', cv2.IMREAD_GRAYSCALE)

hist = cv2.calcHist([src], [0], None, [
    256], [0, 256])
plt.subplot(1, 2, 1)
plt.title('hist')
plt.plot(hist)

dst = cv2.normalize(src, None, 0, 255, cv2.NORM_MINMAX)

hist2 = cv2.calcHist([dst], [0], None, [
    256], [0, 256])
plt.subplot(1, 2, 2)
plt.title('hist2')
plt.plot(hist2)

cv2.imshow('src', src)
cv2.imshow('dst', dst)
cv2.waitKey(1)

plt.show()
cv2.destroyAllWindows()

src : 입력 영상
dst : 출력 영상
alpha : 최솟값 
beta : 최댓값
norm_type : 정규화 타입, NORM_IMF, NORM_L1, NORM_MINMAX 등(설명은 봐도 잘 모르겠네요)
dtype : 결과 영상 타입
mask : 마스크 영상

 

원본 사진(src)과 정규화 결과(dst) 비교해보면 히스토그램이 눈대중으로 40~ 220 정도 히스토그램 분포되었던 게 0 ~ 255까지 분포된 것을 확인하실 수 있습니다. normalize의 결과는 어느 정도 중간에 몰려있는 영상에서 잘 이루어지네요