การใช้งาน HDF5 เบื้องต้น

Hierarchical Data Format (HDF) [1] ถูกออกแบบมาเพื่อใช้ในการจัดเก็บข้อมูลขนาดใหญ่ สนับสนุนโครงสร้าไฟล์ข้อมูลแบบ Hierarchical  โดยแบบโครงสร้างออกเป็นสองระดับคือ

  • Dataset  ใช้จัดเก็บ multi-dimensional array และข้อมูลต้องเป็น homogeneous data type 
  • Groups เป็น data container ที่บรรจุได้ทั้ง datasets หรือ group

H5Py  [2][3] คือ python package ที่ใช้ interface กับ HDF5  ที่ทำงานในระดับ low level สามารถใช้งานร่วมกับ Numpy เป็นอย่างดี การติดตั้งทำได้สองทาง คือ

python3 -m pip install h5py

กรณีที่ใช้ conda

conda install h5py



การบันทึกข้อมูล 1 dataset

import numpy as np
import h5py

#create 2 dimensiondummy data
dummy_data = np.random.randint(5,size=(10,10))

#create hdf file and store data on it
with h5py.File('random.hdf5', 'w') as f:
 dset = f.create_dataset("demo_dataset", data=dummy_data)



ข้อมูลถูกบันทึกลงไฟล์ด้วย key ชื่อ "demo_dataset" ซึ่งจะถูกใช้อ้างอิงในการอ่านข้อมูล

import numpy as np
import h5py

with h5py.File('random.hdf5', 'r') as f:
 data = f['demo_dataset']
 print(data[:1,:])


ในกรณีที่ไม่ทราบว่าไฟล์ข้อมูลมี key อะไรบ้าง สามารถค้นหาด้วย function keys()

import numpy as np
import h5py

with h5py.File('random.hdf5', 'r') as f:
        for key in f.keys():
        print(key)


การบันทึกข้อมูลมากกว่า 1 dataset

import numpy as np
import h5py

#create dummy data
dummy_data_1 = np.random.randint(5,size=(10,10))
dummy_data_2 = np.random.randint(10,size=(5,5))

#create hdf file and store data on them
with h5py.File('multiple_dataset.hdf5', 'w') as f:
 dset1 = f.create_dataset("dataset_1", data=dummy_data_1)
 dset2 = f.create_dataset("dataset_2", data=dummy_data_2)




import numpy as np
import h5py

with h5py.File('multiple_dataset.hdf5', 'r') as f:
        data_1 = f['dataset_1']
        data_2 = f['dataset_2']
 print(data1)
 print(data2)


การกำหนด data type 
ดูเรื่อง data type จาก http://docs.h5py.org/en/latest/faq.html  และ https://docs.scipy.org/doc/numpy/reference/generated/numpy.dtype.html  h5py ใช้ data type และสัญญลักษณ์เดียวกับ Numpy

import numpy as np
import h5py

#create dummy data
dummy_data_1 = np.random.randint(5,size=(10,10))
dummy_data_2 = np.random.randint(10,size=(5,5))

#create hdf file and store data on them
with h5py.File('multiple_dataset.hdf5', 'w') as f:
 dset1 = f.create_dataset("dataset_1", data=dummy_data_1,dtype=np.int8)
 dset2 = f.create_dataset("dataset_2", data=dummy_data_2,dtype=np.int8)



การกำหนด Group 
ถ้าเทียบ dataset เป็นไฟล์ข้อมูลแล้ว group ก็เหมือนกับ folder หรือ directory ที่เก็บไฟล์ข้อมูลที่สอดคล้องกัน


เขียนข้อมูลลงไฟล์


import numpy as np
import h5py

#create dummy data
dummy_data_1 = np.random.randint(5,size=(10,10),dtype=np.int8)
dummy_data_2 = np.random.randint(10,size=(5,5),dtype=np.int8)

#create hdf file and store data on them
with h5py.File('group_demo.hdf5', 'w') as f:
 g10 = f.create_group("group_10")
 g11 = g10.create_group("group_11")
 data_10 = g10.create_dataset('data_10',data=dummy_data_1)
 data_11 = g11.create_dataset('data_11',data=dummy_data_2)


การอ่านข้อมูลจากไฟล์

import numpy as np
import h5py

#create hdf file and store data on them
with h5py.File('group_demo.hdf5', 'r') as f:
 data_10 = f['group_10/data_10']
 data_11 = f['group_10/group_11/data_11']
        print(data_10[0])
        print(data_11[0])


หากไม่ทราบ key หรือโครงสร้าง

import numpy as np
import h5py

def get_node_name(name):
 print(name)

#create hdf file and store data on them
with h5py.File('group_demo.hdf5', 'r') as f:
      f.visit(get_node_name)


การ resize  dataset
ในกรณีที่ไม่สามารถกำหนดได้ว่าจะต้องการบันทึกข้อมูลจำนวนมากน้อยเท่าไหร่ h5py อนุญาตให้ทำการปรับขนาดของ dataset เพื่อเพิ่มจำนวน element ได้ (append data)


import numpy as np
import h5py
from PIL import Image

class ROI() :
 def __init__(self,x1,y1,x2,y2):
  self.x1 = x1
  self.y1 = y1
  self.x2 = x2
  self.y2 = y2
  
 def get_value(self):
  return (self.x1,self.y1,self.x2,self.y2)

def parse_pts(pts_file):
 coords=[]
 with open(pts_file,"r") as f : 
  i = 1
  for line in f :
   if i < 3 :
    i = i + 1
    continue
   if "{" in line or "}" in line :
    continue 
   #split coordinate 
   p = line.split(" ")
   x = float(p[0].strip())
   y = float(p[1].strip())
   coords.append([x,y]) 
 return np.array(coords)

def crop_face(coords,img_file,pad=5):
 img = Image.open(img_file)
 min_x = img.size[0]
 min_y = img.size[1]
 max_x = 0. 
 max_y = 0. 

 for coord in coords :
  if coord[0] < min_x :
   min_x  = coord[0]
  if coord[1] < min_y :
   min_y = coord[1]
  if coord[0] > max_x :
   max_x = coord[0]
  if coord[1] > max_y :
   max_y = coord[1]
 min_x -= pad
 min_y -= pad
 max_x += pad
 max_y += pad
 w = max_x - min_x
 h = max_y - min_y

 if w > h :
  dif = w - h
  #expand y axis
  min_y -= dif/2
  max_y += dif/2
 if w < h :
  dif = h - w
  #expand x axis
  min_x -= dif/2
  max_x += dif/2
 #crop_area = (min_x , min_y , max_x  ,max_y )
 crop_area = ROI(min_x , min_y,max_x ,max_y  ) 
 #face = img.crop(crop_area) 
 face = img.crop(crop_area.get_value()) 
 rs_face = face.resize((128,128),Image.ANTIALIAS)
 
 return np.array(rs_face)

def write_data(img_file,pts_file,mode='w'):
 land_mark = parse_pts(pts_file)
 face_img = crop_face(land_mark,img_file,pad=5)

 if mode=='w':
  with h5py.File('resizable_demo.hdf5', 'w') as f:
   im = f.create_dataset("image",(1,128,128,3),maxshape=(5000,128,128,3 ),dtype=np.uint8)
   lb = f.create_dataset("labeled",(1,68,2),maxshape=(5000,68,2 ))
   im[-1] = face_img
   lb[-1] = land_mark
 elif mode == 'a':
  with h5py.File('resizable_demo.hdf5', 'a') as f:
   img_ds = f['image']
   lb_ds = f['labeled']
   img_ds.resize((img_ds.shape[0]+1,128,128,3))
   lb_ds.resize((lb_ds.shape[0]+1,68,2))
   img_ds[-1] = face_img
   lb_ds[-1] = land_mark

def read_image():
 with h5py.File('resizable_demo.hdf5', 'r') as f:
  img = f['image']
  for i in range(img.shape[0]):
   im = Image.fromarray(img[i].astype(np.uint8),'RGB')
   im.show()
 
if __name__ == "__main__":
 img_file = "indoor_001.png"
 pts_file = "indoor_001.pts"
 write_data(img_file,pts_file,mode='a')
 read_image()


 





 [1] https://portal.hdfgroup.org/display/knowledge/What+is+HDF5
[2] https://www.h5py.org/
[3] http://docs.h5py.org/en/stable/

Previous
Next Post »