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

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

まず、次の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に揃えています。

画像処理に関する疑問にお答えできます。お気軽にお問い合わせください。


4 件のコメント

  • opencv初心者です!
    明度の正規化についてC++を用いて実装したいと考えているのですが、どのようにすればよいでしょうか?
    初歩的な質問で大変申し訳ないですm(__)m

    • cv::Mat mean;
      cv::Mat stddev;
      cv::meanStdDev(img, mean, stddev );

      とすることで、meanに平均、stddevに標準偏差が計算されて取得できます。

    • 画像をどのような型の配列で保持するかによって変わります。floatなどの浮動小数点数型であれば、この数値は何でも構いません。ただし、整数型の場合には、小数点以下の情報が失われます。故に、例えば0~255の範囲の整数で値を保持するnp.uint8タイプの配列であれば、0~255の範囲にまんべんなく収まるように平均輝度、標準偏差を設定する必要があります。今回は64、16にしていますが、出力される画像に問題がなければ多少変更しても問題はないと思います。

  • コメントを残す