728x90
import numpy as np
import matplotlib.pyplot as plt
import cv2 as cv


# 히스토그램 스트레칭 함수
def imadjust(src, input_range=None, output_range=None, gamma=1.0):  # (원본영상, 입력범위, 출력범위, 감마)
    src_dtype = src.dtype

    if src_dtype == 'uint8':
        src = src / 255

    if input_range == None:
        input_range = [0, 1]
    if output_range == None:
        output_range = [0, 1]

    low_in, high_in = input_range
    low_out, high_out = output_range

    r = np.arange(0, 256) / 255.0
    g = np.arange(0, 256) / 255.0    # LUT

    g[g < low_in] = low_out
    g[g > high_in] = high_out
    g = np.where((r >= low_in) & (r <= high_in),
                 ((r - low_in) / (high_in - low_in)) ** (gamma) * (high_out - low_out) + low_out, g)

    dst = g[(src*255).astype('uint8')]   # LUT를 사용하여 이미지 변환

    if src_dtype == 'uint8':
        dst = (dst * 255).astype('uint8')

    return dst


img = cv.imread('data/lenna.tif')
#img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)  # 흑백 영상
img = img[..., ::-1]
img = img / 255

plt.figure('image')
plt.subplot(2, 2, 1)
plt.title('input image')
plt.axis('off')
plt.imshow(img, cmap='gray')

plt.subplot(2, 2, 2)
dst1 = imadjust(img, input_range=[0, 1], output_range=[0.3, 0.7])
plt.title(str([0, 1]) + ' -> ' + str([0.3, 0.7]))
plt.axis('off')
plt.imshow(dst1, cmap='gray')

plt.subplot(2, 2, 3)
dst2 = imadjust(img, input_range=[0.2, 0.8], output_range=[0, 1])
plt.title(str([0.2, 0.8]) + ' -> ' + str([0, 1]))
plt.axis('off')
plt.imshow(dst2, cmap='gray')

plt.subplot(2, 2, 4)
dst3 = imadjust(img, input_range=[0.4, 0.6], output_range=[0, 1])
plt.title(str([0.4, 0.6]) + ' -> ' + str([0, 1]))
plt.imshow(dst3, cmap='gray')
plt.axis('off')
plt.show()

if img.dtype == 'uint8':
    bin_range = [0, 256]
else:
    bin_range = [0, 1]

plt.figure('image_histogram')
plt.subplot(2, 2, 1)
plt.title('Histogram : input image')
plt.hist(img.ravel(), 256, bin_range)

plt.subplot(2, 2, 2)
plt.title('Histogram : '+ str([0, 1]) + ' -> ' + str([0.3, 0.7]))

plt.hist(dst1.ravel(), 256, bin_range)

plt.subplot(2, 2, 3)
plt.title('Histogram : ' + str([0.2, 0.8]) + ' -> ' + str([0, 1]))
plt.hist(dst2.ravel(), 256, bin_range)

plt.subplot(2, 2, 4)
plt.title('Histogram : ' + str([0.4, 0.6]) + ' -> ' + str([0, 1]))
plt.hist(dst3.ravel(), 256, bin_range)

plt.show()

org = cv.imread('data/lenna.tif')
img2 = imadjust(org, [0.4, 0.7], [0, 1], 0.3)
psnr = cv.PSNR(org, img2)
print('%.4f' % psnr)

org = cv.imread('data/lenna.tif') / 255
img2 = imadjust(org, [0, 1], [0.4, 0.7], 0.3)
sse = np.sum((org - img2) ** 2)
print('%.3e' % sse)

# imadjust(src, input_range=[0,1], output_range=[0,1], gamma=1.0)

- 히스토그램 스트레칭을 하는 함수

- 히스토그램 스트레칭은 히스토그램의 양쪽 끝단을 잡아당겨서 영상의 대조비를 강화하여 선명한 영상 얻음

- low_in, high_in 은 입력범위의 최소, 최대(디폴트는 [0,1])

- low_out, high_out 은 출력범위의 최소, 최대(디폴트는 [0,1])

- low_in 보다 작은 값은 low_out 으로 출력함

- low_out 보다 큰 값을 high_out 으로 출력함

- low_in 과 high_in 사이의 값들은 감마 변환을 하여 출력함

- np.where() 함수를 사용하여 조건에 해당하는 인덱스에 해당하는 값을 변환함

- 감마가 1보다 크면 어둡게, 1보다 작으면 밝게 변함, 1이면 원본과 동일

- 입력영상이 uint8float64 제한 없게 하기 위하여 uint8인 경우 255로 나누어 정규화 시 킨 뒤 스트레칭 작업을 수행한 후 다시 255를 곱하고 uint8로 변환하여 반환함

- Look Up Table를 사용하기 위하여 x축 데이터 r(0~1) 과 변환 테이블 g를 생성함

- 화소 값에 따라 스트레칭한 값을 g에 저장함

- 변환 테이블 g를 사용하여 입력영상에 적용하여 스트레칭한 결과 영상 반환 받음

 

# 원본영상과 히스토그램 스트레칭한 영상 출력

- 원본영상이 uint8인 경우 bin 범위를 [0, 256] 로 설정

- 원본영상이 float64인 경우 bin 범위를 [0, 1] 로 설정

- 영상을 읽어올 때cv.imread()로 읽으면 b,g,r 순이므로 역순으로 재배열함

- 2x2 형태의 창에 원본 영상과3개의 히스토그램 스트레칭한 영상 출력하고 각각에 대한 히 스토그램 출력

- 히스토그램을 출력할 때는 영상을 1차원 리스트로 변환하여 입력하여야 함

- 1차원 리스트로 변환한 영상, bin의 개수 bin 범위를 입력하여 히스토그램 출력함

 

# 필요한 모듈 import

- numpy, matplotlib.pyplot, cv2

 

# 실행 결과

1. 칼라 영상(uint8)인 경우

- 원본과 imadjust 실행한 영상 3

- 영상들의 히스토그램

2. 칼라 영상(float64)인 경우

- 원본과 imadjust 실행한 영상 3

- 영상들의 히스토그램

3. 흑백 영상(uint8)인 경우

- 원본과 imadjust 실행한 영상 3

- 영상들의 히스토그램

4. 흑백 영상(float64)인 경우

- 원본과 imadjust 실행한 영상 3

- 영상들의 히스토그램

# 느낀 점

- 실행결과를 보니 결과 영상은 얼추 맞게 나오는 것 같으나 확신하지 못함

- 자체 평가표에 주어진 문제에 대한 출력 값이 올바르게 나오지 않음

- 감마 변환에 대한 수식이 올바르지 못한 거 같음

- uint8float64에 대한 제한이 없다는 것을 억지로 맞춰서 되게끔 한 거 같아 올바른 방법 이 무엇인지 궁금함

반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기