web-dev-qa-db-ja.com

numpy配列をscikit-imageを使用して高精度(16ビット)の画像として保存します

高精度(16ビットなど)でグレースケール.pngファイルに保存したい2D浮動小数点numpy配列を使用しています。可能であれば、scikit-image skimage.ioパッケージを使用してこれを実行したいと思います。

これが私が試した主なことです:

import numpy as np
from skimage import io, exposure, img_as_uint, img_as_float

im = np.array([[1., 2.], [3., 4.]], dtype='float64')
im = exposure.rescale_intensity(im, out_range='float')
im = img_as_uint(im)
im

生成:

array([[    0, 21845],
       [43690, 65535]], dtype=uint16)

最初にこれを画像として保存してから、Python Imaging Library:

# try with pil:
io.use_plugin('pil')
io.imsave('test_16bit.png', im)
im2 = io.imread('test_16bit.png')
im2

生成:

array([[  0,  85],
       [170, 255]], dtype=uint8)

そのため、どこか(書き込みまたは読み取りのいずれか)で精度が失われました。次に、matplotlibプラグインを試してみました。

# try with matplotlib:
io.use_plugin('matplotlib')
io.imsave('test_16bit.png', im)
im3 = io.imread('test_16bit.png')
im3

32ビットのフロートが表示されます。

array([[ 0.        ,  0.33333334],
       [ 0.66666669,  1.        ]], dtype=float32)

しかし、16ビットのuintをファイルに保存したことを考えると、これが本当に32ビットであるとは思えません。誰かが私が間違っているところを教えてくれるといいですね。これを3D配列にも拡張したいと思います(つまり、画像あたり48ビットで、カラーチャネルあたり16ビットを節約します)。

更新:

問題はimsaveにあります。画像はチャネルあたり8ビットです。 io.imsaveを使用して高ビット深度の画像を出力するにはどうすればよいですか?

11
tsawallis

freeimageライブラリを使用してこれを行います。

_import numpy as np
from skimage import io, exposure, img_as_uint, img_as_float

io.use_plugin('freeimage')

im = np.array([[1., 2.], [3., 4.]], dtype='float64')
im = exposure.rescale_intensity(im, out_range='float')
im = img_as_uint(im)

io.imsave('test_16bit.png', im)
im2 = io.imread('test_16bit.png')
_

結果:

_[[    0 21845]
 [43690 65535]]
_

3D配列に関しては、配列を適切に構築する必要があり、そうすれば機能します。

_# im = np.array([[1, 2.], [3., 4.]], dtype='float64')
im = np.linspace(0, 1., 300).reshape(10, 10, 3)
im = exposure.rescale_intensity(im, out_range='float')
im = img_as_uint(im)

io.imsave('test_16bit.png', im)
im2 = io.imread('test_16bit.png')
_

読み取った画像が反転するため、np.fliplr(np.flipud(im2))のようなもので元の形になります。

11
abudis