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

news2025/1/4 19:19:50

介绍:用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进行更复杂的数学运算,或者反之亦然。两者之间的结合可以利用各自的优势。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spire.PDF for .NET【页面设置】演示:向 PDF 添加平铺背景图像

平铺背景通常是指用一个或多个小图像重复填充的背景。在本文中&#xff0c;您将学习如何在 PDF 中平铺图像&#xff0c;并使用 C# 和 VB.NET 为您的 PDF 创建平铺背景。 Spire.PDF for .NET 是一款独立 PDF 控件&#xff0c;用于 .NET 程序中创建、编辑和操作 PDF 文档。使用 …

文件本地和OSS上传

这里写目录标题 前端传出文件后端本地存储阿里云OSS存储上传Demo实现上传ConfigurationProperties 前端传出文件 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>上传文件</title> </head&g…

SpringCloud源码分析-Gateway

Gateway核心原理&#xff0c;请求经过一系列的责任链最后到达服务端。

两个等号和三个等号(待查资料)

1太癫了&#xff0c;居然时要才行&#xff0c;都不行 2. 三等号的结果 .。。。。毁灭吧

什么是神经网络?神经网络的基本组成部分训练神经网络激活函数有哪些局限性和挑战

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c; 忍不住分享一下给大家。点击跳转到网站 学习总结 1、掌握 JAVA入门到进阶知识(持续写作中……&#xff09; 2、学会Oracle数据库入门到入土用法(创作中……&#xff09; 3、手把…

《Java核心技术II》流中的filter、map和flatMap方法

filter、map和flatMap方法 filter filter通过转换产生过滤后的新流,将字符串流转化为只包含长单词的另一个流。 List words ...; Stream longWords words.stream().filter(w->w.length()>12) filter类型是Predicate(谓词&#xff0c;表示动作)类型对象&#xff0c…

linux进阶

目录 变量 shell变量 环境变量 预定义变量 位置变量 其他 管道与重定向 管道 重定向 shell脚本 分支结构 循环结构 数组 脚本实例 变量 shell变量 shell变量&#xff1a;shell程序在内存中存储数据的容器 shell变量的设置&#xff1a;colorred 将命令的结果赋值…

阿赵的MaxScript学习笔记分享十六《MaxScript和WinForm交互》

MaxScript学习笔记目录 大家好&#xff0c;我是阿赵。   之前有网友给我留言说MaxScript和DotNet的WinForm界面交互有问题。我回头看了一下&#xff0c;发现之前的MaxScript文章是漏了这部分没有说明&#xff0c;这里补充一下。这里的内容主要是用C#写一个WinForm界面&#x…

出海新势力:巴西短剧的崛起与出海系统开发平台的赋能

在全球短剧蓬勃发展的浪潮中&#xff0c;巴西短剧宛如一颗耀眼的新星&#xff0c;迅速在拉美文娱的天空中崭露头角&#xff0c;成为备受瞩目的潜力股&#xff0c;正以独特的魅力吸引着越来越多观众的目光&#xff0c;在国际舞台上绽放出属于自己的光彩。 巴西短剧缘何火爆&…

HTML5新特性|01 音频视频

音频 1、Audio (音频) HTML5提供了播放音频文件的标准 2、control(控制器) control 属性供添加播放、暂停和音量控件 3、标签: <audio> 定义声音 <source> 规定多媒体资源,可以是多个<!DOCTYPE html> <html lang"en"> <head><…

多模态论文笔记——Coca

大家好&#xff0c;这里是好评笔记&#xff0c;公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本文详细介绍多模态模型Coca&#xff0c;在DALLE 3中使用其作为captioner基准模型的原因和优势。 文章目录 ALBEF论文模型结构组成训练目标 CoCa​论文模型结构CoCa…

Flutter 调试环境下浏览器网络请求跨域问题解决方案

本篇文章主要讲解&#xff0c;Flutter调试环境情况下&#xff0c;浏览器调试报错跨域问题的解决方法&#xff0c;通过本篇文章你可以快速掌握Flutter调试环境情况下的跨域问题。 日期&#xff1a;2024年12月28日 作者&#xff1a;任聪聪 报错现象&#xff1a; 报文信息&#xf…

在K8S中,如何部署kubesphere?

在Kubernetes集群中&#xff0c;对于一些基础能力较弱的群体来说K8S控制面板操作存在一定的难度&#xff0c;此时kubesphere可以有效的解决这类难题。以下是部署kubesphere的操作步骤&#xff1a; 操作部署&#xff1a; 1. 部署nfs共享存储目录 yum -y install nfs-server e…

2024-12-29-sklearn学习(25)无监督学习-神经网络模型(无监督) 烟笼寒水月笼沙,夜泊秦淮近酒家。

文章目录 sklearn学习(25) 无监督学习-神经网络模型&#xff08;无监督&#xff09;25.1 限制波尔兹曼机25.1.1 图形模型和参数化25.1.2 伯努利限制玻尔兹曼机25.1.3 随机最大似然学习 sklearn学习(25) 无监督学习-神经网络模型&#xff08;无监督&#xff09; 文章参考网站&a…

数据挖掘——决策树分类

数据挖掘——决策树分类 决策树分类Hunt算法信息增益增益比率基尼指数连续数据总结 决策树分类 树状结构&#xff0c;可以很好的对数据进行分类&#xff1b; 决策树的根节点到叶节点的每一条路径构建一条规则&#xff1b;具有互斥且完备的特点&#xff0c;即每一个样本均被且…

数据仓库建设方案和经验总结

在做数据集成的过程中&#xff0c;往往第二步的需求就是建设数仓由于数据分散在不同的存储环境或数据库中&#xff0c;对于新业务需求的开发需要人工先从不同的数据库中同步、集中、合并等处理&#xff0c;造成资源和人力的浪费。同时&#xff0c;目前的系统架构&#xff0c;无…

迈向AGI,3、2、1,2025上链接!

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 往期精彩文章推荐 关于AI TIME AI TIME源起于2019年&#xff0c;旨在发扬科学思辨精神&#xff0c;邀请各界人士对人工智能理论、算法和场景应用的本质问题进行探索&#xff0c;加强思想碰撞&#xff0c;链接全…

云效流水线使用Node构建部署前端web项目

云效流水线实现自动化部署 背景新建流水线配置流水线运行流水线总结 背景 先来看看没有配置云效流水线之前的部署流程&#xff1a; 而且宝塔会经常要求重新登录&#xff0c;麻烦的很 网上博客分享了不少的配置流程&#xff0c;这一篇博客的亮点就是不仅给出了npm命令构建&…

计算机网络 (14)数字传输系统

一、定义与原理 数字传输系统&#xff0c;顾名思义&#xff0c;是一种将连续变化的模拟信号转换为离散的数字信号&#xff0c;并通过适当的传输媒介进行传递的系统。在数字传输系统中&#xff0c;信息被编码成一系列的二进制数字&#xff0c;即0和1&#xff0c;这些数字序列能够…

【Leecode】Leecode刷题之路第97天之交错字符串

题目出处 97-交错字符串-题目出处 题目描述 个人解法 思路&#xff1a; todo代码示例&#xff1a;&#xff08;Java&#xff09; todo复杂度分析 todo官方解法 97-交错字符串-官方解法 方法1&#xff1a;动态规划 思路&#xff1a; class Solution {public boolean isInte…