cv::Mat 初始化
一、无数据拷贝的cv::Mat的定义和初始化
1、默认形式
cv::Mat m;
2、指定类型和大小(行列)的二维数组
cv::Mat m(int rows, int cols, int type);
3、有初始化值的指定类型和大小(行列)的二维数组
cv::Mat m(int rows, int cols, int type, const Scalar& s);
4、使用预先存在数据定义的指定类型和大小(行列)的二维数组
cv::Mat m(int rows, int cols, int type, void* data, size_t step = AUTO_STEP);
5、指定大小(size)和类型的二维数组
cv::Mat m(cv::Size sz, int type, const Scalar& s);
6、使用预先存在的数据定义的指定大小(size)和类型的二维数组
cv::Mat m(cv::Size sz, int type, void* data, size_t step = AUTO_STEP);
7、指定类型的多维数组
cv::Mat m(int ndims, const int* sizes, int type);
8、有初始化值的指定类型多维数组
cv::Mat m(int ndims, const int* sizes, int type, const Scalar& s);
9、使用预先存在的数据定义的指定类型的多维数组
cv::Mat m(int ndims, const int* sizes, int type, void* data, size_t step = AUTO_STEP);
二、从其他cv::Mat进行数据拷贝的定义和初始化
1、拷贝构造形式
cv::Mat m(const cv::Mat& mat);
2、指定行列范围的拷贝构造
cv::Mat m(const cv::Mat& mat, const cv::Range& rows, const cv::Range& cols);
3、指定ROI的拷贝构造
cv::Mat m(const cv::Mat& mat, const cv::Rect& roi);
4、使用多维数组中指定范围内的数据的拷贝构造
cv::Mat(const cv::Mat& mat, const cv::Range* ranges);
三、使用OpenCV中的模板进行定义和初始化
1、使用cv::Vec定义相同类型、大小为n的一维数组
cv::Mat m(const cv::Vec<T, n>& vec, bool = copyData = true);
2、使用cv::Matx定义相同类型、大小为mxn的二维数组
cv::Mat(const cv::Matx<T, m, n>& vec, bool copyData = true);
3、使用STL vector定义相同类型的一维数组
cv::Mat(const std::vector& vec, bool copyData = true);
四、直接使用静态函数创建cv::Mat
1、使用zeros()函数定义指定大小和类型的cv::Mat(全为0)
cv::Mat m = cv::Mat::zeros(int rows, int cols, int type);
2、使用ones()函数定义指定大小和类型的cv::Mat(全为0)
cv::Mat m = cv::Mat::ones(int rows, int cols, int type);
3、使用eye()函数定义指定大小和类型的cv::Mat(恒等矩阵)
cv::Mat m = cv::Mat::eye(int rows, int cols, int type);
完整代码
#include "opencv2/opencv.hpp"
#include "opencv2/imgproc/types_c.h"
void demo1() {
/*
1、...
*/
cv::Mat m0;
/*
2、指定类型和大小(行列)的二维数组
cv::Mat m1(int rows, int cols, int type);
*/
cv::Mat m1(1080, 1920, CV_8UC3);
/*
3、有初始化值的指定类型和大小(行列)的二维数组
cv::Mat m(int rows, int cols, int type, const Scalar& s);
*/
cv::Mat m2(1080, 1920, CV_8UC3, cv::Scalar(100, 1, 1));
/*
4、使用预先存在数据定义的指定类型和大小(行列)的二维数组
cv::Mat m(int rows, int cols, int type, void* data, size_t step = AUTO_STEP);
*/
char* data = new char[15];
cv::Mat m3(3, 5, CV_8UC1, data);
std::cout << m3 << std::endl;
cv::Mat m4(1, 5, CV_8UC3, data);
std::cout << m4 << std::endl;
/*
5、指定大小(size)和类型的二维数组
cv::Mat m(cv::Size sz, int type, const Scalar& s);
*/
cv::Mat m5(cv::Size(10, 10), CV_8UC3, cv::Scalar(1, 2, 3));
std::cout << m5 << std::endl;
/*
6、使用预先存在的数据定义的指定大小(size)和类型的二维数组
cv::Mat m(cv::Size sz, int type, void* data, size_t step = AUTO_STEP);
*/
cv::Mat m6(cv::Size(3, 5), CV_8UC1, data);
std::cout << m6 << std::endl;
/*
7、指定类型的多维数组
cv::Mat m(int ndims, const int* sizes, int type);
*/
int size[3] = { 3, 2, 2 };
cv::Mat m7(3, size, CV_8UC1);
/*
8、有初始化值的指定类型多维数组
cv::Mat m(int ndims, const int* sizes, int type, const Scalar& s);
*/
int matSize[] = { 5,8,10 };//每一维元素的个数:8:行,10:列
cv::Mat m8(3, matSize, CV_16UC3, cv::Scalar::all(0));
printf("\n///求step[i]的大小:每一维元素的大小(单位字节)//\n");
printf("step[0]:%d\n", m8.step[0]);//480:面的大小(第一维)
printf("step[1]:%d\n", m8.step[1]);//60:线的大小(第二维)
printf("step[2]:%d\n", m8.step[2]);//6:点的大小(第三维)
/*
9、使用预先存在的数据定义的指定类型的多维数组
cv::Mat m(int ndims, const int* sizes, int type, void* data, size_t step = AUTO_STEP);
*/
int matSize2[] = { 2,2,2 };//每一维元素的个数:8:行,10:列
char* data2 = new char[8];
cv::Mat m9(3, matSize2, CV_8UC1, data2);
printf("\n///求step[i]的大小:每一维元素的大小(单位字节)//\n");
printf("step[0]:%d\n", m9.step[0]);//480:面的大小(第一维)
printf("step[1]:%d\n", m9.step[1]);//60:线的大小(第二维)
printf("step[2]:%d\n", m9.step[2]);//6:点的大小(第三维)
}
void demo2() {
char* data = new char[15];
cv::Mat m0(3, 5, CV_8UC1, data);
std::cout << m0 << std::endl;
/*
1、拷贝构造形式
cv::Mat m(const cv::Mat& mat);
*/
cv::Mat m1(m0);
/*
2、指定行列范围的拷贝构造
cv::Mat m(const cv::Mat& mat, const cv::Range& rows, const cv::Range& cols);
*/
cv::Mat m2(m0, cv::Range(1,2), cv::Range(1,3));
/*
3、指定ROI的拷贝构造
cv::Mat m(const cv::Mat& mat, const cv::Rect& roi);
*/
cv::Mat m3(m0, cv::Rect(1,1, 2,2));
std::cout << m3.size() << std::endl;
/*
4、使用多维数组中指定范围内的数据的拷贝构造
cv::Mat(const cv::Mat& mat, const cv::Range* ranges);
*/
int matSize[] = { 5,8,10 };//每一维元素的个数:8:行,10:列
cv::Mat mm(3, matSize, CV_16UC3, cv::Scalar::all(0));
cv::Range* ranges = new cv::Range[3]{cv::Range(1,2), cv::Range(1,3), cv::Range(1,4)};
cv::Mat m4(mm, ranges);
printf("step[0]:%d\n", m4.step[0]);//480:面的大小(第一维)
printf("step[1]:%d\n", m4.step[1]);//60:线的大小(第二维)
printf("step[2]:%d\n", m4.step[2]);//6:点的大小(第三维)
}
//三、使用OpenCV中的模板进行定义和初始化
void demo3() {
/*
1、使用cv::Vec定义相同类型、大小为n的一维数组
cv::Mat m(const cv::Vec<T, n>& vec, bool = copyData = true);
*/
cv::Vec<float, 10> data1{ 1,2,3,4,5, 6,7,8,9,10 };
cv::Mat m1(data1, true);
std::cout << m1 << std::endl;
/*
2、使用cv::Matx定义相同类型、大小为mxn的二维数组
cv::Mat(const cv::Matx<T, m, n>& vec, bool copyData = true);
*/
cv::Matx<float, 2, 4> data2{ 1,2,3,4,5,6,7,7 };
cv::Mat m2(data2, true);
std::cout << m2 << std::endl;
/*
3、使用STL vector定义相同类型的一维数组
cv::Mat(const std::vector<T>& vec, bool copyData = true);
*/
std::vector<float> vec{1, 2, 3, 4, 5, 6};
cv::Mat m3(vec, true);
std::cout << m3 << std::endl;
}
//四、直接使用静态函数创建cv::Mat
void demo4() {
/*
1、使用zeros()函数定义指定大小和类型的cv::Mat(全为0)
cv::Mat m = cv::Mat::zeros(int rows, int cols, int type);
*/
cv::Mat m1 = cv::Mat::zeros(10, 10, CV_8UC1);
/*
2、使用ones()函数定义指定大小和类型的cv::Mat(全为0)
cv::Mat m = cv::Mat::ones(int rows, int cols, int type);
*/
cv::Mat m2 = cv::Mat::ones(10, 10, CV_8UC1);
/*
* 3、使用eye()函数定义指定大小和类型的cv::Mat(恒等矩阵)
cv::Mat m = cv::Mat::eye(int rows, int cols, int type);
*/
cv::Mat m3 = cv::Mat::eye(10, 10, CV_8UC1);
std::cout << m3 << std::endl;
}
int main()
{
// demo1();
// demo2();
// demo3();
demo4();
return 0;
}
cv::Mat 访问
单通道灰度图数据存放格式:
多通道的图像中,每列并列存放通道数量的子列,如RGB三通道彩色图:
opencv中,由于使用Mat.at访问数据时,必须正确填写相应的数据类型,因此必须弄清楚opencv中的数据类型与我们常用数据类型一一对应关系。
单通道访问 Mat:
Mat_---------CV_8U
Mat_-----------CV_8S
Nat_---------CV_16S
Mat_--------CV_16U
Mat_-----------CV_32S
Mat_----------CV_32F
Mat_--------CV_64F
下面主要记录三种常见的访问Mat的方式:1.at访问 2.ptr访问 3.data访问
Mat中不管是以at访问还是ptr访问,都是行优先 ,先Y轴后X轴(即先行后列)
//***方法1:************************************************************
t = (double)getTickCount();
Mat img1(1000, 1000, CV_32F);
for (int i=0; i<1000; i++)
{
for (int j=0; j<1000; j++)
{
img1.at<float>(i,j) = 3.2f;
}
}
t = (double)getTickCount() - t;
printf("in %gms\n", t*1000/getTickFrequency());
//***方法2************************************************************
t = (double)getTickCount();
Mat img2(1000, 1000, CV_32F);
for (int i=0; i<1000; i++)
{
for (int j=0; j<1000; j++)
{
img2.ptr<float>(i)[j] = 3.2f;
}
}
t = (double)getTickCount() - t;
printf("in %gms\n", t*1000/getTickFrequency());
//***方法3************************************************************
t = (double)getTickCount();
Mat img3(1000, 1000, CV_32F);
float* pData = (float*)img3.data;
for (int i=0; i<1000; i++)
{
for (int j=0; j<1000; j++)
{
*(pData) = 3.2f;
pData++;
}
}
t = (double)getTickCount() - t;
printf("in %gms\n", t*1000/getTickFrequency());
//***方法3************************************************************
t = (double)getTickCount();
Mat img4(1000, 1000, CV_32F);
for (int i=0; i<1000; i++)
{
for (int j=0; j<1000; j++)
{
((float*)img3.data)[i*1000+j] = 3.2f;
}
}
t = (double)getTickCount() - t;
printf("in %gms\n", t*1000/getTickFrequency());
//***方法3******加强版************************************************
t = (double)getTickCount();
Mat img5(1000, 1000, CV_32F);
float *pData1;
for (int i=0; i<1000; i++)
{
pData1=img5.ptr<float>(i);
for (int j=0; j<1000; j++)
{
pData1[j] = 3.2f;
}
}
t = (double)getTickCount() - t;
printf("in %gms\n", t*1000/getTickFrequency());
多通道Mat访问
用at进行多通道访问,对应的数据类型如下:
typedef Vec<uchar, 2> Vec2b; //无符号双通道 CV_8U:0~255
typedef Vec<uchar, 3> Vec3b; //无符号3通道
typedef Vec<uchar, 4> Vec4b;
typedef Vec<short, 2> Vec2s; //short型双通道 CV_16S:-32768~32767
typedef Vec<short, 3> Vec3s;
typedef Vec<short, 4> Vec4s;
typedef Vec<int, 2> Vec2i; //整型双通道 CV_32S:-2147483648~2147483647
typedef Vec<int, 3> Vec3i;
typedef Vec<int, 4> Vec4i;
typedef Vec<float, 2> Vec2f; //浮点型双通道 CV_32F:1.1810-38~3.401038
typedef Vec<float, 3> Vec3f;
typedef Vec<float, 4> Vec4f;
typedef Vec<float, 6> Vec6f;
typedef Vec<double, 2> Vec2d; //double型双通道 CV_64F:2.2310-308~1.7910308
typedef Vec<double, 3> Vec3d;
typedef Vec<double, 4> Vec4d;
typedef Vec<double, 6> Vec6d;
示例程序,创建及访问双通道Mat
#include <opencv2/core/core.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
int i, j;
Mat dimg(3, 5, CV_16SC2,Scalar(-5,5));//构造一个3*5的short型双通道矩阵
cout << "原矩阵" << endl << dimg << endl;
short int a=1,b=15;
for (i = 0; i < dimg.rows; i++)
{
for (j = 0; j < dimg.cols; j++)
{
dimg.at<Vec2s>(i, j)[0] = a;//at<type>其中type由矩阵的类型确定
dimg.at<Vec2s>(i, j)[1] = b;
}
}
cout << "改变后矩阵" << endl << dimg << endl;
system("pause");
}