如果使用Mat类,我们得到的好处是:
不需要手动申请一块内存;
在不需要时不用再手动释放内存;
可以通过类的封装,方便的获取到数据的相关信息
Mat类分为两个部分:矩阵头和矩阵数据。如果我们在操作一副图像的数据量时,矩阵数据的大小很大(一般约有1M的数据量),那么拷贝和赋值函数所作的操作如果的深拷贝的话,效率会大大的降低。所以,Opencv的做法是只复制其矩阵头信息,而矩阵数据采用引用的方式,即多个Mat对象共享同一个矩阵数据,这里使用的原理类似c++11中的共享指针
cv::Mat A = cv::imread("D:/bb/tu/ma.jpg"); cv::Mat B(A); cv::Mat C = A; printf("A.data = %p B.data = %p C.data = %p ", A.data, B.data, C.data);
输出结果如下:
如上我们可以看到,三个Mat类对象的矩阵数据的地址是一样的。那么释放内存的原则是怎样的呢。这个也是内部使用了引用计数的方法,类似共享指针,当引用计数变为0的时候才会真正的释放内存
Mat对象的创建
cv::Mat M1(5, 4, CV_8UC4, cv::Scalar(0, 0, 0, 255));//创建2维矩阵对象 /* 参数1和参数2:行数和列数 参数3:图像属性8UC4: 第一位8:比特数 代表8bite,16bites,32bites,64bites,每一个像素点在内存空间所占的空间大小 第二位U:S--代表---signed int---有符号整形 U--代表--unsigned int--无符号整形 F--代表--float-------单精度浮点型 最后两位c4:通道数:1--灰度图片---是--单通道图像 2--RGB彩色图像---------是--3通道图像 3--带Alph通道的RGB图像--是--4通道图像 参数4:每个像素点的颜色 */ std::cout << M1 << std::endl; //显示数据 int r=M1.rows; //返回行数 int c=M1.cols; //返回列数 qDebug()<<r<<c;
cv::Mat M1(5, 4, CV_8UC3); std::cerr<<M1<<std::endl; M1=cv::Scalar(10, 20, 30);//赋值 std::cerr<<M1<<std::endl;
int sz[2]={5,4}; cv::Mat M(2, sz, CV_8UC4, cv::Scalar(0, 0, 0, 255));//创建n维矩阵对象 /* 参数1:矩阵的维数 参数2:是个数组,表示行数和列数 */ std::cout << M << std::endl;
cv::Mat M; M.create(5, 4, CV_8UC4);//创建2维矩阵对象 //注意:这种方法好像不能有第四个颜色参数,每个点的颜色随机 std::cout << M << std::endl;
cv::Mat M = cv::Mat::eye(4, 4, CV_32F); //创建单位矩阵 std::cout << M << std::endl;
cv::Mat M = cv::Mat::ones(4, 4, CV_32F); //创建全是1的矩阵 std::cout << M << std::endl;
cv::Mat M = cv::Mat::zeros(4, 4, CV_32F); //创建全是0的矩阵 std::cout << M << std::endl;
cv::Mat M = (cv::Mat_<double>(3, 3) << 0, -10, 0, -11, 0, 0, 0, 88, 1); //创建自定义数据的矩阵 std::cout << M << std::endl;
cv::Mat M = (cv::Mat_<double>(3, 3) << 0, -10, 0, -11, 0, 0, 0, 88, 1); cv::Mat M5 = M.row(1).clone(); //M5中的数据就是M的第二行数据 //通过克隆函数clone获取我们需要的某一行或列的数据,这里构建出来的矩阵是深拷贝出来的Mat类对象 std::cout << M5 << std::endl;
Mat基本属性
cv::Mat A = cv::imread("D:/bb/tu/ma.jpg",1); int i = A.type();//返回图像属性 //具体对应值见下表 std::cout<< i; cv::namedWindow("显示"); imshow("显示",A);
cv::Mat A = cv::imread("D:/bb/tu/ma.jpg",1); int i = A.channels(); //返回通道数 int w=A.cols; //返回列数,即宽 int h=A.rows; //返回行数,即高 cv::namedWindow("显示"); imshow("显示",A); qDebug()<<i<<w<<h;
cv::Mat sm(6, 5, CV_8UC3); int d=sm.depth();//获取矩阵元素深度,其返回的其类型和Mat一致 /* 返回值对应的元素深度 CV_8U = 0 - 8-bit unsigned integers ( 0..255 ) CV_8S = 1 - 8-bit signed integers ( -128..127 ) CV_16U = 2 - 16-bit unsigned integers ( 0..65535 ) CV_16S = 3 - 16-bit signed integers ( -32768..32767 ) CV_32S = 4 - 32-bit signed integers ( -2147483648..2147483647 ) CV_32F = 5 - 32-bit floating-point numbers ( -FLT_MAX..FLT_MAX, INF, NAN ) CV_64F = 6 - 64-bit floating-point numbers ( -DBL_MAX..DBL_MAX, INF, NAN ) CV_USRTYPE1=7 */ int c=sm.channels(); //返回矩阵通道数目 int dim=sm.dims; //返回矩阵维度 int e=sm.elemSize();//返回每个元素占用的字节数大小(带通道) int e1=sm.elemSize1();//返回单个元素值占用的字节数大小 int w=sm.step[0]; //第一级在矩阵内存中占据的字节的数量 //step[i]就是第i+1级在矩阵内存中占据的字节的数量 //资料看:https://blog.csdn.net/lanmeng_smile/article/details/47864615 int h=sm.step1(1); //一个元素所占的字节数 std::cerr<<d<<std::endl;