OpenCV  4.10.0
开源计算机视觉库
加载中...
搜索中...
无匹配项
创建、写入和读取数据集

目标

本教程向您展示

  • 如何创建数据集?
  • 如何将 cv::Mat 写入数据集?
  • 如何从数据集读取 cv::Mat
注意
目前,它只支持读取和写入 cv::Mat,并且矩阵在内存中应连续。对其他数据类型的支持尚未实现。

源代码

以下代码演示了将单通道矩阵和双通道矩阵写入数据集,然后再次读取它们。

您可以从 这里 下载代码,或者在 opencv_contrib 源代码库的 modules/hdf/samples/create_read_write_datasets.cpp 文件中找到它。

#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/hdf.hpp>
using namespace cv;
static void write_root_group_single_channel()
{
String filename = "root_group_single_channel.h5";
String dataset_name = "/single"; // 注意它时根组 / 的子组
// 准备数据
Mat data;
data = (cv::Mat_<float>(2, 3) << 0, 1, 2, 3, 4, 5, 6);
Ptr<hdf::HDF5> h5io = hdf::open(filename);
// 将数据写入给定的数据集
// 数据集 "/single" 是自动创建的,因为它时根组的子组
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();
}
static void write_single_channel()
{
String filename = "single_channel.h5";
String parent_name = "/data";
String dataset_name = parent_name + "/single";
// 准备数据
Mat data;
data = (cv::Mat_<float>(2, 3) << 0, 1, 2, 3, 4, 5);
Ptr<hdf::HDF5> h5io = hdf::open(filename);
// 首先,我们需要创建父组
if (!h5io->hlexists(parent_name)) h5io->grcreate(parent_name);
// 如果不存在,则创建数据集
if (!h5io->hlexists(dataset_name)) h5io->dscreate(data.rows, data.cols, data.type(), dataset_name);
// 以下内容与上面的函数 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();
}
/*
* 创建、读取和写入多通道矩阵
* 与单通道矩阵相同
*/
static void write_multiple_channels()
{
String filename = "two_channels.h5";
String parent_name = "/data";
String dataset_name = parent_name + "/two_channels";
// 准备数据
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);
// 首先,我们需要创建父组
if (!h5io->hlexists(parent_name)) h5io->grcreate(parent_name);
// 如果不存在,则创建数据集
if (!h5io->hlexists(dataset_name)) h5io->dscreate(data.rows, data.cols, data.type(), dataset_name);
// 以下内容与上面的函数 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;
}
从 Mat 派生的模板矩阵类。
定义 mat.hpp:2230
n 维密集数组类
定义 mat.hpp:812
uchar * data
指向数据的指针
定义 mat.hpp:2140
int channels() const
返回矩阵通道数。
int cols
定义 mat.hpp:2138
size_t total() const
返回数组元素的总数。
int rows
行和列的数量,或当矩阵具有超过 2 维时为 (-1, -1)
定义 mat.hpp:2138
int type() const
返回矩阵元素的类型。
std::string String
定义 cvstd.hpp:151
std::shared_ptr< _Tp > Ptr
定义 cvstd_wrapper.hpp:23
#define CV_32SC2
定义 interface.h:113
#define CV_Assert(expr)
在运行时检查条件,如果失败则抛出异常。
定义 base.hpp:342
int main(int argc, char *argv[])
定义 highgui_qt.cpp:3
与磁盘上的文件关联的文件存储的“黑盒”表示。
定义 core.hpp:102

解释

创建数据集的第一步是打开文件

Ptr<hdf::HDF5> h5io = hdf::open(filename);

对于函数 write_root_group_single_channel(),由于数据集名为 /single,它位于根组内,因此我们可以使用

// 将数据写入给定的数据集
// 数据集 "/single" 是自动创建的,因为它时根组的子组
h5io->dswrite(data, dataset_name);

将数据直接写入数据集,而无需事先创建它。因为它是在 cv::hdf::HDF5::dswrite() 中自动创建的。

警告
这仅适用于位于根组内的数据集。

当然,我们可以自己创建数据集

// 首先,我们需要创建父组
if (!h5io->hlexists(parent_name)) h5io->grcreate(parent_name);
// 如果不存在,则创建数据集
if (!h5io->hlexists(dataset_name)) h5io->dscreate(data.rows, data.cols, data.type(), dataset_name);

要从数据集读取数据,我们使用

Mat expected;
h5io->dsread(expected, dataset_name);

通过指定数据集的名称。

我们可以使用

double diff = norm(data - expected);
CV_Assert(abs(diff) < 1e-10);

来检查读出的数据是否与之前写入的数据完全一致。

结果

图 1 显示了使用 HDFView 工具可视化文件 root_group_single_channel 的结果。图 2 和图 3 分别给出了不在根组内的数据集的矩阵结果。
图 1:将单通道矩阵写入根组内的数据集的结果
图 2:将单通道矩阵写入不在根组内的数据集的结果