dtype np.uint8 の 256 x 256 ピクセルの何千ものグレースケール タイルがあり、それらをできるだけ早く 1 つの BigTiff ピラミッド型イメージに結合したいと考えています。
私の現在のアプローチは、最終的な画像のサイズで numpy 配列を作成し、そこにすべてのタイルを貼り付けることです (これには数秒しかかかりません)。節約のために、私は複数のアプローチを調べました。
1) Tifffileimsave
、非常に遅いことが判明した関数を使用して、少なくとも約 700MB になるファイルの場合、少なくとも 10 分以上かかると見積もっています。
2) pyvips、 を使用して大量の numpy イメージを pyvips イメージに変換し、pyvips.Image.new_from_memory
これを使用して保存します。
vips_img.tiffsave(filename, tile=True, compression='lzw', bigtiff=True, pyramid=True, Q=80)
vips_img の作成には約 42 秒かかり、ディスクへの保存にはさらに約 30 秒かかりますが、これはすべて単一のスレッドを使用して行われます。別の方法を使用するか、マルチスレッドを活用して、これをより効率的に行う方法があるかどうか疑問に思っています。高速ストレージが利用可能であるため、最初に別の形式で保存するか、必要に応じて別のプログラミング言語に転送することができます。
ブレーンストーミング: すべてのタイルは既存の BigTiff 画像から取得され、前処理パイプラインを通過したため、再度保存する必要があります。元のファイルをコピーして、そこにあるデータを効率的に置き換える方法があるかどうか疑問に思っています。
詳細を編集してください:
画像のサイズはおおよそ 55k x 45k ですが、たとえば 150k x 150k までの大きな画像にもこのコードを使用したいと思います。
55k x 45k の画像と 256 x 256 のタイルの場合、約 53k タイルについて話しています。これらのタイルには、関心のある情報がすべて含まれているわけではないため、最終的にはタイルの 50% を再度保存することになり、残りの画像は黒くなる可能性があります。処理されたものを同じ形式で保存することは、オーバーレイとして表示したいので、私にとって最も便利なアプローチのようです
中間ソリューションで編集
前に、numpy 配列から pyvips イメージを作成するのに 40 秒かかったと述べました。これの原因は、入力が転置された numpy 配列であったことです。転置操作自体は非常に高速ですが、以前と同じようにメモリに残っていたため、転置された形式で読み取るときに多くのキャッシュ ミスが発生したと思われます。
したがって、現在、次の行には 30 秒かかります (200MB のファイルを書き込むため)。
vips_img.tiffsave(filename, tile=True, compression='lzw', bigtiff=True, pyramid=True, Q=80)
これがより速くできればいいのですが、妥当なようです。
コード例
私の場合、タイルの約 15% のみが対象であり、前処理されます。ただし、これらは画像全体にあります。これをギガピクセル形式で保存したいと思います。これにより、openslide を使用して、便利なライブラリを使用して画像の一部を取得できるようになります。この例では、黒/情報の割合をシミュレートするために ~15% のランダム データを生成しました。この例のパフォーマンスは、データが画像全体に分散している実際の実装と似ています。
import numpy as np
import pyvips
def numpy2vips(a):
dtype_to_format = {
'uint8': 'uchar',
'int8': 'char',
'uint16': 'ushort',
'int16': 'short',
'uint32': 'uint',
'int32': 'int',
'float32': 'float',
'float64': 'double',
'complex64': 'complex',
'complex128': 'dpcomplex',
}
height, width, bands = a.shape
linear = a.reshape(width * height * bands)
vi = pyvips.Image.new_from_memory(linear.data, width, height, bands,
dtype_to_format[str(a.dtype)])
return vi
left = np.random.randint(0, 256, (7500, 45000), np.uint8)
right = np.zeros((50000, 45000), np.uint8)
img = np.vstack((left, right))
vips_img = numpy2vips(np.expand_dims(img, axis=2))
start = time.time()
vips_img.tiffsave("t1", tile=True, compression='deflate', bigtiff=True, pyramid=True)
print("pyramid deflate took: ", time.time() - start)
start = time.time()
vips_img.tiffsave("t2", tile=True, compression='lzw', bigtiff=True, pyramid=True)
print("pyramid lzw took: ", time.time() - start)
start = time.time()
vips_img.tiffsave("t3", tile=True, compression='jpeg', bigtiff=True, pyramid=True)
print("pyramid jpg took: ", time.time() - start)
start = time.time()
vips_img.dzsave("t4", tile_size=256, depth='one', overlap=0, suffix='.jpg[Q=75]')
print("dzi took: ", time.time() - start)
出力
pyramid deflate took: 32.69183301925659
pyramid lzw took: 32.10764741897583
pyramid jpg took: 59.79427194595337
数分以上かかっていたので、dzsave が完了するのを待ちませんでした。