web-dev-qa-db-ja.com

Python)を使用して16ビットPNG画像ファイルを読み取ります

16ビットのデータ型で書かれたPNG画像ファイルを読み込もうとしています。データはNumPy配列に変換する必要があります。しかし、「16ビット」でファイルを読み取る方法がわかりません。 PILとSciPyを試してみましたが、ロード時に16ビットデータを8ビットに変換しました。誰かが16ビットPNGファイルからデータをアップアウトしてデータ型を変更せずにNumPy配列に変換する方法を教えてもらえますか?

以下は私が使用したスクリプトです。

from scipy import misc
import numpy as np
from PIL import Image
#make a png file    
a = np.zeros((1304,960), dtype=np.uint16)
a[:] = np.arange(960)
misc.imsave('16bit.png',a)

#read the png file using scipy
b = misc.imread('16bit.png')
print "scipy:" ,b.dtype

#read the png file using PIL
c = Image.open('16bit.png')   
d = np.array(c)
print "PIL:", d.dtype
8
Nownuri

私はここでも同じ問題を抱えています。自分で作成した16ビット画像でもテストしました。 pngパッケージをロードすると、すべて正しく開かれました。また、「ファイル」の出力は問題ないように見えました。

それらをPILで開くと、常に8ビットのnumpy-arraysになりました。

LinuxでPython 2.7.6を使用する。

このようにそれは私のために働きます:

import png
import numpy as np

reader = png.Reader( path-to-16bit-png )
pngdata = reader.read()
px_array = np.array( map( np.uint16, pngdata[2] ) 
print( px_array.dtype )

たぶん誰かが前者のアプローチがうまくいった状況でより多くの情報を与えることができますか? (これはかなり遅いので)

前もって感謝します。

5
Mr.Fridy

これは、PILが16ビットデータをサポートしていないために発生します。ここで説明します: http://effbot.org/imagingbook/concepts.htm

Osgeo gdalパッケージ(PNGを読み取ることができます)を使用する回避策を使用します。

#Import
import numpy as np
from osgeo import gdal

#Read in PNG file as 16-bit numpy array
lon_offset_px=0
lat_offset_px=0
fn = 'filepath'
gdo = gdal.Open(fn)
band = gdo.GetRasterBand(1)
xsize = band.XSize
ysize = band.YSize
png_array = gdo.ReadAsArray(lon_offset_px, lat_offset_px, xsize, ysize)
png_array = np.array(png_array)

これは戻ります

png_array.dtype
dtype('uint16')

私が見つけたよりクリーンな方法は、skimageパッケージを使用することです。

from skimage import io
im = io.imread(jpg)

ここで、「im」はnumpy配列になります。注:これはPNGでテストしていませんが、TIFFファイルで機能します

私はpngモジュールを使用しています:最初にpngをインストールします:

>pip install pypng

次に

import png
import numpy as np
reader = png.Reader('16bit.png')
data = reader.asDirect()
pixels = data[2]
image = []
for row in pixels:
  row = np.asarray(row)
  row = np.reshape(row, [-1, 3])
  image.append(row)
image = np.stack(image, 1)
print(image.dtype)
print(image.shape)
2
Wenyi Tang

私が見つけた最も簡単な解決策:

16ビットのモノクロPNGピローを開くと、I;16モードとして正しく開きません。 Image.modeI(32ビット)として開かれます

したがって、numpy配列に変換するための最良の方法です。 dtype = "int32"なので、dtype = "uint16"に変換します。

import numpy as np
from PIL import Image

im = Image.fromarray(np.array(Image.open(name)).astype("uint16"))
print("Image mode: ",im.mode))

Python 3.6.8 with Pillow6.1.0でテスト済み

1
Rutrus

あなたの「16ビット」PNGは16ビットではないと思います。 (LinuxまたはMacを使用している場合は、file 16bit.pngを実行して、その内容を確認できます)

PILとnumpyを使用すると、16ビット値を含む32ビット配列が得られます。

import PIL.Image
import numpy

image = PIL.Image.open('16bit.png')   
pixel = numpy.array(image)

print "PIL:", pixel.dtype

print max(max(row) for row in pixel)

出力は次のとおりです。

PIL: int32
65535
0
David Jones

私はPILバージョン5.3.0を使用してこの画像で遊んでいます:

enter image description here

データを正常に読み取ります。

_>>> image = Image.open('/home/jcomeau/Downloads/grayscale_example.png')
>>> image.mode
'I'
>>> image.getextrema()
(5140, 62708)
>>> image.save('/tmp/test.png')
_

そしてそれは正しいモードで保存します、しかし内容は同一ではありません:

_jcomeau@aspire:~$ diff /tmp/test.png ~/Downloads/grayscale_example.png 
Binary files /tmp/test.png and /home/jcomeau/Downloads/grayscale_example.png differ
jcomeau@aspire:~$ identify /tmp/test.png ~/Downloads/grayscale_example.png 
/tmp/test.png PNG 85x63 85x63+0+0 16-bit sRGB 6.12KB 0.010u 0:00.000
/home/jcomeau/Downloads/grayscale_example.png PNG 85x63 85x63+0+0 16-bit sRGB 6.14KB 0.000u 0:00.000
_

ただし、image.show()は常に8ビットのグレースケールに変換され、0と255でクランプされます。したがって、変換のどの段階でも何が得られるかを確認するのに役立ちません。そうするためのルーチンを書くことはできますが、おそらくモンキーパッチ.show()でさえ、別のxtermでdisplayコマンドを実行するだけです。

_>>> image.putdata([n - 32768 for n in image.getdata()])
>>> image.getextrema()
(-27628, 29940)
>>> image.save('/tmp/test2.png')
_

darkened grayscale image

モード_I;16_に変換しても効果がないことに注意してください。

_>>> image.convert('I;16').save('/tmp/test3.png')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/jcomeau/.local/lib/python2.7/site-packages/PIL/Image.py", line 1969, in save
    save_handler(self, fp, filename)
  File "/home/jcomeau/.local/lib/python2.7/site-packages/PIL/PngImagePlugin.py", line 729, in _save
    raise IOError("cannot write mode %s as PNG" % mode)
IOError: cannot write mode I;16 as PNG
_
0
jcomeau_ictx

優れた OpenImageIO ライブラリのPython APIを使用することもできます。

import OpenImageIO as oiio
img_input = oiio.ImageInput.open("test.png")    # Only reads the image header
pix = img_input.read_image(format="uint16")     # Reads the pixels into a Numpy array

OpneImageIOはVFX業界で広く使用されているため、ほとんどのLinuxディストリビューションにはネイティブパッケージが付属しています。残念ながら、他の点では優れたドキュメントはPDF形式(私は個人的にHTMLが好きです)です。/usr/share/doc/OpenImageIOで探してください。

0
beemtee