OpenCV中的Mat类

本文介绍了OpenCV中的Mat类,它是用于存储矩阵数据的核心类,包括向量、矩阵和图像。Mat类的创建、构造方式、赋值方法以及元素读取和运算操作进行了详细阐述,如默认构造、按大小和类型构造、使用已有矩阵构造等,并讨论了通过at、ptr和迭代器访问元素的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、Mat类简介

1.1、Mat类的作用

OpenCv提供了Mat类用来存储矩阵类型数据,包括向量、矩阵、图像等数据。Mat类分为分为矩阵头和指向存储数据的矩阵指针两部分。矩阵头包含矩阵的尺寸、存储方法、地址和引用次数。

#include <opencv2\opencv.hpp>
#include <iostream>
 
using namespace std;
using namespace cv;
 
int main()
{
    Mat a;
    a = imread("1.jpg",flags); //向a中赋值图像数据,flags指定读取图片的方式
    Mat b = a;//只是复制了矩阵头和指向存储数据的指针(指向的是同一个矩阵数据),相当于那段数据的别名.
    cv::imshow("image", a); //显示图片
    waitKey();
    return 0;
}

1.2、Mat类的创建

Mat b = Mat_<double>(3, 3);//创建一个3*3的矩阵存放double类型数据
Mat a(640, 480, CV_8UC3)//创建一个640*480的3通道矩阵用于存放彩色图像
Mat a(3, 3, CV_8UC1);//创建一个3*3的8位无符号整数的单通道矩阵
Mat a(3, 3, CV_8U);//创建单通道矩阵,C1标识可以省略

二、Mat类的构造

2.1、默认构造函数

//cv::Mat::Mat();
cv::Mat a = cv::imread("1.jpg",flags);

这种构造方式,不需要传递任何参数,在后续给变量赋值的时候会自动判断矩阵的类型与大小,实现灵活的存储,常用于存储读取的图像数据和某个函数运算的输出结果。

2.2、根据特定的大小和类型构造

//cv::Mat::Mat(int rows,int cols,int type)
int rows = a.rows, cols = a.cols;
cv::Mat b = cv::Mat(rows, cols, CV_8UC1);

2.3、用Size( )结构构造

//cv::Mat::Mat(Size size(), int type);
//size为二维数组变量尺寸,通过Size(cols,rows)进行赋值(列在前,行在后);type为矩阵存储的数据类型
cv::Mat a(Size(480,580), CV_8UC1);//构造一个行580,列480的单通道矩阵

2.4、利用已有矩阵构造

//cv::Mat::Mat(const Mat & a);
cv::Mat b(a);
//这种构造方式只是复制了Mat类的矩阵头,矩阵指针指向是同一个地址。(浅复制)
//若要深复制,可用
cv::Mat b = a.clone();

//cv::Mat::Mat(const Mat & a,const Range & rowRange, const Range & colRange=Range::all);
cv::Mat b(a, Range(2, 5), Range(1, 4));//从a中截取第二行到第五行,第一列到第四列的内容
cv::Mat b(a, Range(2, 5));//从a中截取第二行到第五行的内容,列范围省略时,所有的列都会被截取
//这种方式构造的类与已有Mat类共享数据

三、Mat类的赋值

3.1、在构造时赋值

//cv::Mat::Mat(int rows, int cols, int type, const Scalar & s)
//rows-矩阵的行数; cols-矩阵的列数;type-存储数据的类型;s-给矩阵中每个橡树赋值的参数变量
cv::Mat a(2, 2, CV_8UC3, cv::Scalar(0, 0, 255));//创建一个3通道矩阵,每个像素都是0,0,255
cv::Mat a(2, 2, CV_8UC2, cv::Scalar(0, 255));//创建一个2通道矩阵,每个像素都是0,255
cv::Mat a(2, 2, CV_8UC1, cv::Scalar(255));//创建一个单通道矩阵,每个像素都是255

3.2、直接赋值

cv::Mat a= (cv::Mat_<int>(3,3)<<1,2,3,4,5,6,7,8,9);
cv::Mat a = (cv::Mat_<double>(2, 3) << 1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
//该方式是一行一行的存入

3.3、循环赋值

cv::Mat a = (cv::Mat_<int>(3, 3));//定义一个3*3的矩阵
for(int i = 0; i < a.rows;i++) //矩阵行数循环
{
    for (int j; j < a.cols; j++) //矩阵列数循环
    {
        a.at<int>(i, j) = i + j;
    }
}

3.4、利用类方法赋值

 cv::Mat a = cv::Mat::eye(3, 3, CV_8UC1);
 cv::Mat c = cv::Mat::diag(b);
 cv::Mat d = cv::Mat::ones(3, 3, CV_8UC1);
 cv::Mat e = cv::Mat::zeros(3, 2, CV_8UC3);

四、Mat类的运算

4.1、加-减-乘-除运算

cv::Mat a = (cv::Mat_<int>(3, 3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);
cv::Mat b = (cv::Mat_<int>(3, 3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);
cv::Mat c = (cv::Mat_<double>(3, 3) << 1.0, 2.0, 3.0, 4.0,5.0, 6.0, 7.0, 8.0, 9.0);
cv::Mat d = (cv::Mat_<double>(3, 3) << 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
cv::Mat e, f, g, h,i;
e = a + b;
f = c - d;
g = 2 * a;
h = d / 2.0;
i = a - 1;

当两个Mat类进行加减运算时,需保证数据要一致,比如int和double类型数据的两个类不能进行加减运算。常数与Mat类变量运算,结果的数据类型保留Mat类变量的数据类型。

4.2、两个Mat类的乘法运算

cv::Mat a = (cv::Mat_<int>(3, 3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);
cv::Mat b = (cv::Mat_<int>(3, 3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);
cv::Mat c = (cv::Mat_<double>(3, 3) << 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
cv::Mat d = (cv::Mat_<double>(3, 3) << 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
cv::Mat e, f;
double k;
e = c*d;//数学乘积
k = a.dot(b);//内积,常数,对应列向量点乘后相加
f=a.mul(b)//对应位乘积

五、Mat类元素的读取

5.1、多通道Mat数据的存储示意图

3通道3*3矩阵存储方式

先存储第一个元素的三个通道数据,再存储第二个元素三个通道数据。

5.2、Mat类常见属性和方法

属性

作用

cols

矩阵的列数

rows

矩阵的行数

steps

以字节为单位的有效宽度

dims

矩阵的维度

成员方法

elemSize()

每个元素的字节数

total()

矩阵中元素的个数

channels()

矩阵的通道数

5.3、通过at读取Mat类单通道矩阵的元素

cv::Mat a = (cv::Mat_<int>(3, 3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);
int b = a.at<int>(0, 0);

通过at读取元素需要跟上“<数据类型>”,类型不匹配则会报错。该方法以坐标的形式给出需要读取的元素坐标(行数,列数)

5.4、通过at读取Mat类多通道矩阵的元素

因为单通道图像是一个二维矩阵,所以 at<>( , )方法的最后给出二维坐标即可访问对应位置元素。在OpenCv中,针对三通道,定义了,cv::Vec3b、cv::Vec3s、cv::Vec3w、cv::Vec3d、cv::Vec3f、cv::Vec3i共6种类型,其中数字表示通道数,最后一位是类型的缩写,b是uchar的缩写,s是short类型的缩写,w是ushort类型的缩写,d是double类型的缩写,f是float类型的缩写,i是int类型的缩写

cv::Mat a(3,4,CV_8UC3,Scalar(2,0,255));
cv::Vec3b b = a.at<Vec3b>(0, 0);
int first = b[0];  //值为2
int second = b.val[1];//值为0
int third = b.val[2];//值为255

5.5、通过指针ptr读取Mat矩阵种的元素

矩阵中每一行的每个元素都是挨着放的,如果能找到每一行元素的起始地址位置,那么读取矩阵中每一行不同位置的元素时将指针在起始位置向后移动若干位即可。

cv::Mat a(3,4,CV_8UC3,Scalar(2,0,255));
for (int i = 0; i < a.rows;i++)
{
    uchar *ptr = a.ptr<uchar>(i);
    for (int j = 0; j < a.cols*a.channels(); j++)
    {
        cout << (int)ptr[j] << endl;
    }
}

5.6、通过迭代器访问Mat类矩阵中的元素

Mat类变量也是一个容器变量,故Mat类变量拥有迭代器,用于访问Mat变量中的数据,通过迭代器可以实现对矩阵中每一个元素的遍历

cv::Mat a = (cv::Mat_<uchar>(3, 3) << 3, 4, 5, 1, 6, 7, 8, 0, 1);
cv::MatIterator_<uchar> it = a.begin < uchar > ();
cv::MatIterator_<uchar> it_end = a.end < uchar >();
for (int i = 0;it!=it_end;it++)
{
    cout << (int)(*it) << " ";
    if (++i%a.channels()==0)
    {
        cout << endl;
    }

}

Mat类的迭代器变量类型是cv::MatIterator_< >,在定义时同样需要在括号中声明数据的变量类型。Mat类迭代器的起始是Mat.begin< >(),结束是Mat.end< >(),与其他迭代器用法相同,通过“++”运算实现指针位置向下迭代,数据的读取方式是先读取第一个元素的每一个通道,之后再读取第二个元素的每一个通道,直到最后一个元素的最后一个通道

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值