IAM

OPENSOURCEFAN STUDYING
STUDYINGCOMPUTERSCIENCEANDMATH COMPUTERSCIENCE

Check out the latest superpixel benchmark — Superpixel Benchmark (2016) — and let me know your opinion! @david_stutz
19thAPRIL2017

SNIPPET

C++

How to read and write Eigen tensors from and to HDF5 files using C++.

main.cpp
#include <iostream>
#include <unsupported/Eigen/CXX11/Tensor>
#include <H5Cpp.h>

/** \brief Read a Hdf5 file into an Eigen tensor.
 * \param[in] filepath path to file
 * \param[out] dense Eigen tensor
 * \return success
 */
template<int RANK>
bool read_hdf5(const std::string filepath, Eigen::Tensor<float, RANK, Eigen::RowMajor>& dense) {
    try
    {
        H5::H5File file(filepath, H5F_ACC_RDONLY);
        H5::DataSet dataset = file.openDataSet("tensor");

        /*
         * Get filespace for rank and dimension
         */
        H5::DataSpace filespace = dataset.getSpace();

        /*
         * Get number of dimensions in the file dataspace
         */
        size_t rank = filespace.getSimpleExtentNdims();

        if (rank != RANK) {
          std::cout << "[Error] invalid rank read: " << rank << std::endl;
          exit(1);
        }

        /*
         * Get and print the dimension sizes of the file dataspace
         */
        hsize_t dimsf[rank];
        filespace.getSimpleExtentDims(dimsf);

        //std::cout << "Read " << filepath << ": ";
        //for (int i = 0; i < RANK; ++i) {
        //  std::cout << dimsf[i] << " ";
        //}
        //std::cout << std::endl;

        /*
         * Define the memory space to read dataset.
         */
        H5::DataSpace mspace(rank, dimsf);

        //size_t buffer_size = 1;
        //for (int i = 0; i < RANK; ++i) {
        //  buffer_size *= dimsf[i];
        //}

        float* buffer = static_cast<float*>(dense.data());
        dataset.read(buffer, H5::PredType::NATIVE_FLOAT, mspace, filespace);

        //for (int i = 0; i < buffer_size; ++i) {
        //  std::cout << buffer[i] << std::endl;
        //}
    }

    // catch failure caused by the H5File operations
    catch(H5::FileIException error)
    {
        error.printError();
        return false;
    }

    // catch failure caused by the DataSet operations
    catch(H5::DataSetIException error)
    {
        error.printError();
        return false;
    }

    // catch failure caused by the DataSpace operations
    catch(H5::DataSpaceIException error)
    {
        error.printError();
        return false;
    }
    
    return true;
}

/** \brief Write the given set of volumes to h5 file.
 * \param[in] filepath h5 file to write
 * \param[in] dense volume data
 */
template<int RANK>
bool write_hdf5(const std::string filepath, Eigen::Tensor<float, RANK, Eigen::RowMajor>& dense)
{
    try
    {
        /*
         * Turn off the auto-printing when failure occurs so that we can
         * handle the errors appropriately
         */
        H5::Exception::dontPrint();

        /*
         * Create a new file using H5F_ACC_TRUNC access,
         * default file creation properties, and default file
         * access properties.
         */
        H5::H5File file(filepath, H5F_ACC_TRUNC);

        /*
         * Define the size of the array and create the data space for fixed
         * size dataset.
         */
        hsize_t dimsf[RANK];
        for (int i = 0; i < RANK; ++i) {
          dimsf[i] = dense.dimension(i);
        }

        H5::DataSpace dataspace(RANK, dimsf);

        /*
         * Define datatype for the data in the file.
         * We will store little endian INT numbers.
         */
        H5::IntType datatype(H5::PredType::NATIVE_FLOAT);
        datatype.setOrder(H5T_ORDER_LE);

        /*
         * Create a new dataset within the file using defined dataspace and
         * datatype and default dataset creation properties.
         */
        H5::DataSet dataset = file.createDataSet("tensor", datatype, dataspace);

        /*
         * Write the data to the dataset using default memory space, file
         * space, and transfer properties.
         */
        float* data = static_cast<float*>(dense.data());
        dataset.write(data, H5::PredType::NATIVE_FLOAT);
    }  // end of try block

    // catch failure caused by the H5File operations
    catch(H5::FileIException error)
    {
        error.printError();
        return false;
    }

    // catch failure caused by the DataSet operations
    catch(H5::DataSetIException error)
    {
        error.printError();
        return false;
    }

    // catch failure caused by the DataSpace operations
    catch(H5::DataSpaceIException error)
    {
        error.printError();
        return false;
    }

    // catch failure caused by the DataSpace operations
    catch(H5::DataTypeIException error)
    {
        error.printError();
        return false;
    }

    return true;
}

int main(int argc, char** argv)
{
    Eigen::Tensor<float, 3, Eigen::RowMajor> write_tensor(2, 2, 2);
    for (int h = 0; h < write_tensor.dimension(0); ++h)
    {
        std::cout << "height " << h << std::endl;
        for (int w = 0; w < write_tensor.dimension(1); ++w)
        {
            for (int d = 0; d < write_tensor.dimension(2); ++d)
            {
                write_tensor(h, w, d) = (h + 1)*(w + 1)*(d + 1);
                std::cout << write_tensor(h, w, d) << " ";
            }
            
            std::cout << std::endl;
        }
    }
    
    write_hdf5<3>("test.h5", write_tensor);
    Eigen::Tensor<float, 3, Eigen::RowMajor> read_tensor(2, 2, 2);
    read_hdf5<3>("test.h5", read_tensor);
    
    for (int h = 0; h < read_tensor.dimension(0); ++h)
    {
        std::cout << "height " << h << std::endl;
        for (int w = 0; w < read_tensor.dimension(1); ++w)
        {
            for (int d = 0; d < read_tensor.dimension(2); ++d)
            {
                std::cout << read_tensor(h, w, d) << " ";
            }
            
            std::cout << std::endl;
        }
    }
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.2)
project(voxelize_cuboids)

set(CMAKE_CXX_FLAGS "--std=gnu++11 ${CMAKE_CXX_FLAGS}")

find_package(HDF5 COMPONENTS C CXX HL REQUIRED)
find_package(Eigen3 REQUIRED)

message("Eigen3: ${EIGEN3_INCLUDE_DIR}")

include_directories(
  ${HDF5_INCLUDE_DIRS}
  ${EIGEN3_INCLUDE_DIR}
)
add_executable(main main.cpp)
target_link_libraries(main
  ${HDF5_CXX_LIBRARIES}
)

What is your opinion on the code snippet? Is it working? Let me know your thoughts in the comments below or using the following platforms: