감마 보정을 OpenCV를 사용하지 않고

소개



이미지 처리에서 밝기와 대비를 변환하는 방법으로 감마 보정이 있습니다.

식으로는 간단하고 입력을 x, 출력을 y로 하면
$y=255·(\frac{x}{255}) ^\frac{1}{\gamma}$
로 표현할 수 있습니다. 이 $\gamma$의 값을 변경하면 출력 이미지의 픽셀 값을 변경할 수 있습니다.
$\gamma$가 1보다 크면 전체적으로 밝아지고 $\gamma$가 1보다 작으면 전체적으로 어두워집니다.
아래 그림은 $\gamma$ 값을 변경할 때 입력과 출력 사이의 관계를 보여줍니다.


수식에서 $\frac{1}{\gamma}$가 단순히 $\gamma$일 수 있습니다. 그 경우는 위로 볼록과 아래에 볼록이 바뀝니다.

이미지 처리 라이브러리의 OpenCV에도 감마 보정 기능이 있습니다.
수식을 보면 알 수 있듯이 매우 간단하기 때문에 numpy만으로 감마 보정 함수를 만들 수 있습니다.
* 어디까지나 공부용

실제로 해보자



식을 바탕으로 감마 보정의 함수를 만들어 보겠습니다. 순간.
#python version 3.6.5
import numpy as np               #version 1.14.3
import matplotlib.pyplot as plt 
from skimage import io           #scikit image version 0.13.1
plt.rcParams["font.family"] = "Times New Roman"
plt.rcParams["font.size"] = 12

def gammma(x, r):
    """
    ガンマ補正y=255*(x/255) 
    x 入力画像
    r ガンマ補正の係数
    """
    x = np.float64(x)
    y = x/255.
    y = y **(1/r)
    return np.uint8(255*y)

RGB 마다 히스토그램을 작성, 표시하는 함수도 작성해 둡니다. (어떤 휠의 재발 ... 이하 약)
def hist_rgb(img):
    #rgbのヒストグラムを作成する関数
    #結果を格納する変数res [brightness, channel]
    res = np.zeros([256, 3])   
    for channel in range(3):
        #あるchannelを抽出
        img_tmp = img[:,:,channel]
        #画像を1次元にする
        img_tmp =img_tmp.reshape(img_tmp.size)
        for i in img_tmp:
            res[i, channel] += 1
    return res

def mat_hist_rgb(hist, ylim = 0.06):
    #hist_rgbのfunctionで計算したヒストグラムを表示
    x = np.arange(hist.shape[0])
    #ヒストグラムの色を指定
    colors = ["red", "green", "blue"]
    for i, color in enumerate(colors):
        plt.bar(x,hist[:, i], color=color, alpha=0.3, width=1.0)
    plt.xlabel("Brightness")
    plt.ylabel("Frequency")
    plt.xlim(0, 255)
    plt.yticks([])
    plt.show()

우선 lena 님을 읽어 original 이미지의 히스토그램을 표시합니다.
img_lena = io.imread("lena_std.tif")
hist_lena = hist_rgb(img_lena)
mat_hist_rgb(hist_lena)




적색 성분이 많음을 알 수 있습니다.

$\gamma=0.5$인 경우
img_gamma = gammma(img_lena, r=0.5)
io.imsave("r05.png", img_gamma)
mat_hist_rgb(hist_rgb(img_gamma))



히스토그램을 보면 원래 이미지와 비교하여 대부분 어두운 것을 알 수 있습니다.



$\gamma=2.0$인 경우
img_gamma = gammma(img_lena, r=2.0)
io.imsave("r05.png", img_gamma)
mat_hist_rgb(hist_rgb(img_gamma))

상당히 밝아집니다.





특정 색상만 보정



히스토그램을 보면 lena의 이미지는 전체적으로 붉은 색을 띠는 이미지임을 알 수 있습니다.
거기서 특정의 색, 이번의 경우는 적색의 채널에만 감마 보정을 걸어 보겠습니다.
#channelで変換するRGBを指定, R=0, G=1, B=2
channel = 0

#元の画像をコピー
img_gamma = np.copy(img_lena)

#ガンマ補正
img_gamma[:,:,channel] = gammma(img_lena[:,:,channel], r=0.3)
io.imsave("red.png", img_gamma)
mat_hist_rgb(hist_rgb(img_gamma))

$\gamma=0.3$이므로 적색 성분을 약화시키고 있습니다. 이쪽이 자연스러운 느낌이 듭니다.





참고문헌



디지털화상처리[개정 제2판], 공익재단법인 영상정보교육진흥협회(2020)

좋은 웹페이지 즐겨찾기