Commit 7f7b0bc1 authored by KUANG Fangjun's avatar KUANG Fangjun Committed by Fangjun Kuang

Add attribute read/write supports to the HDF module.

The following data types for attributes are implemented:
 - int
 - double
 - cv::String
 - cv::InputArray
parent f03e415e
......@@ -103,13 +103,109 @@ public:
*/
CV_WRAP virtual bool hlexists( const String& label ) const = 0;
/* @overload */
/**
* Check whether a given attribute exits or not in the root group.
*
* @param atlabel the attribute name to be checked.
* @return true if the attribute exists, false otherwise.
*
* @sa atdelete, atwrite, atread
*/
CV_WRAP virtual bool atexists(const String& atlabel) const = 0;
/**
* Delete an attribute from the root group.
*
* @param atlabel the attribute to be deleted.
*
* @note CV_Error() is called if the given attribute does not exist. Use atexists()
* to check whether it exists or not beforehand.
*
* @sa atexists, atwrite, atread
*/
CV_WRAP virtual void atdelete(const String& atlabel) = 0;
/**
* Write an attribute inside the root group.
*
* @param value attribute value.
* @param atlabel attribute name.
*
* The following example demonstrates how to write an attribute of type cv::String:
*
* @snippet samples/read_write_attributes.cpp snippets_write_str
*
* @note CV_Error() is called if the given attribute already exists. Use atexists()
* to check whether it exists or not beforehand. And use atdelete() to delete
* it if it already exists.
*
* @sa atexists, atdelete, atread
*/
CV_WRAP virtual void atwrite(const int value, const String& atlabel) = 0;
/**
* Read an attribute from the root group.
*
* @param value address where the attribute is read into
* @param atlabel attribute name
*
* The following example demonstrates how to read an attribute of type cv::String:
*
* @snippet samples/read_write_attributes.cpp snippets_read_str
*
* @note The attribute MUST exist, otherwise CV_Error() is called. Use atexists()
* to check if it exists beforehand.
*
* @sa atexists, atdelete, atwrite
*/
CV_WRAP virtual void atread(int* value, const String& atlabel) = 0;
/** @overload */
CV_WRAP virtual void atwrite(const double value, const String& atlabel) = 0;
/** @overload */
CV_WRAP virtual void atread(double* value, const String& atlabel) = 0;
/** @overload */
CV_WRAP virtual void atwrite(const String& value, const String& atlabel) = 0;
/** @overload */
CV_WRAP virtual void atread(String* value, const String& atlabel) = 0;
/**
* Write an attribute into the root group.
*
* @param value attribute value. Currently, only n-d continuous multi-channel arrays are supported.
* @param atlabel attribute name.
*
* @note CV_Error() is called if the given attribute already exists. Use atexists()
* to check whether it exists or not beforehand. And use atdelete() to delete
* it if it already exists.
*
* @sa atexists, atdelete, atread.
*/
CV_WRAP virtual void atwrite(InputArray value, const String& atlabel) = 0;
/**
* Read an attribute from the root group.
*
* @param value attribute value. Currently, only n-d continuous multi-channel arrays are supported.
* @param atlabel attribute name.
*
* @note The attribute MUST exist, otherwise CV_Error() is called. Use atexists()
* to check if it exists beforehand.
*
* @sa atexists, atdelete, atwrite
*/
CV_WRAP virtual void atread(OutputArray value, const String& atlabel) = 0;
/** @overload */
CV_WRAP virtual void dscreate( const int rows, const int cols, const int type,
const String& dslabel ) const = 0;
/* @overload */
/** @overload */
CV_WRAP virtual void dscreate( const int rows, const int cols, const int type,
const String& dslabel, const int compresslevel ) const = 0;
/* @overload */
/** @overload */
CV_WRAP virtual void dscreate( const int rows, const int cols, const int type,
const String& dslabel, const int compresslevel, const vector<int>& dims_chunks ) const = 0;
/** @brief Create and allocate storage for two dimensional single or multi channel dataset.
......
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
/**
* @file create_groups.cpp
* @author Fangjun Kuang <csukuangfj dot at gmail dot com>
......
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
/**
* @file create_read_write.cpp
* @file create_read_write_datasets.cpp
* @author Fangjun Kuang <csukuangfj dot at gmail dot com>
* @date December 2017
*
......@@ -13,14 +9,6 @@
*
*/
#ifdef __GNUC__
# pragma GCC diagnostic ignored "-Wmissing-declarations"
# if defined __clang__ || defined __APPLE__
# pragma GCC diagnostic ignored "-Wmissing-prototypes"
# pragma GCC diagnostic ignored "-Wextra"
# endif
#endif
//! [tutorial]
#include <iostream>
......@@ -29,7 +17,7 @@
using namespace cv;
void write_root_group_single_channel()
static void write_root_group_single_channel()
{
String filename = "root_group_single_channel.h5";
String dataset_name = "/single"; // Note that it is a child of the root group /
......@@ -61,7 +49,7 @@ void write_root_group_single_channel()
h5io->close();
}
void write_single_channel()
static void write_single_channel()
{
String filename = "single_channel.h5";
String parent_name = "/data";
......@@ -98,7 +86,7 @@ void write_single_channel()
* creating, reading and writing multiple-channel matrices
* are the same with single channel matrices
*/
void write_multiple_channels()
static void write_multiple_channels()
{
String filename = "two_channels.h5";
String parent_name = "/data";
......
/**
* @file read_write_attributes.cpp
* @author Fangjun Kuang <csukuangfj dot at gmail dot com>
* @date December 2017
*
* @brief It demonstrates how to read and write attributes inside the
* root group.
*
* Currently, only the following datatypes can be used as attributes:
* - cv::String
* - int
* - double
* - cv::InputArray (n-d continuous multichannel arrays)
*
* Although HDF supports associating attributes with both datasets and groups,
* only support for the root group is implemented by OpenCV at present.
*/
//! [tutorial]
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/hdf.hpp>
using namespace cv;
static void read_write_attributes()
{
String filename = "attributes.h5";
//! [tutorial_open_file]
Ptr<hdf::HDF5> h5io = hdf::open(filename);
//! [tutorial_open_file]
//! [tutorial_write_mat]
String attr_mat_name = "array attribute";
Mat attr_mat;
attr_mat = (cv::Mat_<float>(2, 3) << 0, 1, 2, 3, 4, 5, 6);
if (!h5io->atexists(attr_mat_name))
h5io->atwrite(attr_mat, attr_mat_name);
//! [tutorial_write_mat]
//! [snippets_write_str]
String attr_str_name = "string attribute";
String attr_str = "Hello HDF5 from OpenCV!";
if (!h5io->atexists(attr_str_name))
h5io->atwrite(attr_str, attr_str_name);
//! [snippets_write_str]
String attr_int_name = "int attribute";
int attr_int = 123456;
if (!h5io->atexists(attr_int_name))
h5io->atwrite(attr_int, attr_int_name);
String attr_double_name = "double attribute";
double attr_double = 45678.123;
if (!h5io->atexists(attr_double_name))
h5io->atwrite(attr_double, attr_double_name);
// read attributes
Mat expected_attr_mat;
int expected_attr_int;
double expected_attr_double;
//! [snippets_read_str]
String expected_attr_str;
h5io->atread(&expected_attr_str, attr_str_name);
//! [snippets_read_str]
//! [tutorial_read_mat]
h5io->atread(expected_attr_mat, attr_mat_name);
//! [tutorial_read_mat]
h5io->atread(&expected_attr_int, attr_int_name);
h5io->atread(&expected_attr_double, attr_double_name);
// check results
CV_Assert(norm(attr_mat - expected_attr_mat) < 1e-10);
CV_Assert(attr_str.compare(expected_attr_str) == 0);
CV_Assert(attr_int == expected_attr_int);
CV_Assert(fabs(attr_double - expected_attr_double) < 1e-10);
//! [tutorial_close_file]
h5io->close();
//! [tutorial_close_file]
}
int main()
{
read_write_attributes();
return 0;
}
//! [tutorial]
......@@ -61,6 +61,21 @@ public:
// check if object / link exists
virtual bool hlexists( const String& label ) const;
virtual bool atexists(const String& atlabel) const;
virtual void atdelete(const String& atlabel);
virtual void atwrite(const int value, const String& atlabel);
virtual void atread(int* value, const String& atlabel);
virtual void atwrite(const double value, const String& atlabel);
virtual void atread(double* value, const String& atlabel);
virtual void atwrite(const String& value, const String& atlabel);
virtual void atread(String* value, const String& atlabel);
virtual void atwrite(InputArray value, const String& atlabel);
virtual void atread(OutputArray value, const String& atlabel);
/*
* h5 group
*/
......@@ -218,7 +233,7 @@ inline hid_t HDF5Impl::GetH5type( int cvType ) const
h5Type = H5T_NATIVE_INT;
break;
default:
CV_Error( Error::StsInternal, "Unknown cvType." );
CV_Error_(Error::StsInternal, ("Unknown cvType: %d.", cvType));
}
return h5Type;
}
......@@ -242,7 +257,7 @@ inline int HDF5Impl::GetCVtype( hid_t h5Type ) const
else if ( H5Tequal( h5Type, H5T_NATIVE_INT ) )
cvType = CV_32S;
else
CV_Error( Error::StsInternal, "Unknown H5Type." );
CV_Error_(Error::StsInternal, ("Unknown H5Type: %d.", h5Type));
return cvType;
}
......@@ -302,15 +317,229 @@ bool HDF5Impl::hlexists( const String& label ) const
return exists;
}
bool HDF5Impl::atexists(const String& atlabel) const
{
bool res = false;
// save old error handler
void *errdata;
H5E_auto2_t errfunc;
hid_t stackid = H5E_DEFAULT;
H5Eget_auto(stackid, &errfunc, &errdata);
// turn off error handling
H5Eset_auto(stackid, NULL, NULL);
hid_t attr = H5Aopen_name(m_h5_file_id, atlabel.c_str());
if (attr >= 0)
{
res = true;
H5Aclose(attr);
}
// restore previous error handler
H5Eset_auto(stackid, errfunc, errdata);
return res;
}
void HDF5Impl::atdelete(const String& atlabel)
{
if (!atexists(atlabel))
CV_Error_(Error::StsInternal,("The attribute '%s' does not exist!", atlabel.c_str()));
H5Adelete(m_h5_file_id, atlabel.c_str());
}
void HDF5Impl::atwrite(const int value, const String& atlabel)
{
if (atexists(atlabel))
CV_Error_(Error::StsInternal,("The attribute '%s' already exists!", atlabel.c_str()));
hid_t aid = H5Screate(H5S_SCALAR);;
hid_t attr = H5Acreate2(m_h5_file_id, atlabel.c_str(), H5T_NATIVE_INT, aid,
H5P_DEFAULT, H5P_DEFAULT);
H5Awrite(attr, H5T_NATIVE_INT, &value);
H5Sclose(aid);
H5Aclose(attr);
}
void HDF5Impl::atread(int* value, const String& atlabel)
{
if (!value)
CV_Error(Error::StsBadArg, "NULL pointer");
if (!atexists(atlabel))
CV_Error_(Error::StsInternal, ("Attribute '%s' does not exist!", atlabel.c_str()));
hid_t attr = H5Aopen(m_h5_file_id, atlabel.c_str(), H5P_DEFAULT);
H5Aread(attr, H5T_NATIVE_INT, value);
H5Aclose(attr);
}
void HDF5Impl::atwrite(const double value, const String& atlabel)
{
if (atexists(atlabel))
CV_Error_(Error::StsInternal,("The attribute '%s' already exists!", atlabel.c_str()));
hid_t aid = H5Screate(H5S_SCALAR);;
hid_t attr = H5Acreate2(m_h5_file_id, atlabel.c_str(), H5T_NATIVE_DOUBLE, aid,
H5P_DEFAULT, H5P_DEFAULT);
H5Awrite(attr, H5T_NATIVE_DOUBLE, &value);
H5Sclose(aid);
H5Aclose(attr);
}
void HDF5Impl::atread(double* value, const String& atlabel)
{
if (!value)
CV_Error(Error::StsBadArg, "NULL pointer");
if (!atexists(atlabel))
CV_Error_(Error::StsInternal, ("Attribute '%s' does not exist!", atlabel.c_str()));
hid_t attr = H5Aopen(m_h5_file_id, atlabel.c_str(), H5P_DEFAULT);
H5Aread(attr, H5T_NATIVE_DOUBLE, value);
H5Aclose(attr);
}
void HDF5Impl::atwrite(const String& value, const String& atlabel)
{
if (atexists(atlabel))
CV_Error_(Error::StsInternal,("The attribute '%s' already exists!", atlabel.c_str()));
hid_t aid = H5Screate(H5S_SCALAR);
hid_t atype = H5Tcopy(H5T_C_S1);
H5Tset_size(atype, value.size()+1);
H5Tset_strpad(atype, H5T_STR_NULLTERM);
hid_t attr = H5Acreate2(m_h5_file_id, atlabel.c_str(), atype, aid, H5P_DEFAULT, H5P_DEFAULT);
H5Awrite(attr, atype, value.c_str());
H5Sclose(aid);
H5Tclose(atype);
H5Aclose(attr);
}
void HDF5Impl::atread(String* value, const String& atlabel)
{
if (!value)
CV_Error(Error::StsBadArg, "NULL pointer");
if (!atexists(atlabel))
CV_Error_(Error::StsInternal, ("Attribute '%s' does not exist!", atlabel.c_str()));
hid_t attr = H5Aopen(m_h5_file_id, atlabel.c_str(), H5P_DEFAULT);
hid_t atype = H5Aget_type(attr);
H5T_class_t type_class = H5Tget_class(atype);
if (type_class != H5T_STRING)
{
H5Tclose(atype);
H5Aclose(attr);
CV_Error_(Error::StsInternal, ("Attribute '%s' is not of string type!", atlabel.c_str()));
}
size_t size = H5Tget_size(atype);
*value = String(size, 0); // allocate space
hid_t atype_mem = H5Tget_native_type(atype, H5T_DIR_ASCEND);
H5Aread(attr, atype_mem, const_cast<char*>(value->c_str()));
H5Tclose(atype_mem);
H5Tclose(atype);
H5Aclose(attr);
}
void HDF5Impl::atwrite(InputArray value, const String& atlabel)
{
if (atexists(atlabel))
CV_Error_(Error::StsInternal,("The attribute '%s' already exists!", atlabel.c_str()));
Mat value_ = value.getMat();
if (!value_.isContinuous())
CV_Error(Error::StsInternal, "Only continuous array are implemented. Current array is not continuous!");
int ndims = value_.dims;
vector<hsize_t> dim_vec(ndims);
for (int i = 0; i < ndims; i++)
dim_vec[i] = value_.size[i];
hid_t dtype = GetH5type(value_.type());
if (value_.channels() > 1)
{
hsize_t dims[1] = { (hsize_t)value_.channels()};
dtype = H5Tarray_create(dtype, 1, dims);
}
hid_t aid = H5Screate(H5S_SIMPLE);
H5Sset_extent_simple(aid, ndims, dim_vec.data(), NULL);
hid_t attr = H5Acreate2(m_h5_file_id, atlabel.c_str(), dtype,
aid, H5P_DEFAULT, H5P_DEFAULT);
H5Awrite(attr, dtype, value_.data);
if (value_.channels() > 1)
H5Tclose(dtype);
H5Sclose(aid);
H5Aclose(attr);
}
void HDF5Impl::atread(OutputArray value, const String& atlabel)
{
if (!atexists(atlabel))
CV_Error_(Error::StsInternal, ("Attribute '%s' does not exist!", atlabel.c_str()));
hid_t attr = H5Aopen(m_h5_file_id, atlabel.c_str(), H5P_DEFAULT);
hid_t atype = H5Aget_type(attr);
hid_t aspace = H5Aget_space(attr);
int rank = H5Sget_simple_extent_ndims(aspace);
vector<hsize_t> dim_vec_(rank);
H5Sget_simple_extent_dims(aspace, dim_vec_.data(), NULL);
vector<int> dim_vec(dim_vec_.begin(), dim_vec_.end());
int nchannels = 1;
hid_t h5type;
if (H5Tget_class(atype) == H5T_ARRAY)
{
hsize_t dims;
H5Tget_array_dims(atype, &dims);
nchannels = (int) dims;
hid_t super_type = H5Tget_super(atype);
h5type = H5Tget_native_type(super_type, H5T_DIR_ASCEND);
H5Tclose(super_type);
}
else
h5type = H5Tget_native_type(atype, H5T_DIR_ASCEND);
int dtype = GetCVtype(h5type);
value.create(rank, dim_vec.data(), CV_MAKETYPE(dtype, nchannels));
H5Aread(attr, atype, value.getMat().data);
H5Sclose(aspace);
H5Tclose(atype);
H5Aclose(attr);
}
/*
* h5 group
*/
void HDF5Impl::grcreate( const String& grlabel )
{
hid_t gid = H5Gcreate( m_h5_file_id, grlabel.c_str(),
H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
H5Gclose( gid );
if (hlexists(grlabel))
CV_Error_(Error::StsInternal, ("Requested group '%s' already exists.", grlabel.c_str()));
hid_t gid = H5Gcreate(m_h5_file_id, grlabel.c_str(),
H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
H5Gclose(gid);
}
/*
......@@ -358,7 +587,7 @@ vector<int> HDF5Impl::dsgetsize( const String& dslabel, int dims_flag ) const
SizeVect.resize( n_dims );
}
else
CV_Error( Error::StsInternal, "Unknown dimension flag." );
CV_Error_(Error::StsInternal, ("Unknown dimension flag: %d", dims_flag));
// fill with size data
for ( size_t d = 0; d < SizeVect.size(); d++ )
......@@ -479,7 +708,7 @@ void HDF5Impl::dscreate( const int n_dims, const int* sizes, const int type,
CV_Assert( compresslevel >= H5_NONE && compresslevel <= 9 );
if ( hlexists( dslabel ) == true )
CV_Error( Error::StsInternal, "Requested dataset already exists." );
CV_Error_(Error::StsInternal, ("Requested dataset '%s' already exists.", dslabel.c_str()));
int channs = CV_MAT_CN( type );
......@@ -802,7 +1031,7 @@ void HDF5Impl::dsinsert( InputArray Array, const String& dslabel,
// check dataset exists
if ( hlexists( dslabel ) == false )
CV_Error( Error::StsInternal, "Dataset does not exist." );
CV_Error_(Error::StsInternal, ("Dataset '%s' does not exist.", dslabel.c_str()));
Mat matrix = Array.getMat();
......@@ -935,7 +1164,7 @@ void HDF5Impl::kpcreate( const int size, const String& kplabel,
CV_Assert( compresslevel >= H5_NONE && compresslevel <= 9 );
if ( hlexists( kplabel ) == true )
CV_Error( Error::StsInternal, "Requested dataset already exists." );
CV_Error_(Error::StsInternal, ("Requested dataset '%s' already exists.", kplabel.c_str()));
hsize_t dchunk[1];
hsize_t dsdims[1];
......@@ -1058,7 +1287,7 @@ void HDF5Impl::kpinsert( const vector<KeyPoint> keypoints, const String& kplabel
// check dataset exists
if ( hlexists( kplabel ) == false )
CV_Error( Error::StsInternal, "Dataset does not exist." );
CV_Error_(Error::StsInternal, ("Dataset '%s' does not exist.", kplabel.c_str()));
hsize_t dsddims[1];
hsize_t doffset[1];
......
......@@ -61,6 +61,9 @@ TEST_F(HDF5_Test, create_a_single_group)
EXPECT_EQ(m_hdf_io->hlexists(group_name), true);
EXPECT_EQ(m_hdf_io->hlexists("child"), false);
// It should fail since it creates a group with an existing name
EXPECT_ANY_THROW(m_hdf_io->grcreate(group_name));
m_hdf_io->close();
}
......@@ -210,3 +213,146 @@ TEST_F(HDF5_Test, write_read_dataset_2)
m_hdf_io->close();
}
TEST_F(HDF5_Test, test_attribute)
{
reset();
String attr_name = "test attribute name";
int attr_value = 0x12345678;
m_hdf_io = hdf::open(m_filename);
EXPECT_EQ(m_hdf_io->atexists(attr_name), false);
m_hdf_io->atwrite(attr_value, attr_name);
EXPECT_ANY_THROW(m_hdf_io->atwrite(attr_value, attr_name)); // error! it already exists
EXPECT_EQ(m_hdf_io->atexists(attr_name), true);
int expected_attr_value;
m_hdf_io->atread(&expected_attr_value, attr_name);
EXPECT_EQ(attr_value, expected_attr_value);
m_hdf_io->atdelete(attr_name);
EXPECT_ANY_THROW(m_hdf_io->atdelete(attr_name)); // error! Delete non-existed attribute
EXPECT_EQ(m_hdf_io->atexists(attr_name), false);
m_hdf_io->close();
}
TEST_F(HDF5_Test, test_attribute_int)
{
reset();
String attr_name = "test int";
int attr_value = 0x12345678;
m_hdf_io = hdf::open(m_filename);
m_hdf_io->atwrite(attr_value, attr_name);
int expected_attr_value;
m_hdf_io->atread(&expected_attr_value, attr_name);
EXPECT_EQ(attr_value, expected_attr_value);
m_hdf_io->close();
}
TEST_F(HDF5_Test, test_attribute_double)
{
reset();
String attr_name = "test double";
double attr_value = 123.456789;
m_hdf_io = hdf::open(m_filename);
m_hdf_io->atwrite(attr_value, attr_name);
double expected_attr_value;
m_hdf_io->atread(&expected_attr_value, attr_name);
EXPECT_NEAR(attr_value, expected_attr_value, 1e-9);
m_hdf_io->close();
}
TEST_F(HDF5_Test, test_attribute_String)
{
reset();
String attr_name = "test-String";
String attr_value = "----_______----Hello HDF5----_______----\n";
m_hdf_io = hdf::open(m_filename);
m_hdf_io->atwrite(attr_value, attr_name);
String expected_attr_value;
m_hdf_io->atread(&expected_attr_value, attr_name);
EXPECT_EQ(attr_value.compare(expected_attr_value), 0);
m_hdf_io->close();
}
TEST_F(HDF5_Test, test_attribute_InutArray_OutputArray_2d)
{
reset();
String attr_name = "test-InputArray-OutputArray-2d";
cv::Mat attr_value;
std::vector<int> depth_vec;
depth_vec.push_back(CV_8U); depth_vec.push_back(CV_8S);
depth_vec.push_back(CV_16U); depth_vec.push_back(CV_16S);
depth_vec.push_back(CV_32S); depth_vec.push_back(CV_32F);
depth_vec.push_back(CV_64F);
std::vector<int> channel_vec;
channel_vec.push_back(1); channel_vec.push_back(2);
channel_vec.push_back(3); channel_vec.push_back(4);
channel_vec.push_back(5); channel_vec.push_back(6);
channel_vec.push_back(7); channel_vec.push_back(8);
channel_vec.push_back(9); channel_vec.push_back(10);
std::vector<std::vector<int> > dim_vec;
std::vector<int> dim_2d;
dim_2d.push_back(2); dim_2d.push_back(3);
dim_vec.push_back(dim_2d);
std::vector<int> dim_3d;
dim_3d.push_back(2);
dim_3d.push_back(3);
dim_3d.push_back(4);
dim_vec.push_back(dim_3d);
std::vector<int> dim_4d;
dim_4d.push_back(2); dim_4d.push_back(3);
dim_4d.push_back(4); dim_4d.push_back(5);
dim_vec.push_back(dim_4d);
Mat expected_attr_value;
m_hdf_io = hdf::open(m_filename);
for (size_t i = 0; i < depth_vec.size(); i++)
for (size_t j = 0; j < channel_vec.size(); j++)
for (size_t k = 0; k < dim_vec.size(); k++)
{
if (m_hdf_io->atexists(attr_name))
m_hdf_io->atdelete(attr_name);
attr_value.create(dim_vec[k], CV_MAKETYPE(depth_vec[i], channel_vec[j]));
randu(attr_value, 0, 255);
m_hdf_io->atwrite(attr_value, attr_name);
m_hdf_io->atread(expected_attr_value, attr_name);
double diff = norm(attr_value - expected_attr_value);
EXPECT_NEAR(diff, 0, 1e-6);
EXPECT_EQ(attr_value.size(), expected_attr_value.size());
EXPECT_EQ(attr_value.type(), expected_attr_value.type());
}
m_hdf_io->close();
}
......@@ -3,13 +3,13 @@ Creating Groups {#tutorial_hdf_create_groups}
Goal
----
This tutorial will show you:
- How to create a HDF5 file?
- How to create a group?
- How to check whether a given group exists or not?
- How to create a subgroup?
Source Code
----
......@@ -35,7 +35,7 @@ Next, we create the group `Group1`
@snippet samples/create_groups.cpp tutorial_create_group
Note that we have to check whether `/Group1` exists or not using
the function `hlexists` before creating it. You can not create
the function cv::hdf::HDF5::hlexists() before creating it. You can not create
a group with an existing name. Otherwise, an error will occur.
Then, we create the subgroup named `Subgroup1`. In order to
......
......@@ -3,12 +3,13 @@ Creating, Writing and Reading Datasets {#tutorial_hdf_create_read_write_datasets
Goal
----
This tutorial shows you:
- How to create a dataset?
- How to write a `cv::Mat` to a dataset?
- How to read a `cv::Mat` from a dataset?
@note Currently, it supports only reading and writing `cv::Mat` and the matrix should be continuous
@note Currently, it supports only reading and writing cv::Mat and the matrix should be continuous
in memory. Supports for other data types have not been implemented yet.
Source Code
......@@ -36,7 +37,7 @@ the dataset name is `/single`, which is inside the root group, we can use
@snippet samples/create_read_write_datasets.cpp tutorial_write_root_single_channel
to write the data directly to the dataset without the need of creating
it beforehand. Because it is created inside `HDF5::dswrite()`
it beforehand. Because it is created inside cv::hdf::HDF5::dswrite()
automatically.
@warning This applies only to datasets that reside inside the root group.
......@@ -59,7 +60,7 @@ Results
----
Figure 1 shows the result visualized using the tool HDFView for the file
`root_group_sinle_channel`. The results
`root_group_single_channel`. The results
of matrices for datasets that are not the direct children of the root group
are given in Figure 2 and Figure 3, respectively.
......
Reading and Writing Attributes{#tutorial_hdf_read_write_attributes}
===============================
Goal
----
This tutorial shows you:
- How to write attributes?
- How to read attributes?
@note Although attributes can be associated with groups and datasets, only attributes
with the root group are implemented in OpenCV. Supported attribute types are
`int`, `double`, `cv::String` and `cv::InputArray` (only for continuous arrays).
Source Code
----
The following code demonstrates reading and writing attributes
inside the root group with data types `cv::Mat`, `cv::String`, `int`
and `double`.
You can download the code from [here][1] or find it in the file
`modules/hdf/samples/read_write_attributes.cpp` of the opencv_contrib source code library.
@snippet samples/read_write_attributes.cpp tutorial
Explanation
----
The first step is to open the HDF5 file:
@snippet samples/read_write_attributes.cpp tutorial_open_file
Then we use cv::hdf::HDF5::atwrite() to write attributes by specifying its value and name:
@snippet samples/read_write_attributes.cpp tutorial_write_mat
@warning Before writing an attribute, we have to make sure that
the attribute does not exist using cv::hdf::HDF5::atexists().
To read an attribute, we use cv::hdf::HDF5::atread() by specifying the attribute name
@snippet samples/read_write_attributes.cpp tutorial_read_mat
In the end, we have to close the HDF file
@snippet samples/read_write_attributes.cpp tutorial_close_file
Results
----
Figure 1 and Figure 2 give the results visualized using the tool HDFView.
![Figure 1: Attributes of the root group](pics/attributes-file.png)
![Figure 2: Detailed attribute information](pics/attributes-details.png)
[1]: https://github.com/opencv/opencv_contrib/tree/master/modules/hdf/samples/read_write_attributes.cpp
......@@ -2,9 +2,9 @@ The Hierarchical Data Format (hdf) I/O {#tutorial_table_of_content_hdf}
=====================================
Here you will know how to read and write a HDF5 file using OpenCV.
Currently, only `cv::Mat` is supported.
Specifically, it shows you how to read/write groups, datasets and attributes.
Note that the HDF5 library has to be installed in your system
@note The HDF5 library has to be installed in your system
to use this module.
- @subpage tutorial_hdf_create_groups
......@@ -22,3 +22,11 @@ to use this module.
*Author:* Fangjun Kuang
You will learn how to create, read and write datasets.
- @subpage tutorial_hdf_read_write_attributes
*Compatibility:* \> OpenCV 3.4
*Author:* Fangjun Kuang
You will learn how to read and write attributes.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment