如何仅将 TIFF 图像堆栈中的选定帧加载到内存中,而不必加载所有内容

How to load only chosen frames from TIFF image stack into memory, without having to load everything

提问人:TheEponymousProgrammer 提问时间:11/2/2023 最后编辑:TheEponymousProgrammer 更新时间:11/21/2023 访问量:53

问:

我正在处理大型 TIFF 图像堆栈,这些堆栈相当于 的 NumPy 数组。我有兴趣编写一个函数,该函数允许我从数组中快速选择选定的切片进行绘图和比较,以查看图像的演变情况。但是,我所知道的大多数方法都涉及必须首先将整个内容加载到内存中,而我的桌面无法处理。(300, 2048, 2048)n

您能否建议我如何优化我的代码,以便快速识别图像堆栈中要加载和绘制的数组切片,而无需先将整个堆栈加载到内存中?

工作尝试:
下面@Malcolm提供的建议非常有效,使我能够加载图像堆栈元数据和单个切片,而无需将整个堆栈加载到内存中。参数 in 允许加载图像堆栈的各个切片,而 class(?) 允许在不加载实际数组的情况下加载文件元数据。
key=io.imread()TiffFile()

# Import relevant modules
import matplotlib.pyplot as plt
from tifffile import TiffFile
from skimage import io


# Load file
file = "example.tiff"  # Array of dimensions (300, 2048, 2048)
stk = TiffFile(file)  # Load file metadata

# Check number of figures to plot in subplot
frm_sep = 10  # Frames between images
num_frm = 6

# Create figure and subplots
fig, axs = plt.subplots(nrows=1, ncols=num_frm, sharey=True)
for i in range(num_frm):
    # Load image reference image to adjust intensities
    if i == 0:
        img_ref = io.imread(fft, key=0)
        v_max=np.percentile(np.ravel(img_ref), 99)
    else: pass
    
    # Plot subplot
    ax = axs[i]
    ax.imshow(
        io.imread(fft, key=(i * frm_sep)),
        vmin=0,
        vmax=v_max
    )
    ax.set_title(f"Frame {i * frm_sep}")

我最初的尝试:

# Import relevant modules
from skimage import io
import dask.array as da
import matplotlib.pyplot as plt

# Load file
file = "example.tiff"  # Array dimensions of (300,2048, 2048)
img_stk = da.from_array(io.imread(file), chunks=(1, 512, 512)  # Tried using dask array for lazy loading

# Load image stack to array
frm_sep = 10  # Frames separating images
num_frm = 6  # Number of frames to show

# Create figure to plot these chosen frames
fig, axs = plt.subplots(nrows=1, ncols=num_frm, sharey=True)
for i in range(num_frm):
    # Display on subplot
    axs[i].imshow(img_stk[i * frm_sep],
                  vmin=0,
                  vmax=np.percentile(np.ravel(img_stk[0]), 99)
                  )
    # Set subplot title
    axs[i].set_title(f"Frame {i * frm_sep}")

代码有效,但每次加载图像堆栈需要几分钟,这对我来说表明我正在加载整个堆栈而不是我选择的切片。

python matplotlib 多维数组 延迟加载 scikit-image

评论

2赞 Malcolm 11/2/2023
该调用肯定会读取整个文件。从 skimage 文档 (scikit-image.org/docs/stable/api/skimage.io.html) 来看,它似乎使用 tiffile 包来加载 TIFF 图像。从 tiffile 包文档 (github.com/cgohlke/tifffile/#examples) 来看,该包似乎支持您想要的选项。由于 skimage.io 文档表明 imread 需要,我会尝试使用 .io.imread(file)key=...**plugin_argsio.imread(file, key=...)
0赞 Malcolm 11/2/2023
请注意,读取文件以查找请求的图像仍可能需要一些时间。检查进程的内存使用情况可能是衡量整个映像堆栈是否被加载到内存中的更好方法。
2赞 Malcolm 11/2/2023
另一种选择是直接使用 tifffile。从我之前引用的示例页面下面的几个示例中,它表明该类允许您一次读取“页面”中的 TIFF 文件。tifffile.TiffFile
0赞 TheEponymousProgrammer 11/21/2023
您好,@Malcolm,对于延迟回复表示歉意,并感谢您的有用建议!我可以确认它完全适用于此脚本的目的。我还查看了您建议的命令,并且可以确认它允许我读取文件元数据而无需将文件加载到内存中。我已经使用优化版本编辑了我的原始代码块。非常感谢!io.imread(file, key=...)tifffile.TiffFile

答: 暂无答案