C++下OpenCV学习笔记
----Mat类数据结构
一.简介
Mat不仅是非常有用的图像容器类,也是一个通用的矩阵类。
- attention
(1)不必再手动为Mat类开辟空间
(2)不必在不需要时立即释放空间 - 组成
(1)矩阵头:包含矩阵尺寸、存储方法、存储地址等信息
(2)一个指向存储所有像素值的矩阵的指针。其中,根据所选的存储方法的不同,矩阵可以是不同的维数。 - 矩阵复制
(1)浅拷贝:=和()
引用计数机制,即让每个Mat对象拥有不同的信息头,但共享同一矩阵。通过让矩阵指针指向同一地址实现。使用拷贝构造函数时只复制信息头和矩阵指针,而不复制矩阵。
1>代码实现
#include<opencv2/opencv.hpp>
using namespace cv;
int main()
{
Mat a, c; //仅创建信息头
a = imread("C:\\Users\\441\\Desktop\\ZL\\夏目\\1.jpg"); //为矩阵开辟内存
Mat b(a); //使用拷贝构造函数
c = a; //使用赋值运算符
imshow("a", a);
imshow("b", b);
imshow("c", c);
waitKey(0);
return 0;
}
2>运行结果
![](https://i-blog.csdnimg.cn/blog_migrate/6eb90f74b1bb5ebdf3adbb17b61480ec.png)
3>attention
通过对任何一个对象作出改变也会影响其他对象。
(2)创建只引用部分数据的信息头(以创建感兴趣区域ROI为例)
a.使用矩阵界定
1>代码实现
#include<opencv2/opencv.hpp>
using namespace cv;
int main()
{
Mat a;
a = imread("C:\\Users\\441\\Desktop\\ZL\\夏目\\1.jpg");
Mat b(a, Rect(250, 125, 250, 150));
imshow("a", a);
imshow("b", b);
waitKey(0);
return 0;
}
2>运行结果
![](https://i-blog.csdnimg.cn/blog_migrate/2ea771c2e22e1b6d3fdaf39a07a14da9.png)
b.用行和列界定
1>代码实现
#include<opencv2/opencv.hpp>
using namespace cv;
int main()
{
Mat a;
a = imread("C:\\Users\\441\\Desktop\\ZL\\夏目\\1.jpg");
Mat b = a(Range(125, 275), Range::all());
imshow("a", a);
imshow("b", b);
waitKey(0);
return 0;
}
2>运行结果
![](https://i-blog.csdnimg.cn/blog_migrate/ec2bda24e03228669b17273e5d29a564.png)
(3)深拷贝
a.完全深拷贝:clone()函数
1>代码实现
#include<opencv2/opencv.hpp>
using namespace cv;
int main()
{
Mat a;
a = imread("C:\\Users\\441\\Desktop\\ZL\\夏目\\1.jpg");
Mat b = a.clone();
imshow("a", a);
imshow("b", b);
waitKey(0);
return 0;
}
2>运行结果
![](https://i-blog.csdnimg.cn/blog_migrate/d088a032406af01bac38fd6a8e3cc49e.png)
3>attention
在内存中申请新的空间,与原独立。
b.copyTo()函数
是否申请新的内存空间,取决于现矩阵头中的大小信息是否与原来的一致,若一致则只深拷贝并不申请新的空间,否则先申请空间后再进行拷贝。
1>代码实现
#include<opencv2/opencv.hpp>
using namespace cv;
int main()
{
Mat a, b;
a = imread("C:\\Users\\441\\Desktop\\ZL\\夏目\\1.jpg");
a.copyTo(b); //a,b大小不一致,此时等同于clone()
imshow("a", a);
imshow("b", b);
waitKey(0);
return 0;
}
#include<opencv2/opencv.hpp>
using namespace cv;
int main()
{
Mat a, b;
a = imread("C:\\Users\\441\\Desktop\\ZL\\夏目\\1.jpg");
b = a.col(250);
a.col(270).copyTo(b); //b与a.col(270)大小一致,将a的第270列赋值给第250列
imshow("a", a);
imshow("b", b);
waitKey(0);
return 0;
}
2>运行结果
![](https://i-blog.csdnimg.cn/blog_migrate/86152093464bcbf2c1a3aefce03222cf.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a320f5968262dda81573b9abe44365cb.png)
二.显式创建Mat类的七种方法
- 使用Mat()构造函数
Mat(int rows, int cols, int type, const Scalar& s);
第一个和第二个参数:表示行数和列数。
第三个参数:表示存储元素的数据类型以及每个矩阵点的通道数
CV_[The number of bits per item][Signed or Unsigned][Type prefix]C[The channel number]
即:CV_[位数][带符号与否][类型前缀]C[通道数]
第四个参数:表示使用指定的定制化值来初始化矩阵
1>代码实现
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main()
{
Mat A(2, 2, CV_8UC3, Scalar(0, 0, 255));
cout << "A = " << endl << A << endl;
return 0;
}
Scalar函数用法详见:Scalar函数用法
2>运行结果
- 在C/C++中通过构造函数进行初始化
Mat(int ndims, const int* sizes, int type, const Scalar& s);
第一个参数:表示维度。
第二个参数:表示每个维度的尺寸。
第三和第四个参数:同1.
1>代码实现
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main()
{
int size[3] = {3,3,3};
Mat A(2, size, CV_8UC3, Scalar(0, 0, 255));
cout << "A = " << endl << A << endl;
return 0;
}
2>运行结果
3>attention
第一个参数需要小于等于2。如果大于2,会报错:
- 为已存在的IplImage(IPLIMAGE)指针创建信息头
1>代码实现
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main()
{
IplImage* img = cvLoadImage("C:\\Users\\441\\Desktop\\ZL\\夏目\\1.jpg", 1);
Mat A = cvarrToMat(img); //转换IplImage*->Mat
cout << "A = " << endl << A << endl;
return 0;
}
2>运行结果
只是部分=_=
- 利用create()函数
void Mat::create(int _rows, int _cols, int _type);
1>代码实现
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main()
{
Mat A;
A.create(3, 3, CV_8UC2);
cout << "A = " << endl << A << endl;
return 0;
}
2>运行结果
3>attention
此创建方法不能为矩阵设初值,只是在改变尺寸时重新为矩阵数据开辟内存而已。
- 采用Matlab式的初始化方法
zeros(),ones(),eye()
1>代码实现
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main()
{
Mat E = Mat::eye(4, 4, CV_64F);
cout << "E = " << endl << E << endl;
Mat O = Mat::ones(2, 2, CV_32F);
cout << "O = " << endl << O << endl;
Mat Z = Mat::zeros(3, 3, CV_32F);
cout << "Z = " << endl << Z << endl;
return 0;
}
2>运行结果
- 对小矩阵使用逗号分隔符式初始化函数
1>代码实现
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main()
{
Mat A = (Mat_<double>(3, 3) << 0, -1, 0, -1, 7, -1, 0, -1, 0);
cout << "A = " << endl << A << endl;
return 0;
}
2>运行结果
- 为已存在的对象创建新信息头
clone(),copyTo()
1>代码实现
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main()
{
Mat A = (Mat_<double>(3, 3) << 0, -1, 0, -1, 7, -1, 0, -1, 0);
Mat RowClone = A.row(1).clone();
cout << "RowClone = " << endl << RowClone << endl;
return 0;
}
2>运行结果
三.构造函数Mat::Mat
Mat共有24个构造函数,包括一个默认构造函数和23个重载的构造函数。函数列表如下:
//! default constructor
Mat();
//! constructs 2D matrix of the specified size and type
// (_type is CV_8UC1, CV_64FC3, CV_32SC(12) etc.)
Mat(int rows, int cols, int type);
Mat(Size size, int type);
//! constucts 2D matrix and fills it with the specified value _s.
Mat(int rows, int cols, int type, const Scalar& s);
Mat(Size size, int type, const Scalar& s);
//! constructs n-dimensional matrix
Mat(int ndims, const int* sizes, int type);
Mat(int ndims, const int* sizes, int type, const Scalar& s);
//! copy constructor
Mat(const Mat& m);
//! constructor for matrix headers pointing to user-allocated data
Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP);
Mat(Size size, int type, void* data, size_t step=AUTO_STEP);
Mat(int ndims, const int* sizes, int type, void* data, const size_t* steps=0);
//! creates a matrix header for a part of the bigger matrix
Mat(const Mat& m, const Range& rowRange, const Range& colRange=Range::all());
Mat(const Mat& m, const Rect& roi);
Mat(const Mat& m, const Range* ranges);
//! converts old-style CvMat to the new matrix; the data is not copied by default
Mat(const CvMat* m, bool copyData=false);
//! converts old-style CvMatND to the new matrix; the data is not copied by default
Mat(const CvMatND* m, bool copyData=false);
//! converts old-style IplImage to the new matrix; the data is not copied by default
Mat(const IplImage* img, bool copyData=false);
//! builds matrix from std::vector with or without copying the data
template<typename _Tp> explicit Mat(const vector<_Tp>& vec, bool copyData=false);
//! builds matrix from cv::Vec; the data is copied by default
template<typename _Tp, int n> explicit Mat(const Vec<_Tp, n>& vec, bool copyData=true);
//! builds matrix from cv::Matx; the data is copied by default
template<typename _Tp, int m, int n> explicit Mat(const Matx<_Tp, m, n>& mtx, bool copyData=true);
//! builds matrix from a 2D point
template<typename _Tp> explicit Mat(const Point_<_Tp>& pt, bool copyData=true);
//! builds matrix from a 3D point
template<typename _Tp> explicit Mat(const Point3_<_Tp>& pt, bool copyData=true);
//! builds matrix from comma initializer
template<typename _Tp> explicit Mat(const MatCommaInitializer_<_Tp>& commaInitializer);
//! download data from GpuMat
explicit Mat(const gpu::GpuMat& m);
//! destructor - calls release()
~Mat();