как создать непрозрачный набор данных с заданным тегом в h5py

#python #hdf5 #h5py

#python #hdf5 #h5py

Вопрос:

Я пытаюсь воссоздать файл HDF5, используя h5py который хранит двоичные данные (например, сжатые изображения в формате JPEG) в виде OPAQUE набора данных, используя тег для хранения типа MIME, чтобы их можно было легко декодировать позже.

Единственный способ, которым я смог решить эту проблему, — использовать низкоуровневый API, но было бы неплохо, если бы было что-то более высокого уровня!

(Я публикую свое решение в качестве ответа в надежде, что оно будет полезно другим людям, поскольку я изо всех сил пытался найти много примеров подобных действий)

Комментарии:

1. Мне любопытно — почему вы сохраняете как непрозрачный набор данных? Примеры данных изображений, которые я видел, сохраняют изображения как np.array различных типов и форм.

2. @kcw78 кодировка jpeg предназначена для экономии места, и непрозрачный тип данных показался подходящим. ожидается архивирование ~ 100 тыс. файлов, каждый файл содержит ~ 500 изображений соответствующую информацию о камере / эксперименте.

3. возможно, @kcw78 неправильно истолковал; формат был разработан для написания кода на C (который будет создавать большинство файлов) Я хотел, чтобы какой-нибудь код на python делал то же самое для тестирования, и опубликовал вопрос, потому что он показался более неудобным, чем я ожидал

Ответ №1:

Более простым способом решить эту проблему и избежать низкоуровневого API может быть HDFql. В Python с использованием HDFql это можно решить следующим образом:

 # import HDFql package
import HDFql

# get size (in bytes) of file 'input.jpeg'
HDFql.execute("SHOW FILE SIZE input.jpeg")

# move cursor to first element
HDFql.cursor_first()

# get cursor element and assign it to variable
input_size = HDFql.cursor_get_unsigned_bigint()

# create HDF5 file 'output.h5'
HDFql.execute("CREATE FILE output.h5")

# create dataset 'mydata' (in file 'output.h5') of data type opaque with a tag 'image/jpeg' and storing the content of file 'input.jpeg'
HDFql.execute("CREATE DATASET output.h5 mydata AS OPAQUE(%d) TAG image/jpeg VALUES FROM BINARY FILE input.jpeg" % input_size)
  

Комментарии:

1. раньше не слышал о HDFql, выглядит интересно! есть ли способ сделать это без использования локальной файловой системы? AFAICT я мог бы использовать variable_transient_register

2. @SamMason: не уверен, что вы подразумеваете под локальной файловой системой. Что касается использования variable_transient_register , да, вы можете использовать его, если у вас есть массив NumPy, заполненный содержимым, которое вы хотите сохранить в dataset mydata . Затем вы могли бы сделать следующее вместо этого: HDFql.execute("CREATE DATASET output.h5 mydata AS OPAQUE(%d) TAG image/jpeg VALUES FROM MEMORY %d" % (input_size, HDFql.variable_transient_register(my_numpy_array))) .

3. да, извините за двусмысленность, вы правильно интерпретировали. допустимо ли его передавать bytes ? Я изо всех сил пытаюсь найти репозиторий (например, github) для HDFql, чтобы я мог проверить себя, какие-либо указатели?

Ответ №2:

Единственный способ, который я нашел для этого, — использовать низкоуровневый API. Это означает, что нам нужно самим настроить типы данных и пространства данных, прежде чем мы сможем создать набор данных и записать данные.

 import h5py
import numpy as np

# get the binary data in
with open('input.jpeg', 'rb') as fd:
  data = fd.read()

# set up an HDF5 type appropriately sized for our data
dtype = h5py.h5t.create(h5py.h5t.OPAQUE, len(data))
dtype.set_tag(b'image/jpeg')

# set up a simple scalar HDF5 data space
space = h5py.h5s.create(h5py.h5s.SCALAR)

with h5py.File('output.h5', 'w') as root:
  ds = h5py.h5d.create(root.id, b'mydata', dtype, space)

  ds.write(space, space, np.frombuffer(data, dtype=np.uint8), dtype)
  

это работает для меня, предоставляя h5dump -H output.h5 :

 HDF5 "output.h5" {
GROUP "/" {
   DATASET "mydata" {
      DATATYPE  H5T_OPAQUE {
         OPAQUE_TAG "image/jpeg";
      }
      DATASPACE  SCALAR
   }
}
}
  

но было бы неплохо, если бы это было немного проще!