画像の明るさを正規化する

画像を定量するときに、あるいは、機械学習の前処理をするときなどに、画像の明るさがバラバラだと、いくらその後の過程に手の込んだプログラムを用いてもうまい結果を出せないと思います。画像の明るさを揃えるためのコードを紹介します。

まず、次の3つの画像を用意しました。元は同じ画像なのですが、コントラストや明るさを変えています。

この画像を次のコードで正規化します。読み込みはグレースケールで行っています。

import cv2
import numpy as np
from matplotlib import pyplot as plt
%matplotlib inline
plt.figure(figsize=(20,20))

for i in range(1,4):
    img = cv2.imread("/Users/YM/Desktop/mri"+str(i)+".png",0)
    
    plt.subplot(4, 3, i)
    plt.imshow(img,clim=[0,255])
    plt.colorbar()
    plt.subplot(4, 3, i+3)
    plt.imshow(cv2.cvtColor(img.astype(np.uint8),cv2.COLOR_GRAY2BGR))
    plt.colorbar()
    
    print np.mean(img),np.std(img)
    img = (img - np.mean(img))/np.std(img)*16+64
    
    plt.subplot(4, 3, i+6)
    plt.imshow(img,clim=[0,255])
    plt.colorbar()
    plt.subplot(4, 3, i+9)
    plt.imshow(cv2.cvtColor(img.astype(np.uint8),cv2.COLOR_GRAY2BGR))
    plt.colorbar()
84.7051914894 53.8605072886
152.579489362 17.3552225433
115.387625532 63.780271425

上の段2つが処理前、下の段2つが処理後です、奇数段目は疑似カラーで描画しています。肝となる部分は、

img = (img - np.mean(img))/np.std(img)*16+64

の部分です。画像の平均輝度を64に、輝度値の標準偏差を16に揃えています。画像の平均はmean関数で、標準偏差はstd関数で求まるので、元画像から平均輝度値を引いて標準偏差で割った時点で平均0、標準偏差1の画像が出来ます。そこにさらに16をかけて、64を足すことで、画像の平均輝度を64に、輝度値の標準偏差を16に揃えています。