- 计算机视觉
- 图像处理
- 深度学习
- 机器学习
【免费下载链接】opencv_contrib
Repository for OpenCV's extra modules
本指南围绕 opencv_contrib 仓库中modules/hdf模块的官方教程总览(table_of_content_hdf.markdown)展开,系统讲解如何借助 OpenCV 的 HDF5 I/O 接口完成三件事:创建组与子组、创建并读写数据集、读写属性。读完本文,你将掌握cv::hdf::HDF5的核心 API 用法、压缩与分块(chunking)等进阶特性,并能结合 HDFView / h5dump 工具验证写入结果。
背景:什么是 OpenCV 的 hdf 模块
hdf 模块是 opencv_contrib 中提供分层数据格式(Hierarchical Data Format)存储例程的扩展模块,模块入口声明位于 modules/hdf/include/opencv2/hdf.hpp。它封装了 HDF5(版本 5)的读写能力,让开发者可以直接用cv::Mat与cv::KeyPoint等 OpenCV 原生类型与.h5文件交互,而无需直接操作 HDF5 C API。
从 CMakeLists.txt 可以看到该模块的编译前提:
- 系统必须已安装 HDF5 库,CMake 通过
find_package(HDF5)完成探测; - Windows 上则通过
HDF_DIR环境变量查找头文件与动态库; - 若未找到 HDF5,会调用
ocv_module_disable(hdf)直接禁用该模块; - 模块最终链接
opencv_core并以 Python 包装形式(WRAP python)构建。
因此,使用本模块前必须先在你的系统上安装 HDF5 开发库(例如 Ubuntu 下sudo apt-get install libhdf5-dev),这也是官方教程在开头特别提示的前提条件。
教程总览:三个子教程对应三类核心能力
总览页将模块能力拆分为三个循序渐进的主题,每个主题都有独立的教程文档与可运行示例:
| 子教程 | 兼容版本 | 作者 | 核心能力 | 示例源码 |
|---|---|---|---|---|
| 创建组 | OpenCV > 3.0 | Fangjun Kuang | 创建组与子组 | create_groups.cpp |
| 创建、读写数据集 | OpenCV > 3.0 | Fangjun Kuang | 创建数据集并读写cv::Mat | create_read_write_datasets.cpp |
| 读写属性 | OpenCV > 3.4 | Fangjun Kuang | 读写根组属性 | read_write_attributes.cpp |
下面分别展开讲解,并补充来自 hdf5.hpp 接口定义的进阶细节。
创建组与子组
对应教程 how_to_create_groups.markdown,目标是创建 HDF5 文件、创建组、判断组是否存在、创建子组。
打开(或自动创建)HDF5 文件
一切操作从cv::hdf::open()开始。如果文件不存在会自动创建,否则以读写模式打开:
Ptr<hdf::HDF5> h5io = hdf::open("mytest.h5");从接口文档(hdf5.hpp)可知:该函数返回Ptr<HDF5>对象指针,对象使用完毕后必须调用close()释放。"/"表示根组(root 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";关键要点:
hlexists(label)用于检查任意 hdf5 链接(组、数据集或其他对象)是否存在,接口注释明确它是线程安全的;grcreate(grlabel)以默认属性创建组,创建后自动关闭句柄;不允许创建同名的组,否则会报错,所以创建前必须用hlexists检查;- 组可以嵌套,标签形如
Group1/SubGroup1,其中SubGroup1位于根组下的Group1之内。
创建子组:父组必须先存在
// 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";创建子组前必须确保父组已存在,否则抛出异常。完整示例见 create_groups.cpp,其执行流程为:open()→hlexists()→grcreate()→close()。
验证结果
用h5dump转储文件内容,可以看到清晰的层级结构:
$ h5dump mytest.h5 HDF5 "mytest.h5" { GROUP "/" { GROUP "Group1" { GROUP "SubGroup1" { } } } }下图是教程中给出的 HDFView 可视化结果,SubGroup1作为Group1的子组嵌套显示:
创建、写入与读取数据集
对应教程 create_read_write_dataset.markdown。数据集的载体是cv::Mat,教程明确说明:当前仅支持读写连续内存(continuous)的cv::Mat,其他数据类型尚未实现。
直接写入根组下的数据集(自动创建)
若数据集位于根组(/)之下,可以直接调用dswrite(),数据集会被自动创建:
// 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);⚠️ 此自动创建行为仅适用于根组的直接子数据集。
手动创建非根组数据集
对于非根组(如/data/single)中的数据集,需要先创建父组,再显式创建数据集:
// 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);dscreate(rows, cols, type, dslabel)是最基本的二维数据集创建接口,type可以是CV_8UC3、CV_32FC1、CV_64FC2等任意 OpenCV 类型。如果数据集已存在,dscreate会抛出异常,因此同样需要先hlexists检查。单通道与多通道矩阵的读写方式完全一致,例如示例中的CV_32SC2双通道矩阵:
Mat data(2, 3, CV_32SC2); for (size_t i = 0; i < data.total()*data.channels(); i++) ((int*) data.data)[i] = (int)i;读取并校验
Mat expected; h5io->dsread(expected, dataset_name); double diff = norm(data - expected); CV_Assert(abs(diff) < 1e-10);dsread()按标签读取整个数据集到Mat;若目标文件不存在会抛出异常。示例通过计算norm(data - expected)验证读回数据与原数据一致。
进阶:压缩、分块与维度信息
接口定义(hdf5.hpp)为数据集创建提供了大量可选能力:
- 压缩级别:
compresslevel取值 0–9,H5_NONE(-1)或 0 表示不压缩,9 表示最佳压缩比,但压缩级别越高计算开销越大;压缩依赖 GNU gzip; - 分块(chunking):
dims_chunks指定块 I/O 的大小。启用压缩必须配合内部分块;若未指定,默认以整个数据集为单个大块。合理的分块能显著提升窗口化读写的速度; - 无限维度:将 rows 或 cols 设为
H5_UNLIMITED(-1)可使该维度无限增长,但要求必须自定义分块,且写入必须用dsinsert()而不是dswrite(); - 多维数据集:
dscreate(n_dims, sizes, type, ...)支持创建 n 维存储空间; - 元数据查询:
dsgetsize(dslabel, dims_flag)可获取实际维度(H5_GETDIMS)、最大维度(H5_GETMAXDIMS)与分块尺寸(H5_GETCHUNKDIMS);dsgettype()返回与CvMat类型系统兼容的存储类型,可用CV_MAT_CN()和CV_MAT_DEPTH()解析通道数与数据类型; - 偏移写入:
dswrite(Array, dslabel, dims_offset, dims_counts)支持写入数据集中的指定窗口区域(offset 指定起始位置,counts 指定各维写入量)。
一个无限行数据集配合dsinsert()自动扩展的典型用法:
int chunks[2] = { 100, 100 }; // create Unlimited x 100 CV_64FC2 space h5io->dscreate(cv::hdf::HDF5::H5_UNLIMITED, 100, CV_64FC2, "hilbert", cv::hdf::HDF5::H5_NONE, chunks); int offset[2] = { 0, 0 }; for (int t = 0; t < 5; t++) { offset[0] += 100 * t; h5io->dsinsert(H, "hilbert", offset); }该场景下最终数据集的行数会随每次dsinsert自动扩展。下图展示了单通道矩阵写入根组数据集后的 HDFView 可视化结果:
关键点(KeyPoint)数据集的专用接口
除cv::Mat外,模块还提供了cv::KeyPoint的专用存取接口:kpcreate()、kpwrite()、kpread()、kpinsert()、kpgetsize()(见 hdf5.hpp)。它们同样支持压缩级别、分块大小与H5_UNLIMITED无限容量模式;kpwrite()在数据集不存在时会自动创建,而kpinsert()需要预创建且仅能在无限维度上扩展。
读写属性
对应教程 read_write_attributes.markdown。
支持范围与类型限制
属性(attribute)通常可挂载到组或数据集上,但当前 OpenCV 仅实现了根组属性的读写。支持的类型有四种:
intdoublecv::Stringcv::InputArray(仅限连续数组,如cv::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);写入前必须用atexists()确认属性不存在——若属性已存在,atwrite()会调用CV_Error()抛错。同理,删除属性用atdelete(),删除不存在的属性同样会报错。
字符串、整型与浮点型属性的写入方式完全一致:
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);读取属性
String expected_attr_str; h5io->atread(&expected_attr_str, attr_str_name);atread()要求属性必须存在,否则抛异常;建议先atexists()检查。完整示例 read_write_attributes.cpp 中,写入了Mat、String、int、double四类属性,并通过断言逐一校验读回结果与写入值一致(例如CV_Assert(norm(attr_mat - expected_attr_mat) < 1e-10))。
查看属性
用 HDFView 打开生成的attributes.h5,即可在根组下看到这些属性及其值;下图分别为根组属性列表和属性详细信息:
测试与更多参考
仓库内对应的单元测试位于 modules/hdf/test/test_hdf5.cpp,覆盖了组创建、数据集读写、属性读写、压缩、分块、无限维度扩展等场景,是验证 API 行为与编写自己代码时最直接的参考。三个示例程序均可作为可运行模板:
- create_groups.cpp —— 组与子组创建
- create_read_write_datasets.cpp —— 数据集创建与
cv::Mat读写 - read_write_attributes.cpp —— 根组属性读写
常见注意事项小结
- 依赖前置:使用 hdf 模块前必须在系统中安装 HDF5 开发库,且 CMake 能通过
find_package(HDF5)找到它,否则模块会被自动禁用(见 CMakeLists.txt)。 - 命名冲突:
grcreate()、dscreate()、atwrite()都不允许覆盖已存在的对象/属性,务必先用hlexists()/atexists()检查。 - 父组优先:创建子组或非根组数据集前,父组必须已经存在。
- 连续内存要求:数据集读写仅支持连续的
cv::Mat;属性数组同样要求连续。 - 线程安全边界:
hlexists()、dsread()、dswrite()等接口是线程安全的,但grcreate()、dscreate()、dsinsert()不保证线程安全;多线程写入建议限定在互不重叠的区域。 - 无限维度必须分块:任何维度使用
H5_UNLIMITED时都必须显式指定 chunk 大小,且写入需使用dsinsert()/kpinsert()以便自动扩展。 - 验证工具:Ubuntu 下可安装
sudo apt-get install hdf5-tools hdfview,用 HDFView 图形化查看或用h5dump命令行转储文件结构,是调试 HDF5 输出的高效手段。
- 计算机视觉
- 图像处理
- 深度学习
- 机器学习
【免费下载链接】opencv_contrib
Repository for OpenCV's extra modules
相关推荐
Archon 提供商能力矩阵(Provider Capability Matrix)深度解析:五个 AI 编码代理的能力差异、fail-fast 语义与自动生成机制
Archon 提供商能力矩阵(Provider Capability Matrix)深度解析:五个 AI 编码代理的能力差异、fail fast 语义与自动生成
计算机视觉图像处理深度学习机器学习OpenCV hdf 模块实战:基于 libhdf5 的分层数据读写、分组与属性操作指南
OpenCV hdf 模块实战:基于 libhdf5 的分层数据读写、分组与属性操作指南 导读 本文以 opencv_contrib 仓库中的 hdf 模块为主
计算机视觉图像处理深度学习机器学习MaaAssistantArknights 远程控制 API 协议详解:getTask 轮询、reportStatus 上报与任务编排实战
MaaAssistantArknights 远程控制 API 协议详解:getTask 轮询、reportStatus 上报与任务编排实战 MAA(MaaAss
计算机视觉图像处理深度学习机器学习
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考