矩阵运算提速——玩转opencv::Mat

介绍:用Eigen或opencv::Mat进行矩阵的运算,比用cpp的vector或vector进行矩阵运算要快吗?

使用 Eigen 或 OpenCV 的 cv::Mat 进行矩阵运算通常比使用 std::vector<int>std::vector<double> 更快。这主要有以下几个原因:

  1. 优化的底层实现:Eigen 和 OpenCV 都是为高效的矩阵运算而设计的库,内部实现了许多优化,例如使用 SIMD(单指令多数据)指令、并行计算等。这些优化可以显著提高计算速度。

  2. 内存布局:Eigen 和 OpenCV 在内存布局上进行了优化,通常使用连续的内存块来存储矩阵数据,这样可以提高缓存命中率,从而加快访问速度。

  3. 专用的算法:这些库提供了许多专用的算法和函数,能够高效地执行常见的矩阵运算(如乘法、求逆、特征值分解等),而使用 std::vector 进行这些操作时,通常需要手动实现算法,效率较低。

  4. 类型安全和表达能力:Eigen 提供了强类型的矩阵和向量类,能够在编译时进行更多的检查,减少运行时错误,同时也使得代码更易于阅读和维护。

因此,如果你的应用涉及大量的矩阵运算,建议使用 Eigen 或 OpenCV 这样的专用库,而不是直接使用 std::vector

构造

link1

索引

访问Mat的通道数

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    // 创建一个3通道的彩色图像(例如,BGR格式)
    cv::Mat colorImage = cv::Mat::zeros(100, 100, CV_8UC3);

    // 创建一个单通道的灰度图像
    cv::Mat grayImage = cv::Mat::zeros(100, 100, CV_8UC1);

    // 获取通道数
    int colorChannels = colorImage.channels();
    int grayChannels = grayImage.channels();

    // 输出通道数
    std::cout << "彩色图像的通道数: " << colorChannels << std::endl; // 应该输出3
    std::cout << "灰度图像的通道数: " << grayChannels << std::endl;   // 应该输出1

    return 0;
}

定义4维Mat

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    // 定义4维矩阵,大小为2x3x4x5,数据类型为CV_32F(32位浮点数)
    cv::Mat mat4D(2, new int[4]{3, 4, 5}, CV_32F);

    // 填充矩阵
    for (int i = 0; i < 2; ++i) {
        for (int j = 0; j < 3; ++j) {
            for (int k = 0; k < 4; ++k) {
                for (int l = 0; l < 5; ++l) {
                    mat4D.at<float>(i, j, k, l) = static_cast<float>(i * 1000 + j * 100 + k * 10 + l);
                }
            }
        }
    }

    // 输出矩阵的形状和内容
    std::cout << "4维矩阵的大小: " << mat4D.size << std::endl;
    std::cout << "4维矩阵的内容:" << std::endl;

    for (int i = 0; i < 2; ++i) {
        for (int j = 0; j < 3; ++j) {
            for (int k = 0; k < 4; ++k) {
                for (int l = 0; l < 5; ++l) {
                    std::cout << mat4D.at<float>(i, j, k, l) << " ";
                }
                std::cout << std::endl;
            }
            std::cout << std::endl;
        }
    }

    // 释放动态分配的内存
    delete[] mat4D.size;

    return 0;
}

取某一行

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    // 创建一个 3x3 的矩阵
    cv::Mat mat = (cv::Mat_<float>(3, 3) << 1, 2, 3,
                                             4, 5, 6,
                                             7, 8, 9);

    // 获取第 3 行(索引为 2)的所有元素
    cv::Mat thirdRow = mat.row(2); // 行索引从 0 开始

    // 输出结果
    std::cout << "第三行的元素是:" << std::endl;
    std::cout << thirdRow << std::endl;

    return 0;
}

提取块

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    // 创建一个 5x5 的矩阵
    cv::Mat mat = (cv::Mat_<float>(5, 5) << 1, 2, 3, 4, 5,
                                             6, 7, 8, 9, 10,
                                             11, 12, 13, 14, 15,
                                             16, 17, 18, 19, 20,
                                             21, 22, 23, 24, 25);

    // 定义要提取的块的起始位置和大小
    int startRow = 1; // 起始行索引
    int startCol = 1; // 起始列索引
    int blockRows = 3; // 块的行数
    int blockCols = 3; // 块的列数

    // 提取块
    cv::Mat block = mat(cv::Range(startRow, startRow + blockRows), cv::Range(startCol, startCol + blockCols));

    // 输出结果
    std::cout << "提取的块是:" << std::endl;
    std::cout << block << std::endl;

    return 0;
}

访问某行某列的元素

在C++中,使用OpenCV库的cv::Mat类来表示图像或矩阵。要访问cv::Mat中的特定行和列的元素,可以使用at(row, col)方法,其中type是元素的数据类型。

#include <iostream>
#include <opencv2/opencv.hpp>

int main() {
    // 创建一个3x3的矩阵,类型为CV_8UC1(单通道8位无符号整数)
    cv::Mat mat = (cv::Mat_<uchar>(3, 3) << 1, 2, 3,
                                             4, 5, 6,
                                             7, 8, 9);

    // 输出整个矩阵
    std::cout << "矩阵内容:\n" << mat << std::endl;

    // 访问特定行和列的元素
    int row = 1; // 第二行(索引从0开始)
    int col = 2; // 第三列(索引从0开始)

    // 使用at方法访问元素
    uchar value = mat.at<uchar>(row, col);
    std::cout << "元素在 (" << row << ", " << col << ") 的值: " << (int)value << std::endl;

    // 修改特定行和列的元素
    mat.at<uchar>(row, col) = 10;
    std::cout << "修改后的矩阵内容:\n" << mat << std::endl;

    return 0;
}

示例输出:

矩阵内容:
[1, 2, 3;
4, 5, 6;
7, 8, 9]
元素在 (1, 2) 的值: 6
修改后的矩阵内容:
[1, 2, 3;
4, 5, 10;
7, 8, 9]

运算

矩阵乘法和Hamornoid积

#include <iostream>
#include <opencv2/opencv.hpp>

int main() {
    // 创建两个相同维度的矩阵
    cv::Mat mat1 = (cv::Mat_<float>(2, 2) << 1, 2,
                                              3, 4);
    cv::Mat mat2 = (cv::Mat_<float>(2, 2) << 5, 6,
                                              7, 8);

    // 输出原始矩阵
    std::cout << "矩阵1:\n" << mat1 << std::endl;
    std::cout << "矩阵2:\n" << mat2 << std::endl;

    // 方法1:使用 cv::multiply
    cv::Mat result1;
    cv::multiply(mat1, mat2, result1);
    std::cout << "矩阵乘法 (使用 cv::multiply):\n" << result1 << std::endl;

    // 方法2:使用 cv::mul
    cv::Mat result2 = mat1.mul(mat2); // 也可以使用 result2 = mat1 * mat2;
    std::cout << "矩阵乘法 (使用运算符 *):\n" << result2 << std::endl;

    // 方法3:使用运算符 *
    cv::Mat result3 = mat1*mat2; // 也可以使用 result2 = mat1 * mat2;
    std::cout << "逐元素相乘结果 (使用运算符 *):\n" << result3 << std::endl;

    return 0;
}

类型一致

  • opencv::Mat之间的加减乘除必须保证类型相同
  • 比如cv::divide()运算
cv::divide(new_cen, cen_index[cen_id].size(), new_cen);
  • opencv::Mat的类型有如下几种:
    在这里插入图片描述* 可在初始化时指定
	Mat new_cen=Mat::zeros(1,128,CV_32FC1);

opencv::Mat是继承Eigen的实现吗?

cv::Mat并不是继承自Eigen库的实现。OpenCV和Eigen是两个独立的库,它们各自有自己的数据结构和实现方式。

OpenCV的cv::Mat

  • cv::Mat是OpenCV中用于表示图像和矩阵的主要数据结构。它提供了多种功能,包括图像处理、矩阵运算、图像读取和写入等。
  • cv::Mat支持多维数组,能够处理不同的数据类型(如8位无符号整数、浮点数等),并且可以表示单通道和多通道图像(如RGB图像)。
  • OpenCV的设计目标是高效处理图像和视频数据,特别是在计算机视觉和图像处理领域。

Eigen库:

  • Eigen是一个用于线性代数的C++模板库,提供了矩阵和向量的高效操作。它专注于数学运算,特别是线性代数、几何变换和数值计算。
  • Eigen的设计目标是提供高性能的数学运算,同时保持易用性和灵活性。

结论:

虽然OpenCV和Eigen都涉及矩阵和线性代数的概念,但它们是独立的库,cv::Mat并不继承自Eigen的实现。实际上,OpenCV和Eigen可以一起使用,开发者可以在OpenCV中处理图像数据,然后使用Eigen进行更复杂的数学运算,或者反之亦然。两者之间的结合可以利用各自的优势。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/947065.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

FastDeploy部署paddlecls分类模型(windows)

目录 写在前面 总体步骤 C SDK编译库 方式1&#xff1a;编译安装 方式2&#xff1a;下载预编译库 准备模型、文件、代码和数据 模型文件类型 samples代码 待预测图像 使用 FastDeploy C SDK 将cpp源码编译为exe 编写cpp代码 cpp代码编译exe 运行可执行程序exe 将…

【第二部分--Python之基础】03 容器类型的数据

Python内置的数据类型如序列&#xff08;列表、元组等&#xff09;、集合和字典等可以容纳多项数据&#xff0c;我们称它们为容器类型的数据。 序列 序列&#xff08;sequence&#xff09;是一种可迭代的、元素有序的容器类型的数据。 序列包括列表&#xff08;list&#xff…

linux shell脚本 【分支结构case...in 、循环结构、函数】内附练习

1.思维导图 2.练习 1.定义一个find函数&#xff0c;查找ubuntu和root的gid 2.定义一个数组&#xff0c;写一个函数完成对数组的冒泡排序 bubble() {n${#arr[*]}for((i0;i<n-1;i));dofor((j0;j<n-1-i;j));doif ((arr[j]>arr[j1]));thentemp${arr[j]}arr[j]${arr[j1]}a…

基于SpringBoot和OAuth2,实现通过Github授权登录应用

基于SpringBoot和OAuth2&#xff0c;实现通过Github授权登录应用 文章目录 基于SpringBoot和OAuth2&#xff0c;实现通过Github授权登录应用0. 引言1. 创建Github应用2. 创建SpringBoot测试项目2.1 初始化项目2.2 设置配置文件信息2.3 创建Controller层2.4 创建Html页面 3. 启动…

从单点 Redis 到 1 主 2 从 3 哨兵的架构演进之路

一、前言 我们有个项目中用的 MySQL、Redis、ES、微服务都是单节点部署的&#xff0c;没有做集群模式部署&#xff0c;为了提高整体的可用性&#xff0c;对项目的部署架构进行了升级&#xff0c;支持高可用。 二、部署拓扑图 我们项目的测试环境 12 台服务器已经部署好了&am…

SQL 中的 EXISTS

我们先从 SQL 中最基础的 WHERE 子句开始。 比如下面这条 SQL 语句&#xff1a; 很显然&#xff0c;在执行这条 SQL 语句的时候&#xff0c;DBMS 会扫描 Student 表中的每一条记录&#xff0c;然后把符合 Sdept IS 这个条件的所有记录筛选出来&#xff0c;并放到结果集里面去…

大型概念模型:在句子表示空间中的语言建模

《Large Concept Models: Language Modeling in a Sentence Representation Space》这篇论文介绍了一种新的语言模型方法&#xff0c;它在句子表示空间中进行建模。该方法旨在改进传统语言模型的局限性&#xff0c;通过捕捉更高级别的语义信息来提高自然语言处理任务的表现。 模…

活动预告 | Microsoft Power Platform 在线技术公开课:实现业务流程自动化

课程介绍 参加“Microsoft Power Platform 在线技术公开课&#xff1a;实现业务流程自动化”活动&#xff0c;了解如何更高效地开展业务。参加我们举办的本次免费培训活动&#xff0c;了解如何借助 Microsoft AI Builder 和 Power Automate 优化工作流。结合使用这些工具可以帮…

YK人工智能(三)——万字长文学会torch深度学习

2.1 张量 本节主要内容&#xff1a; 张量的简介PyTorch如何创建张量PyTorch中张量的操作PyTorch中张量的广播机制 2.1.1 简介 几何代数中定义的张量是基于向量和矩阵的推广&#xff0c;比如我们可以将标量视为零阶张量&#xff0c;矢量可以视为一阶张量&#xff0c;矩阵就是…

企业二要素如何用C#实现

一、什么是企业二要素&#xff1f; 企业二要素&#xff0c;通过输入统一社会信用代码、企业名称或统一社会信用代码、法人名称&#xff0c;验证两者是否匹配一致。 二、企业二要素适用哪些场景&#xff1f; 例如&#xff1a;信用与金融领域 1.信用评级&#xff1a;信用评级…

Visual Studio 2022安装教程

1、下载网址 Visual Studio 2022 IDE安装网址借助 Visual Studio 设计&#xff0c;具有自动完成、构建、调试、测试功能的代码将与 Git 管理和云部署融为一体。https://visualstudio.microsoft.com/zh-hans/vs/ 点击图片所示 双击运行 2、安装 点击C桌面开发&#xff08;右边…

TVS二极管选型【EMC】

TVS器件并联在电路中&#xff0c;当电路正常工作时&#xff0c;他处于截止状态&#xff08;高阻态&#xff09;&#xff0c;不影响线路正常工作&#xff0c;当线路处于异常过压并达到其击穿电压时&#xff0c;他迅速由高阻态变为低阻态&#xff0c;给瞬间电流提供一个低阻抗导通…

redis的集群模式与ELK基础

一、redis的集群模式 1.主从复制 &#xff08;1&#xff09;概述 主从模式&#xff1a;这是redis高可用的基础&#xff0c;哨兵和集群都是建立在此基础之上。 主从模式和数据库的主从模式是一样的&#xff0c;主负责写入&#xff0c;然后把写入的数据同步到从服务器&#xff…

Kubernetes第三天

1.pod容器的三种重启策略 查看容器的重启策略有哪些 kubectl explain po.spec. 发现有Always OnFailure Never Always,当容器退出时&#xff0c;始终重启容器 OnFailure,当容器正常退出时&#xff0c;不会自动重启容器&#xff0c;当容器异常退出时&#xff0c;重启容器 …

61.旋转链表 python

旋转链表 题目题目描述示例 1&#xff1a;示例 2&#xff1a;提示&#xff1a; 题解思路分析Python 实现代码代码解释提交结果 题目 题目描述 给你一个链表的头节点 head &#xff0c;旋转链表&#xff0c;将链表每个节点向右移动 k 个位置。 示例 1&#xff1a; 输入&#…

什么时候出现对象?芊芊测字,ai测字

芊芊测字地址&#xff1a;芊芊测字-ai免费测字

SpringMVC(1)——SpringMVC配置和基本原理

目录 ​编辑 第一章&#xff1a;Java web的发展历史 一.Model I和Model II 1.Model I开发模式&#xff08;已经淘汰&#xff09; 2.Model II开发模式 二. MVC模式 第二章&#xff1a;SpringMVC的入门案例 搭建SpringMVC的入门程序 ①&#xff1a;创建WEB工程&#xff…

Switch组件的用法

文章目录 1 概念介绍2 使用方法3 示例代码我们在上一章回中介绍了PageView这个Widget,本章回中将介绍Switch Widget.闲话休提,让我们一起Talk Flutter吧。 1 概念介绍 我们在这里介绍的Switch是指左右滑动的开关,常用来表示某项设置是打开还是关闭。Flutter中使用Switch类表…

电脑中缺失的nvrtc64_90.dll文件如何修复?

一、文件丢失问题 案例&#xff1a;nvrtc64_90.dll文件缺失 问题分析&#xff1a; nvrtc64_90.dll是NVIDIA CUDA Runtime Compilation库的一部分&#xff0c;通常与NVIDIA的CUDA Toolkit或相关驱动程序一起安装。如果该文件丢失&#xff0c;可能会导致基于CUDA的应用程序&…

Springboot使用RabbitMQ实现关闭超时订单的一个简单示例

1.maven中引入rabbitmq的依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency> 2.application.yml中进行rabbitmq相关配置&#xff1a; # rabbit…