Merge pull request #1493 from csukuangfj:improve-hdf
commit
f03e415e64
16 changed files with 809 additions and 174 deletions
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 30 KiB |
@ -0,0 +1,60 @@ |
||||
// 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> |
||||
* @date December 2017 |
||||
* |
||||
* @brief It demonstrates how to create HDF5 groups and subgroups. |
||||
* |
||||
* Basic steps: |
||||
* 1. Use hdf::open to create a HDF5 file |
||||
* 2. Use HDF5::hlexists to check if a group exists or not |
||||
* 3. Use HDF5::grcreate to create a group by specifying its name |
||||
* 4. Use hdf::close to close a HDF5 file after modifying it |
||||
* |
||||
*/ |
||||
|
||||
//! [tutorial]
|
||||
#include <iostream> |
||||
|
||||
#include <opencv2/core.hpp> |
||||
#include <opencv2/hdf.hpp> |
||||
|
||||
using namespace cv; |
||||
|
||||
int main() |
||||
{ |
||||
//! [create_group]
|
||||
|
||||
//! [tutorial_create_file]
|
||||
Ptr<hdf::HDF5> h5io = hdf::open("mytest.h5"); |
||||
//! [tutorial_create_file]
|
||||
|
||||
//! [tutorial_create_group]
|
||||
// "/" means the root group, which is always present
|
||||
if (!h5io->hlexists("/Group1")) |
||||
h5io->grcreate("/Group1"); |
||||
else |
||||
std::cout << "/Group1 has already been created, skip it.\n"; |
||||
//! [tutorial_create_group]
|
||||
|
||||
//! [tutorial_create_subgroup]
|
||||
// Note that Group1 has been created above, otherwise exception will occur
|
||||
if (!h5io->hlexists("/Group1/SubGroup1")) |
||||
h5io->grcreate("/Group1/SubGroup1"); |
||||
else |
||||
std::cout << "/Group1/SubGroup1 has already been created, skip it.\n"; |
||||
//! [tutorial_create_subgroup]
|
||||
|
||||
//! [tutorial_close_file]
|
||||
h5io->close(); |
||||
//! [tutorial_close_file]
|
||||
|
||||
//! [create_group]
|
||||
|
||||
return 0; |
||||
} |
||||
//! [tutorial]
|
@ -0,0 +1,143 @@ |
||||
// 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 |
||||
* @author Fangjun Kuang <csukuangfj dot at gmail dot com> |
||||
* @date December 2017 |
||||
* |
||||
* @brief It demonstrates how to create a dataset, how |
||||
* to write a cv::Mat to the dataset and how to |
||||
* read a cv::Mat from it. |
||||
* |
||||
*/ |
||||
|
||||
#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> |
||||
|
||||
#include <opencv2/core.hpp> |
||||
#include <opencv2/hdf.hpp> |
||||
|
||||
using namespace cv; |
||||
|
||||
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 /
|
||||
|
||||
// prepare data
|
||||
Mat data; |
||||
data = (cv::Mat_<float>(2, 3) << 0, 1, 2, 3, 4, 5, 6); |
||||
|
||||
//! [tutorial_open_file]
|
||||
Ptr<hdf::HDF5> h5io = hdf::open(filename); |
||||
//! [tutorial_open_file]
|
||||
|
||||
//! [tutorial_write_root_single_channel]
|
||||
// write data to the given dataset
|
||||
// the dataset "/single" is created automatically, since it is a child of the root
|
||||
h5io->dswrite(data, dataset_name); |
||||
//! [tutorial_write_root_single_channel]
|
||||
|
||||
//! [tutorial_read_dataset]
|
||||
Mat expected; |
||||
h5io->dsread(expected, dataset_name); |
||||
//! [tutorial_read_dataset]
|
||||
|
||||
//! [tutorial_check_result]
|
||||
double diff = norm(data - expected); |
||||
CV_Assert(abs(diff) < 1e-10); |
||||
//! [tutorial_check_result]
|
||||
|
||||
h5io->close(); |
||||
} |
||||
|
||||
void write_single_channel() |
||||
{ |
||||
String filename = "single_channel.h5"; |
||||
String parent_name = "/data"; |
||||
String dataset_name = parent_name + "/single"; |
||||
|
||||
// prepare data
|
||||
Mat data; |
||||
data = (cv::Mat_<float>(2, 3) << 0, 1, 2, 3, 4, 5); |
||||
|
||||
Ptr<hdf::HDF5> h5io = hdf::open(filename); |
||||
|
||||
//! [tutorial_create_dataset]
|
||||
// first we need to create the parent group
|
||||
if (!h5io->hlexists(parent_name)) h5io->grcreate(parent_name); |
||||
|
||||
// create the dataset if it not exists
|
||||
if (!h5io->hlexists(dataset_name)) h5io->dscreate(data.rows, data.cols, data.type(), dataset_name); |
||||
//! [tutorial_create_dataset]
|
||||
|
||||
// the following is the same with the above function write_root_group_single_channel()
|
||||
|
||||
h5io->dswrite(data, dataset_name); |
||||
|
||||
Mat expected; |
||||
h5io->dsread(expected, dataset_name); |
||||
|
||||
double diff = norm(data - expected); |
||||
CV_Assert(abs(diff) < 1e-10); |
||||
|
||||
h5io->close(); |
||||
} |
||||
|
||||
/*
|
||||
* creating, reading and writing multiple-channel matrices |
||||
* are the same with single channel matrices |
||||
*/ |
||||
void write_multiple_channels() |
||||
{ |
||||
String filename = "two_channels.h5"; |
||||
String parent_name = "/data"; |
||||
String dataset_name = parent_name + "/two_channels"; |
||||
|
||||
// prepare data
|
||||
Mat data(2, 3, CV_32SC2); |
||||
for (size_t i = 0; i < data.total()*data.channels(); i++) |
||||
((int*) data.data)[i] = (int)i; |
||||
|
||||
Ptr<hdf::HDF5> h5io = hdf::open(filename); |
||||
|
||||
// first we need to create the parent group
|
||||
if (!h5io->hlexists(parent_name)) h5io->grcreate(parent_name); |
||||
|
||||
// create the dataset if it not exists
|
||||
if (!h5io->hlexists(dataset_name)) h5io->dscreate(data.rows, data.cols, data.type(), dataset_name); |
||||
|
||||
// the following is the same with the above function write_root_group_single_channel()
|
||||
|
||||
h5io->dswrite(data, dataset_name); |
||||
|
||||
Mat expected; |
||||
h5io->dsread(expected, dataset_name); |
||||
|
||||
double diff = norm(data - expected); |
||||
CV_Assert(abs(diff) < 1e-10); |
||||
|
||||
h5io->close(); |
||||
} |
||||
|
||||
int main() |
||||
{ |
||||
write_root_group_single_channel(); |
||||
|
||||
write_single_channel(); |
||||
|
||||
write_multiple_channels(); |
||||
|
||||
return 0; |
||||
} |
||||
//! [tutorial]
|
@ -0,0 +1,212 @@ |
||||
// 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 test_hdf5.cpp |
||||
* @author Fangjun Kuang <csukuangfj dot at gmail dot com> |
||||
* @date December 2017 |
||||
* |
||||
*/ |
||||
#include<stdio.h> // for remove() |
||||
|
||||
#include "test_precomp.hpp" |
||||
#include <vector> |
||||
|
||||
using namespace cv; |
||||
|
||||
struct HDF5_Test : public testing::Test |
||||
{ |
||||
virtual void SetUp() |
||||
{ |
||||
m_filename = "test.h5"; |
||||
|
||||
// 0 1 2
|
||||
// 3 4 5
|
||||
m_single_channel.create(2, 3, CV_32F); |
||||
for (size_t i = 0; i < m_single_channel.total(); i++) |
||||
{ |
||||
((float*)m_single_channel.data)[i] = i; |
||||
} |
||||
|
||||
// 0 1 2 3 4 5
|
||||
// 6 7 8 9 10 11
|
||||
m_two_channels.create(2, 3, CV_32SC2); |
||||
for (size_t i = 0; i < m_two_channels.total()*m_two_channels.channels(); i++) |
||||
{ |
||||
((int*)m_two_channels.data)[i] = (int)i; |
||||
} |
||||
} |
||||
|
||||
//! Remove the hdf5 file
|
||||
void reset() |
||||
{ |
||||
remove(m_filename.c_str()); |
||||
} |
||||
|
||||
String m_filename; //!< filename for testing
|
||||
Ptr<hdf::HDF5> m_hdf_io; //!< HDF5 file pointer
|
||||
Mat m_single_channel; //!< single channel matrix for test
|
||||
Mat m_two_channels; //!< two-channel matrix for test
|
||||
}; |
||||
|
||||
TEST_F(HDF5_Test, create_a_single_group) |
||||
{ |
||||
reset(); |
||||
|
||||
String group_name = "parent"; |
||||
m_hdf_io = hdf::open(m_filename); |
||||
m_hdf_io->grcreate(group_name); |
||||
|
||||
EXPECT_EQ(m_hdf_io->hlexists(group_name), true); |
||||
EXPECT_EQ(m_hdf_io->hlexists("child"), false); |
||||
|
||||
m_hdf_io->close(); |
||||
} |
||||
|
||||
|
||||
TEST_F(HDF5_Test, create_a_child_group) |
||||
{ |
||||
reset(); |
||||
|
||||
String parent = "parent"; |
||||
String child = parent + "/child"; |
||||
m_hdf_io = hdf::open(m_filename); |
||||
m_hdf_io->grcreate(parent); |
||||
m_hdf_io->grcreate(child); |
||||
|
||||
EXPECT_EQ(m_hdf_io->hlexists(parent), true); |
||||
EXPECT_EQ(m_hdf_io->hlexists(child), true); |
||||
|
||||
m_hdf_io->close(); |
||||
} |
||||
|
||||
TEST_F(HDF5_Test, create_dataset) |
||||
{ |
||||
reset(); |
||||
|
||||
String dataset_single_channel = "/single"; |
||||
String dataset_two_channels = "/dual"; |
||||
|
||||
m_hdf_io = hdf::open(m_filename); |
||||
|
||||
m_hdf_io->dscreate(m_single_channel.rows, |
||||
m_single_channel.cols, |
||||
m_single_channel.type(), |
||||
dataset_single_channel); |
||||
|
||||
m_hdf_io->dscreate(m_two_channels.rows, |
||||
m_two_channels.cols, |
||||
m_two_channels.type(), |
||||
dataset_two_channels); |
||||
|
||||
EXPECT_EQ(m_hdf_io->hlexists(dataset_single_channel), true); |
||||
EXPECT_EQ(m_hdf_io->hlexists(dataset_two_channels), true); |
||||
|
||||
std::vector<int> dims; |
||||
|
||||
dims = m_hdf_io->dsgetsize(dataset_single_channel, hdf::HDF5::H5_GETDIMS); |
||||
EXPECT_EQ(dims.size(), (size_t)2); |
||||
EXPECT_EQ(dims[0], m_single_channel.rows); |
||||
EXPECT_EQ(dims[1], m_single_channel.cols); |
||||
|
||||
dims = m_hdf_io->dsgetsize(dataset_two_channels, hdf::HDF5::H5_GETDIMS); |
||||
EXPECT_EQ(dims.size(), (size_t)2); |
||||
EXPECT_EQ(dims[0], m_two_channels.rows); |
||||
EXPECT_EQ(dims[1], m_two_channels.cols); |
||||
|
||||
int type; |
||||
type = m_hdf_io->dsgettype(dataset_single_channel); |
||||
EXPECT_EQ(type, m_single_channel.type()); |
||||
|
||||
type = m_hdf_io->dsgettype(dataset_two_channels); |
||||
EXPECT_EQ(type, m_two_channels.type()); |
||||
|
||||
m_hdf_io->close(); |
||||
} |
||||
|
||||
|
||||
TEST_F(HDF5_Test, write_read_dataset_1) |
||||
{ |
||||
reset(); |
||||
|
||||
String dataset_single_channel = "/single"; |
||||
String dataset_two_channels = "/dual"; |
||||
|
||||
m_hdf_io = hdf::open(m_filename); |
||||
|
||||
// since the dataset is under the root group, it is created by dswrite() automatically.
|
||||
m_hdf_io->dswrite(m_single_channel, dataset_single_channel); |
||||
m_hdf_io->dswrite(m_two_channels, dataset_two_channels); |
||||
|
||||
EXPECT_EQ(m_hdf_io->hlexists(dataset_single_channel), true); |
||||
EXPECT_EQ(m_hdf_io->hlexists(dataset_two_channels), true); |
||||
|
||||
// read single channel matrix
|
||||
Mat single; |
||||
m_hdf_io->dsread(single, dataset_single_channel); |
||||
EXPECT_EQ(single.type(), m_single_channel.type()); |
||||
EXPECT_EQ(single.size(), m_single_channel.size()); |
||||
EXPECT_NEAR(norm(single-m_single_channel), 0, 1e-10); |
||||
|
||||
// read dual channel matrix
|
||||
Mat dual; |
||||
m_hdf_io->dsread(dual, dataset_two_channels); |
||||
EXPECT_EQ(dual.type(), m_two_channels.type()); |
||||
EXPECT_EQ(dual.size(), m_two_channels.size()); |
||||
EXPECT_NEAR(norm(dual-m_two_channels), 0, 1e-10); |
||||
|
||||
m_hdf_io->close(); |
||||
} |
||||
|
||||
TEST_F(HDF5_Test, write_read_dataset_2) |
||||
{ |
||||
reset(); |
||||
// create the dataset manually if it is not inside
|
||||
// the root group
|
||||
|
||||
String parent = "/parent"; |
||||
|
||||
String dataset_single_channel = parent + "/single"; |
||||
String dataset_two_channels = parent + "/dual"; |
||||
|
||||
m_hdf_io = hdf::open(m_filename); |
||||
|
||||
m_hdf_io->grcreate(parent); |
||||
EXPECT_EQ(m_hdf_io->hlexists(parent), true); |
||||
|
||||
m_hdf_io->dscreate(m_single_channel.rows, |
||||
m_single_channel.cols, |
||||
m_single_channel.type(), |
||||
dataset_single_channel); |
||||
|
||||
m_hdf_io->dscreate(m_two_channels.rows, |
||||
m_two_channels.cols, |
||||
m_two_channels.type(), |
||||
dataset_two_channels); |
||||
|
||||
EXPECT_EQ(m_hdf_io->hlexists(dataset_single_channel), true); |
||||
EXPECT_EQ(m_hdf_io->hlexists(dataset_two_channels), true); |
||||
|
||||
m_hdf_io->dswrite(m_single_channel, dataset_single_channel); |
||||
m_hdf_io->dswrite(m_two_channels, dataset_two_channels); |
||||
|
||||
EXPECT_EQ(m_hdf_io->hlexists(dataset_single_channel), true); |
||||
EXPECT_EQ(m_hdf_io->hlexists(dataset_two_channels), true); |
||||
|
||||
// read single channel matrix
|
||||
Mat single; |
||||
m_hdf_io->dsread(single, dataset_single_channel); |
||||
EXPECT_EQ(single.type(), m_single_channel.type()); |
||||
EXPECT_EQ(single.size(), m_single_channel.size()); |
||||
EXPECT_NEAR(norm(single-m_single_channel), 0, 1e-10); |
||||
|
||||
// read dual channel matrix
|
||||
Mat dual; |
||||
m_hdf_io->dsread(dual, dataset_two_channels); |
||||
EXPECT_EQ(dual.type(), m_two_channels.type()); |
||||
EXPECT_EQ(dual.size(), m_two_channels.size()); |
||||
EXPECT_NEAR(norm(dual-m_two_channels), 0, 1e-10); |
||||
|
||||
m_hdf_io->close(); |
||||
} |
@ -0,0 +1,7 @@ |
||||
// 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.
|
||||
|
||||
#include "test_precomp.hpp" |
||||
|
||||
CV_TEST_MAIN("cv") |
@ -0,0 +1,20 @@ |
||||
// 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.
|
||||
|
||||
#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 |
||||
|
||||
#ifndef __OPENCV_TEST_PRECOMP_HPP__ |
||||
#define __OPENCV_TEST_PRECOMP_HPP__ |
||||
|
||||
#include "opencv2/ts.hpp" |
||||
#include "opencv2/core.hpp" |
||||
#include "opencv2/hdf.hpp" |
||||
|
||||
#endif |
@ -0,0 +1,85 @@ |
||||
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 |
||||
---- |
||||
|
||||
The following code creates two groups: `Group1` and `SubGroup1`, where |
||||
`SubGroup1` is a child of `Group1`. |
||||
|
||||
You can download the code from [here][1] or find it in the file |
||||
`modules/hdf/samples/create_groups.cpp` of the opencv_contrib source code library. |
||||
|
||||
@snippet samples/create_groups.cpp tutorial |
||||
|
||||
Explanation |
||||
---- |
||||
|
||||
First, we create a HDF5 file |
||||
|
||||
@snippet samples/create_groups.cpp tutorial_create_file |
||||
|
||||
If the given file does not exist, it will be created. Otherwise, it is open for read and write. |
||||
|
||||
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 |
||||
a group with an existing name. Otherwise, an error will occur. |
||||
|
||||
Then, we create the subgroup named `Subgroup1`. In order to |
||||
indicate that it is a sub group of `Group1`, we have to |
||||
use the group name `/Group1/SubGroup1`: |
||||
|
||||
@snippet samples/create_groups.cpp tutorial_create_subgroup |
||||
|
||||
Note that before creating a subgroup, we have to make sure |
||||
that its parent group exists. Otherwise, an error will occur. |
||||
|
||||
In the end, we have to close the file |
||||
|
||||
@snippet samples/create_groups.cpp tutorial_close_file |
||||
|
||||
Result |
||||
---- |
||||
|
||||
There are many tools that can be used to inspect a given HDF file, such |
||||
as HDFView and h5dump. If you are using Ubuntu, you can install |
||||
them with the following commands: |
||||
|
||||
@code |
||||
sudo apt-get install hdf5-tools hdfview |
||||
@endcode |
||||
|
||||
There are also binaries available from the The HDF Group official website <https://support.hdfgroup.org/HDF5/Tutor/tools.html>. |
||||
|
||||
The following figure shows the result visualized with the tool HDFView: |
||||
|
||||
 |
||||
|
||||
The output for `h5dump` is: |
||||
|
||||
@code |
||||
$ h5dump mytest.h5 |
||||
HDF5 "mytest.h5" { |
||||
GROUP "/" { |
||||
GROUP "Group1" { |
||||
GROUP "SubGroup1" { |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@endcode |
||||
|
||||
[1]: https://github.com/opencv/opencv_contrib/tree/master/modules/hdf/samples/create_groups.cpp |
@ -0,0 +1,73 @@ |
||||
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 |
||||
in memory. Supports for other data types have not been implemented yet. |
||||
|
||||
Source Code |
||||
---- |
||||
|
||||
The following code demonstrates writing a single channel |
||||
matrix and a two-channel matrix to datasets and then reading them |
||||
back. |
||||
|
||||
You can download the code from [here][1] or find it in the file |
||||
`modules/hdf/samples/create_read_write_datasets.cpp` of the opencv_contrib source code library. |
||||
|
||||
@snippet samples/create_read_write_datasets.cpp tutorial |
||||
|
||||
Explanation |
||||
---- |
||||
|
||||
The first step for creating a dataset is to open the file |
||||
|
||||
@snippet samples/create_read_write_datasets.cpp tutorial_open_file |
||||
|
||||
For the function `write_root_group_single_channel()`, since |
||||
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()` |
||||
automatically. |
||||
|
||||
@warning This applies only to datasets that reside inside the root group. |
||||
|
||||
Of course, we can create the dataset by ourselves: |
||||
|
||||
@snippet samples/create_read_write_datasets.cpp tutorial_create_dataset |
||||
|
||||
To read data from a dataset, we use |
||||
|
||||
@snippet samples/create_read_write_datasets.cpp tutorial_read_dataset |
||||
|
||||
by specifying the name of the dataset. |
||||
|
||||
We can check that the data read out is exactly the data written before by using |
||||
|
||||
@snippet samples/create_read_write_datasets.cpp tutorial_check_result |
||||
|
||||
Results |
||||
---- |
||||
|
||||
Figure 1 shows the result visualized using the tool HDFView for the file |
||||
`root_group_sinle_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. |
||||
|
||||
 |
||||
|
||||
 |
||||
|
||||
 |
||||
|
||||
|
||||
[1]: https://github.com/opencv/opencv_contrib/tree/master/modules/hdf/samples/create_read_write_datasets.cpp |
@ -0,0 +1,24 @@ |
||||
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. |
||||
|
||||
Note that the HDF5 library has to be installed in your system |
||||
to use this module. |
||||
|
||||
- @subpage tutorial_hdf_create_groups |
||||
|
||||
*Compatibility:* \> OpenCV 3.0 |
||||
|
||||
*Author:* Fangjun Kuang |
||||
|
||||
You will learn how to create groups and subgroups. |
||||
|
||||
- @subpage tutorial_hdf_create_read_write_datasets |
||||
|
||||
*Compatibility:* \> OpenCV 3.0 |
||||
|
||||
*Author:* Fangjun Kuang |
||||
|
||||
You will learn how to create, read and write datasets. |
Loading…
Reference in new issue