当前位置: 首页 > news >正文

五、cv::SparseMat的介绍和使用

文章目录

    • 一、cv::SparseMat的概述
    • 二、稀疏数组的创建
      • 2.1 基本语法
      • 2.2 创建稀疏数组的几种方式
      • 2.3 设置元素值(赋值)
      • 2.4 完整示例:创建 + 赋值 + 遍历
    • 三、稀疏数组的访问方法
      • 3.1 ref<T>(const int* idx)
      • 3.2 find<T>(const int* idx)
      • 3.3 ptr<T>(Node* node)
      • 3.4 cv::SparseMat::value\<T>()
    • 四、示例操作

一、cv::SparseMat的概述

  cv::SparseMat 是 OpenCV 中用于 表示稀疏矩阵(Sparse Matrix)的类。和 cv::Mat 用于存储 稠密矩阵(Dense Matrix)不同,cv::SparseMat 更适合用来表示那些 大多数元素为零或空值 的多维数组。

适用场景:

  • 多维数组(如高维空间向量)。
  • 大部分值为默认值(0)的矩阵。
  • 需要节省内存,且不频繁对所有元素进行访问。

基本特性:

  • 支持任意维度(不像 cv::Mat 只支持 2D)。
  • 仅存储非零值(以哈希表形式实现)。
  • 不支持连续内存访问(不像 cv::Mat 支持指针连续区域)。

二、稀疏数组的创建

2.1 基本语法

cv::SparseMat::SparseMat(int dims, const int* sizes, int type);
  • dims:维度数量(比如2D就是2,3D就是3)。
  • sizes:每一维的大小,是一个数组。
  • type:OpenCV 类型(如 CV_32F、CV_8U 等)。

2.2 创建稀疏数组的几种方式

示例1:创建一个 2D 的稀疏矩阵(5x5,类型 float)

int sizes[] = {5, 5};  // 表示 2D:5 行 5 列
cv::SparseMat sparseMat(2, sizes, CV_32F);

示例2:创建一个 3D 稀疏矩阵(10×10×10)

int sizes[] = {10, 10, 10};
cv::SparseMat sparse3D(3, sizes, CV_8U);

示例3:使用 cv::Mat 的类型宏

int sizes[] = {8, 8};
cv::SparseMat sparseMat(2, sizes, CV_64FC1);  // 64位浮点数

2.3 设置元素值(赋值)

int idx[] = {2, 3};  // 设置 [2][3] 处的值
sparseMat.ref<float>(idx) = 1.23f;

注意:

  • ref() 会在访问位置上自动创建元素。
  • 若该位置已存在,则直接修改其值。

2.4 完整示例:创建 + 赋值 + 遍历

#include <opencv2/opencv.hpp>
#include <iostream>int main() {int sizes[] = {5, 5};cv::SparseMat sm(2, sizes, CV_32F);// 设置几个稀疏元素int idx1[] = {0, 1};int idx2[] = {2, 3};sm.ref<float>(idx1) = 10.0f;sm.ref<float>(idx2) = 20.5f;// 遍历所有非零项for (cv::SparseMatConstIterator it = sm.begin(); it != sm.end(); ++it) {const cv::SparseMat::Node* node = it.node();const float* val = it.ptr<float>();std::cout << "Index: [" << node->idx[0] << "][" << node->idx[1] << "]"<< " = " << *val << std::endl;}return 0;
}

三、稀疏数组的访问方法

3.1 ref(const int* idx)

功能:返回对某个位置元素的引用,如果该元素不存在,则创建并返回默认值(0)。

示例:

int idx[] = {1, 2};
sparseMat.ref<float>(idx) = 3.14f;  // 如果不存在,会自动创建

3.2 find(const int* idx)

功能:返回该位置的值,如果不存在,返回 默认值(0),不会创建新元素。

示例:

int idx[] = {1, 2};
float value = sparseMat.find<float>(idx);

3.3 ptr(Node* node)

功能:给定一个已存在的 Node* 节点,返回其值的指针。

示例:

for (cv::SparseMatConstIterator it = sparseMat.begin(); it != sparseMat.end(); ++it) {const float* val = it.ptr<float>();  // 获取值
}

3.4 cv::SparseMat::value<T>()

功能:用于访问 稀疏矩阵中当前迭代器位置处的值 的函数。它常用于与 cv::SparseMatConstIterator 或 cv::SparseMatIterator 一起,在遍历稀疏矩阵的所有非零元素时进行读取。

用于遍历 cv::SparseMat 的元素:

for (cv::SparseMatConstIterator it = sm.begin(); it != sm.end(); ++it) {float v = it.value<float>();// 使用 v 进行逻辑处理
}

与此等价的访问方式是:

const float* ptr = it.ptr<float>();
float v = *ptr;

但 value() 更简洁,适合只读场景。

示例:使用 value() 遍历稀疏矩阵

#include <opencv2/opencv.hpp>
#include <iostream>int main() {int sizes[] = {3, 3};cv::SparseMat sm(2, sizes, CV_32F);int idx1[] = {0, 1};int idx2[] = {2, 2};sm.ref<float>(idx1) = 5.0f;sm.ref<float>(idx2) = 10.0f;std::cout << "稀疏矩阵中所有非零元素:" << std::endl;for (cv::SparseMatConstIterator it = sm.begin(); it != sm.end(); ++it) {const cv::SparseMat::Node* node = it.node();float value = it.value<float>();  // 👈 使用 value() 获取值std::cout << "Index: [" << node->idx[0] << "][" << node->idx[1]<< "] = " << value << std::endl;}return 0;
}

四、示例操作

示例:创建一个 500x500 的单通道稀疏图像,并设置部分像素

#include <opencv2/opencv.hpp>
#include <iostream>int main() {// 定义尺寸int sizes[] = {500, 500};// 创建单通道 8 位稀疏矩阵cv::SparseMat sparseImg(2, sizes, CV_8UC1);// 设置部分像素值为非零uchar value = 255;sparseImg.ref<uchar>(100, 100) = value;  // 设置点 (100, 100) 为白色sparseImg.ref<uchar>(200, 200) = value;sparseImg.ref<uchar>(300, 300) = value;// 将稀疏图像转换为普通图像用于显示cv::Mat denseImg(500, 500, CV_8UC1, cv::Scalar(0)); // 全部为0cv::SparseMatConstIterator it = sparseImg.begin();cv::SparseMatConstIterator it_end = sparseImg.end();for (; it != it_end; ++it) {const cv::SparseMat::Node* node = it.node();int x = node->idx[0];int y = node->idx[1];denseImg.at<uchar>(x, y) = it.value<uchar>();}// 显示图像cv::imshow("Sparse to Dense Image", denseImg);cv::waitKey(0);return 0;
}

输出结果:
在这里插入图片描述
说明:

  • cv::SparseMat(2, sizes, CV_8UC1):创建一个 2 维稀疏矩阵,类型为单通道 8 位。
  • ref<uchar>(x, y):返回对稀疏矩阵中位置 (x, y) 的引用,若不存在则创建。

为了显示,为什么必须将稀疏图像转成稠密图像?
因为 OpenCV 的图像显示函数(如 cv::imshow)只支持稠密矩阵(cv::Mat),不支持稀疏矩阵(cv::SparseMat)。

原因详解:
1、疏矩阵不是图像格式:cv::SparseMat 本质上是一个稀疏存储结构,它只记录非零位置的索引和值,其内存布局和普通图像的连续二维像素数据完全不同。它并不知道一个“图像”的概念,也无法提供完整的像素数组供 GUI 函数使用。

例如:

sparseMat.ref<uchar>(100, 100) = 255;

这只是记录了 (100, 100) 位置为 255,其余像素都“假设”为 0,实际上并不存在于内存中。

2、imshow 需要一个完整的、连续的像素块:cv::imshow(name, image) 需要图像尺寸、每个像素在内存中的位置、通道、位深度、步长(stride)。这些信息 cv::Mat 都提供了,但 cv::SparseMat 由于数据稀疏、结构不连续,根本无法满足这些要求。

http://www.lryc.cn/news/606381.html

相关文章:

  • CHI - Transaction介绍(1) - Dataless
  • MySQL 中 CHAR 和 VARCHAR 类型有什么区别?
  • 化学结构式解读指南:从基础认知到InDraw智能识别
  • TDengine 中 TDgp 中添加算法模型(预测分析)
  • 智慧城市多源监控协同精度↑28%:陌讯多模态融合算法实战解析
  • Git 详细安装配置教程(Windows版)
  • QT5 widget控件设置背景图不生效的解决方案
  • systmctl的作用,使用场景和用法
  • Maven 与单元测试:JavaWeb 项目质量保障的基石
  • 对于前端工程化的理解
  • Day07_C++编程
  • day066-内容分发网络(CDN)与web应用防火墙(WAF)
  • 【动态规划】数位dp
  • QT收费情况
  • SpringBoot实战:高效Web开发
  • SAM附录详解
  • Android依赖注入框架Hilt入门指南
  • iOS软件性能监控实战指南 开发到上线的完整流程解析
  • 上传文件到服务器
  • C++11特性——右值引用与移动语义
  • 基于大模型的知识库落地实施策略
  • 硬件-音频学习DAY1——音箱材料选择:密度板为何完胜实木
  • opencv解迷宫
  • 图论:SPFA算法
  • 20250731在荣品的PRO-RK3566开发板的Android13下解决敦泰的FT8206触控芯片的只有4点触控功能
  • 经典算法之美:冒泡排序的优雅实现
  • 【计算机网络】IP地址、子网掩码、网关、DNS、IPV6是什么含义?计算机中如何设置子网掩码与网关?
  • 分类-鸢尾花分类
  • 基于SpringBoot和SpringAI框架实践
  • 数据转换能干什么?有哪些好用的数据转换方法?