我正在處理數百個大型高解析度 .tif 影像,這些影像在 Python 中讀取時需要占用大量記憶體。幸運的是,我通常可以通過在加載這些影像后對其進行下采樣來處理這些影像的低解析度版本。我想知道是否有一種方法可以只將影像的一部分而不是整個影像讀入記憶體來提高讀取速度。
下面的代碼顯示了我想要的示例,但是,這仍然會在回傳下采樣陣列之前將整個影像讀入記憶體。是否可以僅將每第 n 個像素值讀取到記憶體中以提高讀取速度?
from tifffile import imread
def standardOpen(f):
im = imread(f)
return(im)
def scaledOpen(f):
im = imread(f)[::,::4,::4]
return(im)
f_path = '/file_name.tif'
im = standardOpen(f_path)
print(im.shape)
>>(88, 2048, 2048)
im_scaled = scaledOpen(f_path)
print(im_scaled.shape)
>>(88, 512, 512)
編輯:我已將示例影像上傳到保管箱:https ://www.dropbox.com/s/xkm0bzudcv2sw5d/S000_t000002_V000_R0000_X000_Y000_C02_I1_D0_P00101.tif?dl=0
This image is 101 slice of 2048x2048 pixels. When I read it using tifffile.imread(image_path) I get a numpy array of shape (101, 2048, 2048)
uj5u.com熱心網友回復:
示例檔案S000_t000002_V000_R0000_X000_Y000_C02_I1_D0_P00101.tif是一個多頁 TIFF。每頁中的影像資料未壓縮存盤在一個條帶中。為了加速從這種特定型別的 TIFF 檔案中讀取切片資料,記憶體映射幀資料并將切片資料復制到預先分配的陣列中,同時遍歷檔案中的頁面。除非想要保留噪聲特性,否則通常最好使用高階濾波進行下采樣,例如使用 OpenCV 進行插值:
import numpy
import tifffile
import cv2 # OpenCV for fast interpolation
filename = 'S000_t000002_V000_R0000_X000_Y000_C02_I1_D0_P00101.tif'
with tifffile.Timer():
stack = tifffile.imread(filename)[:, ::4, ::4].copy()
with tifffile.Timer():
with tifffile.TiffFile(filename) as tif:
page = tif.pages[0]
shape = len(tif.pages), page.imagelength // 4, page.imagewidth // 4
stack = numpy.empty(shape, page.dtype)
for i, page in enumerate(tif.pages):
stack[i] = page.asarray(out='memmap')[::4, ::4]
# # better use interpolation instead:
# stack[i] = cv2.resize(
# page.asarray(),
# dsize=(shape[2], shape[1]),
# interpolation=cv2.INTER_LINEAR,
# )
我會避免這種微優化以提高速度。示例檔案中的影像資料只有約 800 MB,可以輕松放入大多數計算機的 RAM 中。
uj5u.com熱心網友回復:
我用pyvips做了一些實驗來模擬你的作業流程。
首先,我創建了一個尺寸為 60,000 x 40,000 像素的 6.7GB TIF。然后我加載它pyvips并縮小它以適應 1,000 x 1,000 矩形并保存結果:
#!/usr/bin/env python3
import pyvips
# Resize to no more than 1000x1000 pixels
out = pyvips.Image.thumbnail('big.tif', 1000)
# Save with LZW compression
out.tiffsave('result.tif', tile=True, compression='lzw')
這花費了 3 秒并使用了 440MB 的 RAM - 包括 Python 解釋器。然后你可以把它變成一個像這樣的常規 Numpy 陣列——它實際上只是一行代碼——只有一些映射:
# map vips formats to np dtypes
format_to_dtype = {
'uchar': np.uint8,
'char': np.int8,
'ushort': np.uint16,
'short': np.int16,
'uint': np.uint32,
'int': np.int32,
'float': np.float32,
'double': np.float64,
'complex': np.complex64,
'dpcomplex': np.complex128,
}
# vips image to numpy array
def vips2numpy(vi):
return np.ndarray(buffer=vi.write_to_memory(),
dtype=format_to_dtype[vi.format],
shape=[vi.height, vi.width, vi.bands])
# Do actual conversion from vips image to Numpy array
na = vips2numpy(out)
您可以在終端中執行相同的操作,順便說一下vipsthumbnail:
vipsthumbnail big.tif result.tif --size=1000 --vips-leak
memory: high-water mark 372.78 MB
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/452770.html
標籤:python image image-processing tiff
