ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

OpenCV计算机视觉开发入门与实践<十>:OpenCV矩阵类Mat用法

OpenCV计算机视觉开发入门与实践<十>:OpenCV矩阵类Mat用法 1.直接赋值法Mat 矩阵比较小时可以使用直接赋值法。直接赋值法就是利用 Mat_。Mat_也是一个类该类是对 Mat 类的一个包装其定义如下templatetypename_TpclassMat_:publicMat{public://只定义了几个方法//没有定义新的属性};如果要让每个像素取不同的值可以直接用 Mat_赋值代码如下Mat r8(Mat_double(3,3)1,2,3,4,5,6,7,8,9);coutr8 total matrix:\nr1endl;输出结果如下[1,2,3;4,5,6;7,8,9]2.数组法这个方法就是使用数组或指针传入 Mat 构造函数。这个构造函数是Mat(introws,intcols,inttype,void*data,size_t stepAUTO_STEP)创建行数为 rows、列数为 cols像素的列数对于多通道一列像素可能对应多列矩阵元素、类型为 type 的图像并且用数组 data 初始化元素值。Mat(Size size,inttype,void*data,size_t stepAUTO_STEP)创建大小为 size、类型为 type 的图像并且用数组 data 初始化元素值。data 就是要传入数据的指针比如inta[2][3]{1,2,3,4,5,6};//定义 2 行 3 列二维数组Matm1(2,3,CV_32S,a);//float 对应的是 CV_32Fdouble 对应的是 CV_64F若不带通道数则默认通道数是 1coutm1endl;输出结果如下[1,2,3;4,5,6]数组适合操作数据量大的情况比如可以通过 for 循环来构造二维数组然后给 Mat 赋值。3.create 函数法成员函数 create 可以分配新的矩阵数据即重新创建矩阵元素数据函数声明如下voidcreate(introws,intcols,inttype);其中 rows 表示要创建的矩阵行数cols 表示要创建的矩阵列数type 表示图像矩阵元素的类型比如 CV_8UC3。以下代码实现 4×4 的二维单通道矩阵矩阵中的数据为乱值Mat M3;M3.create(4,4,CV_8UC1);std::coutM3 std::endlM3std::endl;输出结果如下[205,205,205,205;205,205,205,205;205,205,205,205;205,205,205,205]4. 定义特殊矩阵为了方便起见Mat 类提供了几个静态成员函数用于快速定义几种特殊矩阵比如全 0 矩阵、全 1 矩阵和对角线为 1 的对角矩阵等。下面介绍这几个静态成员函数。1定义全 0 矩阵函数声明如下staticMatExprzeros(introws,intcols,inttype);staticMatExprzeros(Size size,inttype);staticMatExprzeros(intndims,constint*sz,inttype);比如以下代码定义了 h 行 w 列的全 0 矩阵cv::Mat mzcv::Mat::zeros(cv::Size(w,h),CV_8UC1);Mat tmpdataMat::zeros(h,w,CV_8UC1);2定义第一通道全为 1 的矩阵函数声明如下staticMatExprones(introws,intcols,inttype);staticMatExprones(Size size,inttype);staticMatExprones(intndims,constint*sz,inttype);比如以下代码定义了 h 行 w 列的全 1 矩阵cv::Mat mocv::Mat::ones(cv::Size(w,h),CV_8UC1);Mat tmpdataMat::ones(h,w,CV_8UC1);值得注意的是如果是单通道ones 能把全矩阵置为 1。如果是多通道矩阵ones 只会把每个像素的第一个通道元素置为 1其余两个通道则置为 0比如Mat mymatcv::Mat::ones(cv::Size(3,2),CV_8UC3);//定义 2 行 3 列 3 通道矩阵实际矩阵共有 9 列coutmymatendl;输出结果是[1,0,0,1,0,0,1,0,0;1,0,0,1,0,0,1,0,0]另外也可以用构造函数来达到 ones 效果比如以下两句效果一样Mat mMat::ones(2,2,CV_8UC3);Mat mMat(2,2,CV_8UC3,1);//利用构造函数3对角线为 1 的矩阵函数声明如下staticMatExpreye(introws,intcols,inttype);staticMatExpreye(Size size,inttype);比如以下代码定义了 h 行 w 列的对角线为 1 的对角矩阵cv::Mat mecv::Mat::eye(cv::Size(w,h),CV_32FC1);Mat tmpdataMat::eye(h,w,CV_32FC1);MatExpr 是矩阵表达式类用于对矩阵进行某种计算。5. 得到矩阵的行数、列数和维数Mat 类提供了如下公有成员变量来获得行数、列数和维数1rows矩阵的行数。2cols矩阵的列数。3dims矩阵的维度例如二维矩阵 dims2如果是三维矩阵则 dims3。【例 】打印矩阵的像素行数、像素列数和维数#includeiostream#includeopencv2/imgcodecs.hppusingnamespacecv;//所有 OpenCV 类都在命名空间 cv 下usingnamespacestd;#pragmacomment(lib,opencv_world4140d.lib)//引用引入库intmain(){Matr3(Size(3,3),CV_8UC3);cout矩阵像素行数r3.rows,矩阵像素列数r3.colsendl;cout矩阵维数r3.dimsendl;}6.矩阵的数据指针及其打印矩阵类 Mat 的数据结构分为两部分矩阵头和指向矩阵数据部分的指针。Mat 类提供了公有成员变量属性data 指针用于指向 Mat 数据矩阵的数据部分的首地址其定义如下uchar*cv::Mat::data;当我们只定义一个 Mat 对象时此时 data 指针指向 NULL打印的结果是一对方括号。当我们定义了 Mat 对象的同时又指定了大小则 data 指针指向一段有效内存但内存中的数据是乱的比如 cdcdcdcdcd如果单步调试可以看到此时打印的结果就是矩阵每个元素都是 205。当我们定义 Mat 对象的同时指定了大小并赋了值则 data 指向的内存中的数据就是所赋值的数据此时就可以打印出所赋值的数据了。我们可以用 cout 来打印一个矩阵的数据。#includeiostream#includeopencv2/core.hpp usingnamespacecv;//所有 OpenCV 类都在命名空间 cv 下usingnamespacestd;#pragmacomment(lib,opencv_world4140d.lib)//引用引入库intmain(){inta[3][3]{1,2,3,4,5,6,7,8,9};Matr1(3,3,CV_32S,a);//Mat r1 (Mat_double(3, 3) 1, 2, 3, 4, 5, 6, 7, 8, 9);coutr1 total matrix:\nr1endl;Mat r2;//目前 r2 的 data 是 NULLif(r2.dataNULL)coutr2.dataNULL\n;coutr2r2endl;coutr3\n;Matr3(Size(3,3),CV_8UC3);coutr3;return0;}7. 创建新的矩阵头矩阵类 Mat 的数据结构分为两部分矩阵头和指向矩阵数据部分数据区的指针。矩阵头的内容主要包含矩阵尺寸、存储方法、存储地址和引用次数等。矩阵头的大小是一个常数不会随着图像的大小而改变但是保存图像像素数据的矩阵会随着图像的大小而改变通常数据量会很大比矩阵头大几个数量级。这样在图像复制和传递过程中主要的开销是由存放图像像素的矩阵而引起的。因此OpenCV 使用了引用次数当进行图像复制和传递时不再复制整个 Mat 数据而只是复制矩阵头和指向像素矩阵的指针。Mat 类提供了下列成员函数来创建新的矩阵头并共享原矩阵的数据。注意矩阵头的内存空间是新开辟的。1Mat row(int y);该函数根据指定行索引基于 0 开始最大值是原矩阵行数-1创建一个数的矩阵头并返回Mat 矩阵对象该矩阵对象的数据部分共享原来矩阵的数据部分。其中 y 是指定的行数返回的是Mat 对象。2Mat col (int x);创建一个指定了列索引基于 0 开始最大值是原矩阵列数-1的矩阵头并返回 Mat 矩阵对象该矩阵对象的数据部分共享原来矩阵的数据部分。其中 x 是指定的列数返回值是包含新矩阵头的 Mat 对象。3Mat rowRange(int startrow, int endrow);该函数创建一个指定行区间的新的矩阵头并返回 Mat 矩阵对象该矩阵对象的数据部分共享原来矩阵的数据部分。其中 startrow 是开头行从 0 开始的行间距起始索引endrow 是结尾行。函数取的实际行数 endrowstartrow只取到范围的右边界endrow 包括在内而不取左边界不包括 startrow 行。4Mat colRange(int startcol,int endcol);创建一个指定列区间的新的矩阵头可取指定列区间元素。其中 startcol 是开头列endcol 是结尾列。函数取的实际列数 endcolstartcol只取到范围的右边界endcol 包括在内而不取左边界不包括 startcol 行。【例 】创建矩阵头#includeiostream#includeopencv2/core.hpp #includeopencv2/imgcodecs.hppusingnamespacecv;//所有 OpenCV 类都在命名空间 cv 下usingnamespacestd;#pragmacomment(lib,opencv_world4140d.lib)//引用引入库intmain(){inti,j;//Mat r1 (Mat_double(3, 3) 1, 2, 3, 4, 5, 6, 7, 8, 9);inta[3][3]{1,2,3,4,5,6,7,8,9};Matr1(3,3,CV_32S,a);coutr1 total matrix:\nr1endl;Mat r2;for(i0;ir1.rows;i){r2r1.row(i);//用 r1 的第 i 行作为新矩阵头并返回新矩阵头的矩阵对象if(r1.datar2.data)//由于共享数据因此第 0 行的指针应该是相同的coutwhen ii,r1.datar2.data\n;coutr1.row(i):\nr2endl;}Mat r3;for(j0;jr1.cols;j){r3r1.col(j);//用 r1 的第 j 列作为新矩阵头并返回新矩阵头的矩阵对象if(r1.datar3.data)//由于共享数据因此第 0 列的指针应该是相同的coutwhen jj,r1.datar3.data\n;coutr1.col(j):\nr3endl;}Mat r4r1.rowRange(1,2);//创建新矩阵头并共享 r1 的第 1 列数据基于 0coutr1.rowRange(1, 2):\nr4endl;//创建新矩阵头并共享 r1 的第 1 列和第 2 列的数据coutr1.colRange(1, 3):\nr1.colRange(1,3)endl;}8.得到矩阵通道数成员函数 channels 返回矩阵通道的数目函数声明如下intchannels();函数比较简单直接返回矩阵的通道数比如以下代码Mat r1(Mat_double(3,3)1,2,3,4,5,6,7,8,9);Matr2(576,5*768,CV_8UC3);Mat r3;coutr1 channel number:r1.channels()endl;coutr2 channel number:r2.channels()endl;coutr3 channel number:r3.channels()endl;运行结果是r1 channel number:1r2 channel number:3r3 channel number:1r1 定义了大小为 3×3并且赋了 9 个元素一个像素占某行的一列说明是单通道如果是多通道则一个像素要占多列。r2 因为指定了是 3 通道CV_8UC3所以输出的是 3。r3 默认是单通道。
返回列表