Python 영상처리 기초 with OpenCV

[Python 영상처리 기초 7] 이미지의 화질개선 Contrast-Brightness-Gamma - part1

toyprojects 2023. 9. 16. 23:39

 

 

앞서 [Python 영상처리 기초 4] 이미지의 픽셀값 다루기 - Crop, 선형연산  에서 보았듯이, 

픽셀값을 증가시키면 이미지의 밝기가 밝아짐을 알 수 있습니다. 

 

 

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

img_color = cv2.imread('national-cancer-institute-jdfn7Z03Qa4-unsplash.jpg',cv2.IMREAD_COLOR)
img_gray = cv2.cvtColor(img_color,cv2.COLOR_BGR2GRAY)

start_pt = [1210, 753]     # [y, x-axis] or (y, x-axis), both are fine
end_pt = [2110, 2115]      # [y, x-axis]
img_gray_crop = img_gray[start_pt[0]:end_pt[0], start_pt[1]:end_pt[1]]     # numpy slicing

img_gray_crop_UP = (img_gray_crop * 1.7).astype('uint8')    # intensity 70% UP

 

Cropped Image (좌: Original, 우: Intensity 70% 상향)

 

 

단순히 픽셀값을 증가시킨다면 이미지의 Global 픽셀값들이 증가하므로 원하지 않는 결과를 얻을 수

있습니다. 예를들어 ROI (region of interest) 의 픽셀값 분포가 높거나 낮은 intensity에 집중분포해

있다면 이 영역만을 확장시켜 주어 밝기나 컨트래스트를 개선할 수 있지만, 전 영역의 픽셀값을 증가시키면

그저 빛바랜 듯한 이미지 결과가 나오기도 합니다. 

 

 

이미지의 brightness와 contrast는 다음의 수식 (출처 1)을 통해 조절할 수 있습니다.

 

 

g(i, j) = alpha · f(i, j) + beta

 

 

입력 이미지 f( i 번째 행, j 번째 열 ) 는 alpha와 beta - 각각 gain과 bias로 불리며 contrast와 brightness

를 제어하는 파라메터 - 값에 의한 연산으로 결과 이미지 g( i, j ) 를 얻습니다. 

위 식에서 beta값을 증가 또는 감소시키면 - 맨 위의 이미지의 밝기가 70% 향상된 예와같이 - 대상 이미지의

brightness가 밝아지거나 어두워질 수 있으며, alpha는 대상 이미지 픽셀 분포를 확장 또는 압축하는 역할을 

합니다. 

 

다음은 Brightness-Contrast-Gamma의 관계를 보여주는 그래프이며 이해를 돕는 설명들이 출처 2 

담겨있으므로 한번쯤 읽어 보시길 바랍니다. 여기에서 gamma란 입력 이미지를 매핑하는 곡선의 모양을 정의

하는 값으로써 나중에 후술하겠습니다. 밑의 그래프에 관해 간략히 설명하자면 입력 gray level 과 출력 gray

level의 매핑을 보여주는 그래프들로써 빨간색 선의 증감에 따라 brightness 가 밝아지거나 어두어짐을

나타내고 빨간색 선의 기울기에 따라 contrast의 증감을 보여줍니다. Gamma의 첫번째와 두번째 그래프와

같이 빨간색 선이 어두운 영역에서 급격히 증가하면 (gamma < 1)  어두운 영역의 픽셀 분포가 확장되어 

이 영역의 가시성(visible)이 좋아지는 효과가 있습니다.

 

 

 

Brightness-Contrast-Gamma graphs (출처 2)

 

 

이미지 픽셀값 변환에서 Brightness와 contrast 는 뗄수 없는 관계이고, 항상 선형적인 상관관계를 

갖지도 않습니다. 그러므로 alpha에 의해 contrast가 조정됨과 동시에 brightness가 달라질 수 있고,

반대의 경우도 가능합니다.

 

입력 이미지가 gray scale 2차원의 경우, 위 수식에 따라 x, y축 (혹은 i, j 방향)에 따라 2번의 for loop 

연산을 수행해야 하지만 - 3차원의 컬러 이미지는 3번의 for loop 필요 - 효율적인 연산을 위해 OpenCV

가 제공하는 convertScaleAbs( ) 메소드를 이용해 이미지의 brightness, constrast를 변환해 보겠습니다.

입력 이미지는 다음과 같고 gray scale 이미지로 변환하여 이용할 것입니다.

 

밑의 이미지는 본 블로그 맨밑 출처 3에 가셔서 다운로드 받을 수 있습니다. 

 

 

Cells from cervical cancer - National Cancer Institute (출처3)

 

 

 

다음은 brightness 변환의 결과를 보여줍니다. 입력 이미지는 uint8 타입으로써 최소 0, 최대 255의 픽셀값

범위를 가지며, 위의 변환수식중 임의값 beta = 30 으로 대상 이미지의 brightness를 향상시켰고, 밑의

brightness 변환 전후의 histogram를 비교해보면 그래프의 피크가 좌측에서 우측으로 대략 30만큼 이동

했음을 알 수 있습니다.

 

 

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

img_color = cv2.imread('national-cancer-institute-jdfn7Z03Qa4-unsplash.jpg',cv2.IMREAD_COLOR)
img_gray = cv2.cvtColor(img_color,cv2.COLOR_BGR2GRAY)

alpha = 1   # contrast control
beta = 30   # brightness control
img_beta_UP1 = cv2.convertScaleAbs(img_gray, alpha=alpha, beta=beta)

img_gray_hist = cv2.calcHist([img_gray], [0], None, [256], [0, 256])
img_beta_UP1_hist = cv2.calcHist([img_beta_UP1], [0], None, [256], [0, 256])

fig = plt.figure(figsize=(12,10))    
fig.add_subplot(2,2,1)
plt.axis("off")
plt.title("Original")
plt.imshow(img_gray,cmap='gray')

fig.add_subplot(2,2,2)
plt.axis("off")
plt.title("Brightness raised")
plt.imshow(img_beta_UP1,cmap='gray')

fig.add_subplot(2,2,3)
plt.plot(img_gray_hist)
plt.xlim([0, 256])

fig.add_subplot(2,2,4)
plt.plot(img_beta_UP1_hist)
plt.xlim([0, 256])

plt.show()

 

Brightness를 향상시킨 결과 image와 histogram (좌: Original, 우: beta=30)

 

 

 

또 다른 beta값으로써 입력 이미지 픽셀의 평균값 46.466 (uint8 타입 - 최소0, 최대 255)에 70%를

상향시켜 적용한 결과 입니다. 밑 우측의 histogram에서 보듯이 낮은 영역에 존재하던 피크가 대략

픽셀값 100 으로 이동했음을 알 수 있습니다.

 

 

alpha = 1   # contrast control
beta = np.mean(img_gray)*1.7   # brightness control
img_beta_UP2 = cv2.convertScaleAbs(img_gray, alpha=alpha, beta=beta)

img_gray_hist = cv2.calcHist([img_gray], [0], None, [256], [0, 256])
img_beta_UP2_hist = cv2.calcHist([img_beta_UP2], [0], None, [256], [0, 256])

fig = plt.figure(figsize=(12,10))    
fig.add_subplot(2,2,1)
plt.axis("off")
plt.title("Original")
plt.imshow(img_gray,cmap='gray')

fig.add_subplot(2,2,2)
plt.axis("off")
plt.title("Brightness raised")
plt.imshow(img_beta_UP2,cmap='gray')

fig.add_subplot(2,2,3)
plt.plot(img_gray_hist)
plt.xlim([0, 256])

fig.add_subplot(2,2,4)
plt.plot(img_beta_UP2_hist)
plt.xlim([0, 256])

plt.show()

 

Brightness를 향상시킨 결과 image와 histogram (좌: Original, 우: beta=이미지 평균의 70% 상향)

 

 

 

 

 

 

출처1: https://docs.opencv.org/3.4/d3/dc1/tutorial_basic_linear_transform.html

 

OpenCV: Changing the contrast and brightness of an image!

Prev Tutorial: Adding (blending) two images using OpenCV Next Tutorial: Discrete Fourier Transform Goal In this tutorial you will learn how to: Access pixel values Initialize a matrix with zeros Learn what cv::saturate_cast does and why it is useful Get so

docs.opencv.org

 

 

 

출처2: https://www.quora.com/What-is-the-difference-between-brightness-contrast-and-gamma

 

What is the difference between brightness, contrast, and gamma?

Answer (1 of 4): Not all definitions are the same, but due to tradition from television set controls, this is how they are defined in display technology. Brightness is simply a DC offset. An amount of uniform light added to (or subtracted from) everything

www.quora.com

 

 

 

 

출처3: https://unsplash.com/photos/jdfn7Z03Qa4

 

사진 작가: National Cancer Institute, Unsplash

Cells from cervical cancer – Splash에서 National Cancer Institute의 이 사진 다운로드

unsplash.com