Как мне заполнить n-мерный массив в HDF5 из одномерного источника?

У меня есть массив с несколькими измерениями (x, y, каналы, z, временные шаги). Однако необработанные данные хранятся в изображении TIFF как единый стек из (x, y, каналов) с кадрами временных шагов z *.

Наконец, функция Image.getdata () Pillow возвращает объект, подобный одномерному массиву, который необходимо изменить.

Как лучше всего прочитать это в HDF5, если набор данных слишком велик для размещения в памяти? Можно ли изменить форму массива после того, как он был записан в HDF5, или записать одномерные данные таким образом, чтобы они автоматически заполняли массив (т. Е. Записываются с переменным x, самым быстрым по y и т. Д.) Обновить : что-то вроде numpy.ndarray.flat было бы идеально.

Вот что я пробовал до сих пор (img - это PIL.Image, dset - это набор данных h5py):

1) Чтение отдельных кадров. Этот метод слишком медленный, так как он занимает ~ 20 минут для 300 МБ на 1000 кадров. Большую часть времени тратится на dset [] = вызов.

for i in range(0, img_layers):
  img.seek(i)
  a = numpy.array(img.getdata(), dtype=dtype) # a.shape = (sx * sz * channels,)
  a.resize(sx, sy, channels)
  z = i % sz
  frame = i // sz
  dset[..., z, frame] = a

2) Неполное: чтение по частям. Это намного быстрее (2 минуты для того же набора данных), но у меня это работает только для 4D-изображения (sx, sy, каналы, временные шаги), и мне нужно дополнительное измерение для z-срезов:

chunk_bits = 256 * 1000**2 # 256MB
frame_bits = depth_bits[dtype] * sx * sy * channels
chunk_frames = chunk_bits // frame_bits
a = numpy.zeros((sx, sy, channels, chunk_frames), dtype=dtype)
for i in range(0, layers):
  img.seek(i)
  temp = numpy.array(img.getdata(), dtype=dtype)
  temp.resize(sx, sy, channels)
  a[..., i % chunk_frames] = temp
  if (i + 1) % chunk_frames == 0 or i == (layers - 1):
    chunk = i // chunk_frames
    dset[..., chunk * chunk_frames : i + 1] = a[..., : i % chunk_frames + 1

person kai    schedule 15.11.2013    source источник


Ответы (1)


Вариант 1 был правильным ответом. Однако имеет большое значение, какой размер изменяется быстрее всего:

~ 15 минут:

for i in range(0, img_layers):
  img.seek(i)
  a = numpy.array(img.getdata(), dtype=dtype)
  a.resize(sx, sy, channels)
  z = i % sz
  frame = i // sz
  dset[..., z, frame] = a # Majority of time in this call

~ 3 минуты:

for i in range(0, img_layers):
  img.seek(i)
  a = numpy.array(img.getdata(), dtype=dtype) # Majority of time in this call
  a.resize(sx, sy, channels)
  z = i % sz
  frame = i // sz
  dset[frame, z, ...] = a

Для быстрого чтения этих данных самый быстро меняющийся индекс должен быть ПОСЛЕДНИМ, а не первым.

person kai    schedule 19.11.2013