加速将数百个3D numpy数组写入hdf5文件

时间:2016-01-11 05:11:16

标签: python numpy h5py joblib

我正在处理的应用程序将包含多个图像(视野),平面(Z)和荧光通道的专有tiff文件格式(Nikon nd2文件)转换为numpy数组,然后保存在HDF5文件中。通常,典型数据集具有50个视场(fov),每个视场具有5个通道,每个通道具有40个z平面。整个文件大约为6 Gb。

这是我写的代码:

步骤:

0)导入所有必需的库

import nd2reader as nd2
from matplotlib import pyplot as plt
import numpy as np
import h5py as h5
import itertools
import ast
import glob as glob
from joblib import Parallel, delayed
import time

1)运行nd2文件转换的功能。 转换为numpy数组是使用nd2reader和python程序完成的,并且很快。 为了减少循环次数并使用列表理解,我制作了一个元组列表,每个元组包含通道和fov 例: [(' DAPI',0), (' DAPI',1)] 其中DAPI是通道,fov是数字。

注意:实验频道列表是一个包含字典的文件,而不是将频道(密钥)与感兴趣的基因(值)相匹配。

def ConvertND2File(ND2file):

    ChannelFileName=ND2file.replace('.nd2','ChannelsInfo.txt')


    # Read the file with the channels and raise an error if the file is missing
    try:
        ExperimentChannelList = ast.literal_eval(open(ChannelFileName).read())
    except IOError:
        print("The file:", ChannelFileName, "with the channels dictionary is missing")
        raise

    DataFileName=ND2file.replace('.nd2','.h5')
    with h5.File(DataFileName, 'w') as DataFile:
        ImgRef=nd2.Nd2(ND2file)
        Channels_Fields=itertools.product(ImgRef.channels,ImgRef.fields_of_view)

        # Create the empty array that will contain the 3D image
        ImgStack=np.empty([len(ImgRef.z_levels),ImgRef.height,ImgRef.width])

        # Use list comprehension to save the 3D arrays of the fov for each channel
        _=[SaveImg(DataFile,ImgRef,ExperimentChannelList,ImgStack,*x) for x in Channels_Fields]

2)将图像组合成3D阵列的功能,然后以HDF5文件写入。我用h5py。我生成后立即在磁盘上写下每个3D numpy数组。

def SaveImg(DataFile,ImgRef,ExperimentChannelList,ImgStack,*args):
        channel=args[0]
        fov=args[1]
        for idx,image in enumerate(ImgRef.select(channels=channel,z_levels=ImgRef.z_levels,fields_of_view=fov)):
            ImgStack[idx,:,:]=image
        gene=ExperimentChannelList[channel]
        ChannelGroup=DataFile.require_group(gene)
        FovDataSet=ChannelGroup.create_dataset(str(fov), data=ImgStack,dtype=np.float64,compression="gzip")

3)脚本和joblib的主体调用并行处理目录中的所有文件。

if __name__=='__main__':

    # Run the
    # Directory where ND2 file is stored (Ex. User/Data/)
    WorkingDirectory=input('Enter the directory with the files to process (ex. /User/):  ')
    #WorkingDirectory='/Users/simone/Box Sync/test/ND2conversion/'
    NumberOfProcesses=int(input('Enter the number of processes to use:  '))
    #NumberOfProcesses=2
    FileExt='nd2'
    # Iterator with the name of the files to process
    FilesIter=glob.iglob(WorkingDirectory+'*.'+FileExt)  

    now = time.time()
    Parallel(n_jobs=NumberOfProcesses,verbose=5)(delayed(ConvertND2File)(ND2file) for ND2file in FilesIter)
    print("Finished in", time.time()-now , "sec")

运行时间

转换两个5.9 Gb的文件的总时间 [Parallel(n_jobs = 2)]:完成2中的1 |经过时间:剩余7.4分钟:7.4分钟 [Parallel(n_jobs = 2)]:完成2中的2 |已过去:7.4分钟完成了 完成于444.8717038631439秒

问题:

我只是想知道是否有更好的方法来处理io到hdf5文件以加快转换速度,考虑到如果我想扩展这个过程我将无法将所有3D numpy保留在内存中数组(fov)然后在处理每个通道后写入它们。 谢谢!

0 个答案:

没有答案