Mat类相关操作Opencv的入门基础
初始化构造函数
mat类是opencv中一个非常重要的数据结构,在这里先记录一下最基础的知识,也是最重要的知识吧,千里之行始于足下。
构造函数 | 说明 |
---|---|
cv:Mat(int rows ,int cows, int type) | 指定类型的二维数组 |
CV::Mat(int rows ,int cows,int type,const Saclar&s) | 指定类型的二维数组,并初始化 |
CV::Mat(cv::Size sz,int type) | 指定类型的二维数组,大小由sz定 |
CV::Mat(int rows ,int cows,int type,void*data,size_t_step=AUTO_STEP) | 指定类型的二维数组,并指定预先存储的数据 |
CV::Mat(cv::Size sz,int type,const Saclar&s) | 指定类型的二维数组,并初始化,大小由sz定 |
CV::Mat(cv::Size sz,int type,void*data,size_t_step=AUTO_STEP)- | 指定类型的二维数组,并初始化,大小由sz定,并指定预先存储的数据 |
cv::Mat(int ndims,const int *sizes,int type) | 指定类型的多维数组 |
cv::Mat(int ndims,const int *sizes,int type,const Saclar&s) | 指定类型的多维数组 ,并初始化 |
cv::Mat(int ndims,const int sizes,int type,voiddata,size_t_step=AUTO_STEP) | 指定类型的多维数组,并指定预先存储的数据 |
数据类型
CV_8U-8 位无符号整数 (0……255)
• CV_8S-8 位符号整数 (-128……127)
• CV_16U-16 位无符号整数 (0……65535)
• CV_16S-16 位符号整数 (-32768……32767)
• CV_32S-32 位符号整数 (-2147483648……2147483647)
• CV_32F-32 位浮点数 (-FLT_MAX ………FLT_MAX,INF,NAN)
• CV_64F-64 位浮点数(-DBL_MAX ……….DBL_MAX,INF,NAN)
#define CV_8U 0 //对应uchar
#define CV_8S 1 //对应char
#define CV_16U 2 //对应ushort
#define CV_16S 3 //对应short
#define CV_32S 4 //对应int
#define CV_32F 5 //对应float
#define CV_64F 6 //对应double
代码演示
#pragma once
#include <iostream>
#include <string>
#include<cctype>
#include <fstream>
#include<vector>
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/highgui/highgui.hpp"
using namespace cv;
using namespace std;
int main()
{
//cv:Mat(int rows ,int cows, int type)
Mat m = Mat(10, 10, CV_16F);
cout << m << endl;//10*10的矩阵未初始化
//CV::Mat(int rows ,int cows,int type,const Saclar&s)
Mat m2 = Mat(10, 10, CV_16F, Scalar(0));//初始化均为0
int a[3][2] = { {5,3},{4,5},{5,6} };
//CV::Mat(int rows ,int cows,int type,void*data,size_t_step=AUTO_STEP)
Mat m3 = Mat(3, 2, CV_32S,a);//指定数组初始化
//CV::Mat(cv::Size sz,int type,const Saclar&s)
Mat m4 = Mat(Size(10,10), CV_16F, Scalar(0));//初始化均为0
//CV::Mat(cv::Size sz,int type,void*data,size_t_step=AUTO_STEP)
Mat m5 = Mat(Size(2,3), CV_32S, a);//指定数组初始化,注意和m3的方式略有不同
cout << m3 << endl;
cout << m2 << endl;
cout << m5 << endl;
cout << "hello,world" << endl;
system("pause");
}
复制数据的构造函数
cv::Mat(const Mat&mat); 复制构造函数
CV::Mat(const Mat&mat,const cv::Range&rows,CV::Rang&clos) 从指定行列中复制构造
CV::Mat((const Mat&mat,const cv::Rect&roi) 从感兴趣区域复制
CV::Mat(const Mat&mat,const Range *ranges) 从泛化的感兴趣区域复制
cv::Mat(const cv::MatExpr&expr) 从其他矩阵的线性代数表达式中生成新的复制构造函数
代码演示
#pragma once
#include <iostream>
#include <string>
#include<cctype>
#include <fstream>
#include<vector>
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/highgui/highgui.hpp"
using namespace cv;
using namespace std;
int main()
{
Mat m = imread("D:\\My code\\Python\\opencv\\study\\01.jpg");
//cv::Mat(const Mat&mat);
Mat b = Mat(m);
//CV::Mat(const Mat&mat, const cv::Range&rows, CV::Rang&clos)
Mat r = Mat(m, Range(200, 300), Range(100, 200));//选取区域rows::Range(200, 300),cols:: Range(100, 200)
//CV::Mat((const Mat&mat,const cv::Rect&roi)
Mat rb = Mat(m, Rect(100, 200, 100, 100));//和r的结果一样
cout << "hello,world" << endl;
system("pause");
}
结果
模板构造
(Mat_<>()<<2,345,53,) ,自定义输入矩阵。
Mat tt = (Mat_<int>(2, 3) << 3, 4, 5, 6, 7, 8);
访问Mat数组的方法
1.at<>方法相对来说简单
Mat tt = (Mat_<int>(2, 3) << 3, 4, 5, 6, 7, 8);
tt.at<int>(1,1);//结果为7
tt.at<int>(3)//结果为6 m.at<>(i) 访问数组中的第i个元素
2使用Mat的成员函数ptr<>()
Mat tt = (Mat_<int>(2, 3) << 3, 4, 5, 6, 7, 8);
int *p=tt.ptr<int>(1);//返回的是一个指针
cout <<p[1] << endl;通过指针的方式访问,也可以*(p+1)结果为7
3.内置的迭代器(推荐使用迭代器或者指针的方式访问元素)
此处的迭代器和c++中的迭代器用法类似,这种方法能够较为高效的访问数组元素,而且不容易发生数组的的越界行为
Mat tt = (Mat_<int>(2, 3) << 3, 4, 5, 6, 7, 8);
cout << tt << endl;
MatIterator_<int>it = tt.begin<int>();
while (it!=tt.end<int>())
{
cout << *it << endl;
it++;
}
通过块访问数组元素
示例 | 描述 |
---|---|
m.row(i) | m中的第i行数组 |
m.col(j) | m中的第j列数组 |
m.rowRang(i0,i1) | m中第i行到i1行的数组 |
m.colRang(j0,j1) | m中第j列到j1列的数组 |
m.rowRang(Rang(i0,i1)) | m中第i行到第i1行的数组 |
m.colRang(Rang(j0,j1)) | m中第j列到j1列的数组 |
m.diag(d) | m中偏移为d的对角线所组成的数组 |
m(Rang(i0,j0),Rang(j0,j1)) | m中第j列到j1列到第i行到第i1行构成的新数组 |
m(Rect()) | 和上一个类似 |
示例代码:
Mat tt = (Mat_<int>(3, 3) << 3, 4, 5, 6, 7, 8,9,10,11);
cout << tt << endl;//[3, 4, 5; 6, 7, 8;9, 10, 11]
cout << tt.row(1) << endl;//[6, 7, 8]
cout << tt.col(1) << endl;//[4;7; 10]
cout << tt.colRange(0, 2) << endl;//[3, 4;6, 7;9, 10]
cout << tt.rowRange(0, 2) << endl;//[3, 4, 5; 6, 7, 8]
cout << tt.diag(1) << endl;//[4; 8]
被重载的运算操作符+,-,*
示例 | 描述 |
---|---|
m0+m1,m0-m1 | 矩阵的加减 |
m0+s0,m0-s0 | 矩阵和单个元素的加减 |
s*m0 | 矩阵和单个元素的乘法 |
m0.mul(m1),m0/m1 | 矩阵元素的逐一乘除 |
m0.inv() | 矩阵的逆 |
m0.t() | 矩阵的转置 |
m0>m1 | 矩阵的比较,逐个元素 |
m0^m1 ,m0&m1 | 矩阵的逐个元素的逻辑操作 |
min(m0,m1),max(m0,m1),min(m0,s) | 矩阵和矩阵之间单个元素取最小最大,矩阵和数之间的比较 |
abs(m0) | 矩阵的逐个元素求绝对值 |
代码示例
Mat tt = (Mat_<double>(3, 3) << 1, 4, 5, 6, 7, 8,9,10,11);
Mat tt3 = (Mat_<double>(2, 2) << 1, 4, 5, 6);
Mat tt2 = (Mat_<double>(3, 3) << 5, 6, 5, 6, 7, 8, 9, 10,12);
cout << "(tt+tt2):"<<endl<<(tt+tt2) << endl;
cout << "(tt+2):" << endl<<(tt+2) << endl;
cout << "(tt*2):" << endl<<(tt*2) << endl;
cout << "(tt.mul(tt2)):" << endl << (tt.mul(tt2)) << endl;
cout << "(tt/tt2):" << endl << (tt/tt2) << endl;
cout << "tt3.inv():" << endl << (tt3.inv() )<< endl;
cout << "tt.t():" << endl << tt.t() << endl;
//结果
#if 0
(tt+tt2):
[6, 10, 10;
12, 14, 16;
18, 20, 23]
(tt+2):
[3, 6, 7;
8, 9, 10;
11, 12, 13]
(tt*2):
[2, 8, 10;
12, 14, 16;
18, 20, 22]
(tt.mul(tt2)):
[5, 24, 25;
36, 49, 64;
81, 100, 132]
(tt/tt2):
[0.2, 0.6666666666666666, 1;
1, 1, 1;
1, 1, 0.9166666666666666]
tt3.inv():
[-0.4285714285714285, 0.2857142857142857;
0.3571428571428571, -0.07142857142857142]
tt.t():
[1, 6, 9;
4, 7, 10;
5, 8, 11]
#end if
向量的叉乘和点乘
m.cross(m1) 叉乘, m0.dot(m1)点乘
Mat tt1 = (Mat_<double>(1, 3) << 1, 4, 5);
Mat tt2 = (Mat_<double>(3, 1) << 1, 3, 5);
cout << (tt1.dot(tt2.t())) << endl;//38
cout << (tt1.cross(tt2.t())) << endl;//[5, 0, -1]
//这里不需要将两个向量写成3*1,1*3的形式,都是3*1和3*1就好了。
数组其他的成员函数
示例 | 描述 |
---|---|
m1.clone() | 克隆一个矩阵,重新分配存储空间 |
m1.copyTo(m2) | 把m1复制给m2 |
m1.converTo(m2,type) | 重新调整Mat的数据类型 |
m1.reshap(chan,rows) | 重新调整数组的形状和reshape一样 |
m1.push_back(m) | 在末尾添加一行 |
m1.total() | 计算数组序列的元素的数目 |
m1.elemSize() | 返回m0的位长度 |
m1.type() | 返回元素类型 |
m1.depth() | 返回通道中的元素类型 |
m1.channels() | 返回通道数目 |
m1.empty() | 检查矩阵是否为空 |
这些方法比较简单,在此就不作代码演示,如有需要可以百度具体的函数用法。
矩阵的操作(基础操作)
cv::abs() 计算矩阵的绝对值
Mat tt1 = (Mat_<double>(1, 3) << -1, 2, 5);
Mat tt2 = (Mat_<double>(1, 3) << 1, 3, 5);
cout << abs(tt1) << endl;//[1, 2, 5]
cout << abs(tt1-tt2) << endl;//[2, 1, 0]
cv::add(src,src1,dst)矩阵相加
Mat tt1 = (Mat_<double>(1, 3) << -1, 2, 5);
Mat tt2 = (Mat_<double>(1, 3) << 1, 3, 5);
Mat dst;
add(tt1, tt2, dst);
cout << dst << endl;//[0, 5, 10]
cv::addweighted(src1,alpha,src2,beta,gamma,srt)带有权重的相加
dst=src1alpha+src2beta+gamma
Mat tt1 = (Mat_<double>(1, 3) << -1, 2, 5);
Mat tt2 = (Mat_<double>(1, 3) << 1, 3, 5);
Mat dst;
addWeighted(tt1,0.5, tt2,0.5,1, dst);
cout << dst << endl;//[1, 3.5, 6]
应用:图像混合
Mat m = imread("D:\\My code\\Python\\opencv\\study\\01.jpg");
Mat b = imread("D:\\My code\\Python\\opencv\\study\\04.jpg");
Mat b1 (b, Rect(100, 100, 200, 100));//选取的roi区域,浅拷贝
Mat m1 (m, Rect(200, 140, 200, 100));//选取的roi区域,浅拷贝
addWeighted(b1, 0.5, m1, 0.5, 0, m1);//把相加后的结果放到m中的m1区域
imshow("dd", m);
cv::bitwise_and(),cv::bitwise_not(),cv::bitwise_or(),cv::bitwise_xor() 按位操作
cv::determinant(m0),计算方阵的行列式
cv::eigen(m0);计算方阵的特征值和特征向量
Mat tt=(Mat_<double>(3, 3) << 12, 3, 21, 3, 12, 31, 2, 4, 3);
Mat det = (Mat_<double>(1, 3) << 0, 0, 0);//注意类型为CV_64f或者cv_32f
eigen(tt, det);
cout << det << endl;//[46.8162253176873;9.208629402538843 -29.02485472022613]
cv::exp()元素逐个求幂
函数 | 描述 |
---|---|
cv::Mahalanobis() | 计算两个矩阵的马氏距离 |
cv::mean | 计算矩阵元素的平均值 |
CV::merge | 将多个单通道合成一个多通道 |
cv::norm | 计算两个矩阵的归一化相关系数 |
cv::normlize | 归一化处理 |
cv::minMaxLoc(src,&min,&max,&Point1,&point2) | 计算矩阵的最大最小值 |
cv::randu | 用均匀分布填充矩阵 |
cv::randn | 用正态分布填充矩阵 |
cv::randShuffle | 打乱矩阵 |
cv::setIdentity() | 将矩阵的对角线设置成1,其他设置成0 |
cv:solve() | 求解线性方程的解 |
cv:sort() | 排序矩阵中任意行或者列的元素 |
cv:theRNG() | 返回随机数生成器 |
cv::norm(src1)
cv::norm(src1,src2)
不同参数的计算方法
void cv::normalize ( InputArray src,
InputOutputArray dst,
double alpha = 1,
double beta = 0,
int norm_type = NORM_L2,
int dtype = -1,
InputArray mask = noArray()
)
vector<double> positiveData = { 2.0, 8.0, 10.0 };
vector<double> normalizedData_l1, normalizedData_l2, normalizedData_inf, normalizedData_minmax;
// Norm to probability (total count)
// sum(numbers) = 20.0
// 2.0 0.1 (2.0/20.0)
// 8.0 0.4 (8.0/20.0)
// 10.0 0.5 (10.0/20.0)
normalize(positiveData, normalizedData_l1, 1.0, 0.0, NORM_L1);
// Norm to unit vector: ||positiveData|| = 1.0
// 2.0 0.15
// 8.0 0.62
// 10.0 0.77
normalize(positiveData, normalizedData_l2, 1.0, 0.0, NORM_L2);
// Norm to max element
// 2.0 0.2 (2.0/10.0)
// 8.0 0.8 (8.0/10.0)
// 10.0 1.0 (10.0/10.0)
normalize(positiveData, normalizedData_inf, 1.0, 0.0, NORM_INF);
// Norm to range [0.0;1.0]
// 2.0 0.0 (shift to left border)
// 8.0 0.75 (6.0/8.0)
// 10.0 1.0 (shift to right border)
normalize(positiveData, normalizedData_minmax, 1.0, 0.0, NORM_MINMAX);
void cv::normalize ( const SparseMat & src,
SparseMat & dst,
double alpha,
int normType
)
src 输入矩阵
dst 输出矩阵
alpha 归一化的最低边界.
normType 归一化方法
小结
1.本文介绍了Mat类的一些常用的用法,具体的操作,大家还能访问官方网站https://docs.opencv.org/master/d2/de8/group__core__array.html#gad12cefbcb5291cf958a85b4b67b6149f
2.对矩阵的操作是最基本的操作,希望该篇文章对大家有所帮助