scipy.misc.imsaveは最小値と最大値で規格化される


このページは以下のURLに移転しました。5秒後に自動で移動します。
新URL: https://note.nkmk.me/python-scipy-misc-imsave/

scipy.misc.imsave()で保存する際、uint8以外は最小値と最大値で規格化されるので注意が必要。

症状

例えば、scipy.misc.lena()で取得できる画像の場合、

  • 最小値: 25
  • 最大値: 245

だが、そのままscipy.misc.imsave()で保存すると、保存された画像は、

  • 最小値: 0
  • 最大値: 255

となり、コントラストが強調されたようになってしまう。

1
2
3
4
5
6
7
8
9
10
11
12
from scipy import misc
import numpy as np
from PIL import Image
lena = misc.lena()
print(lena.min(), lena.max())
# 25 245
misc.imsave('lena_imsave.jpg', lena)
lena_imsave = np.array(Image.open('lena_imsave.jpg'))
print(lena_imsave.min(), lena_imsave.max())
# 0 255

左が元画像、右がscipy.misc.imsave()で保存された画像。

originalsaved

原因

コードをたどると、scipy.misc.imsave()scipy.misc.toimage()ndarrayPIL imageに変換して保存している。さらに、scipy.misc.toimage()の中では、scipy.misc.bytescale()が呼ばれている。

scipy.misc.bytescale()では、uint8以外のタイプはデフォルトで最小値から最大値の範囲に規格化される。

scipy.misc.lena()の画像はタイプがint64なので、規格化されてしまう。

対処法

  • numpy.uint8()でタイプを変える。

  • scipy.misc.bytescale()scipy.misc.toimage()で適切な規格化のパラメータを設定する。

1
2
3
4
misc.imsave('lena_uint8.jpg', np.uint8(lena))
misc.imsave('lena_bytescale.jpg', misc.bytescale(lena, cmin=0, cmax=255))
misc.toimage(lena, cmin=0, cmax=255).save('lena_toimage.jpg')

cmincmaxが規格化に使われる値で、デフォルトでは入力されるndarrayの最小値と最大値になっている。例えば、10bit(0-1023)の画像のときは、cmin=0cmax=1023とすればよい。

参考

関連記事