Table of Contents

h5py

Introduction

The h5py project provides an Python interface to the HDF5 file format, therefore provides an Python interface to SPD files independent of SPDLib.

Initial testing suggests h5py is at least 10 times faster than the SPDLib Python bindings for simple read tasks. Further development to link pulses and points in an object oriented way and to write SPD files is required and ongoing.

Examples

Example functions for opening an SPD file, reading the SPD header, and reading rows (defined by the spatial index) of the SPD pulse and point data tables are shown below.

import h5py
import numpy as np


def openSPDFile(infile):
    """
    Open the SPD file
    """
    f = h5py.File(infile, 'r')
    return f    


def readSPDHeader(f):
    """
    Read the SPD header
    """
    dictn = {}
    for name,obj in f['HEADER'].items():
        if obj[()].size == 1:
            dictn[name] = obj[0]
        else:
            dictn[name] = obj[()]
    return dictn
    
    
def readSPDPulsesRow(f,row,selection=None):
    """
    Read a row of pulse data
    """
    cnt = f['INDEX']['PLS_PER_BIN'][row]
    if cnt.any():
        idx = f['INDEX']['BIN_OFFSETS'][row]
        if selection is None:
            pData = f['DATA']['PULSES'][idx[0]:idx[-1]+cnt[-1]]
        else:
            pData = f['DATA']['PULSES'][idx[0]:idx[-1]+cnt[-1],selection]
        return pData.view(np.recarray)
    else:
        return None


def readSPDPointsRow(f,row,fieldName=None):
    """
    Read a row of point data
    """
    cnt = f['INDEX']['PLS_PER_BIN'][row]
    if cnt.any():
        idx = f['INDEX']['BIN_OFFSETS'][row]       
        pData = f['DATA']['PULSES'][idx[0]:idx[-1]+cnt[-1],'PTS_START_IDX','NUMBER_OF_RETURNS']
        start = pData['PTS_START_IDX'][0]
        finish = pData['PTS_START_IDX'][-1] + pData['NUMBER_OF_RETURNS'][-1]
        if fieldName is None:
            points = f['DATA']['POINTS'][start:finish]
        else:
            points = f['DATA']['POINTS'][start:finish,fieldName]
        return points.view(np.recarray)
    else:
        return None


def readSPDXYZRow(f,row,returnType=None):
    """
    Read a row of XYZ point data
    ReturnType:
        1 = first returns
        2 = middle returns
        3 = last returns
        otherwise all returns
    """
    cnt = f['INDEX']['PLS_PER_BIN'][row]
    if cnt.any():
        idx = f['INDEX']['BIN_OFFSETS'][row]       
        pData = f['DATA']['PULSES'][idx[0]:idx[-1]+cnt[-1],'PTS_START_IDX','NUMBER_OF_RETURNS']
        start = pData['PTS_START_IDX'][0]
        finish = pData['PTS_START_IDX'][-1] + pData['NUMBER_OF_RETURNS'][-1]
        points = f['DATA']['POINTS'][start:finish,'X','Y','Z']
        if returnType == 1:
            idx = pData['PTS_START_IDX'] - pData['PTS_START_IDX'][0]
            mask = pData['NUMBER_OF_RETURNS'] > 0
            points = points[idx[mask]]
        elif returnType == 2:
            idx = np.ones(points.size)
            mask = pData['NUMBER_OF_RETURNS'] > 0
            idx[pData['PTS_START_IDX'][mask] - pData['PTS_START_IDX'][mask][0]] = 0
            idx[pData['PTS_START_IDX'][mask] - pData['PTS_START_IDX'][mask][0] + pData['NUMBER_OF_RETURNS'] - 1] = 0
            points = points[idx > 0]
        elif returnType == 3:
            idx = pData['PTS_START_IDX'] - pData['PTS_START_IDX'][0] + pData['NUMBER_OF_RETURNS'] - 1
            mask = pData['NUMBER_OF_RETURNS'] > 0
            points = points[idx[mask]]
        return points.view(np.recarray)
    else:
        return None

Navigation