7.Mat类构造与赋值

一、Mat类的构造

1、利用默认构造函数

  通过代码清单2-4,利用默认构造函数构造了一个Mat类,这种构造方式不需要输入任何的参数,在后续给变量赋值的时候会自动判断矩阵的类型与大小,实现灵活的存储,常用于存储读取的图像数据和某个函数运算输出结果。

代码清单2-4 默认构造函数使用方式

cv::Mat::Mat();

2、根据输入矩阵的尺寸和类型构造

代码清单2-5 利用矩阵尺寸和类型参数构造Mat类

cv::Mat::Mat( int  rows,

           int  cols,

           int  type

          )
  • rows:构造矩阵的行数

  • cols:矩阵的列数

  • type:矩阵中存储的数据类型。此处除了CV_8UC1、CV_64FC4等从1到4通道以外,还提供了更多通道的参数,通过CV_8UC(n)中的n来构建多通道矩阵,其中n最大可以取到512. 

这种构造方法我们前文也见过,通过输入矩阵的行、列以及存储数据类型实现构造。这种定义方式清晰、直观、易于阅读,常用在明确需要存储数据尺寸和数据类型的情况下,例如相机的内参矩阵、物体的旋转矩阵等。利用输入矩阵尺寸和数据类型构造Mat类的方法存在一种变形,通过将行和列组成一个Size()结构进行赋值,代码清单2-6中给出了这种构造方法的原型。

代码清单2-6 用Size()结构构造Mat类

cv::Mat::Mat(Size size(), int  type)
  • size:2D数组变量尺寸,通过Size(cols, rows)进行赋值。

  • type:与代码清单2-5中的参数一致

利用这种方式构造Mat类时要格外注意,在Size()结构里矩阵的行和列的顺序与代码清单2-5中的方法相反,使用Size()时,列在前、行在后。如果不注意同样会构造成功Mat类,但是当我们需要查看某个元素时,我们并不知道行与列颠倒,就会出现数组越界的错误。使用该种方法构造函数如下:

代码清单2-7 用Size()结构构造Mat示例

cv::Mat a(Size(480, 640), CV_8UC1); //构造一个行为640,列为480的单通道矩阵

cv::Mat b(Size(480, 640), CV_32FC3); //构造一个行为640,列为480的3通道矩

3、利用已有矩阵构造

代码清单2-8 利用已有矩阵构造Mat类

cv::Mat::Mat( const Mat & m);

m:已经构建完成的Mat类矩阵数据。

这种构造方式非常简单,可以构造出与已有的Mat类变量存储内容一样的变量。注意这种构造方式只是复制了Mat类的矩阵头,矩阵指针指向的是同一个地址,因此如果通过某一个Mat类变量修改了矩阵中的数据,另一个变量中的数据也会发生改变。如果想复制两个一模一样的Mat类而彼此之间不会受影响,可以使用m=a.clone()实现。如果需要构造的矩阵尺寸比已有矩阵小,并且存储的是已有矩阵的子内容,那么可以用代码清单2-9中的方法进行构建:

代码清单2-9 构造已有Mat类的子类

cv::Mat::Mat(const Mat & m,

               const Range & rowRange,

               const Range & colRange = Range::all()

               )
  • m:已经构建完成的Mat类矩阵数据。

  • rowRange:在已有矩阵中需要截取的行数范围,是一个Range变量,例如从第2行到第5行可以表示为Range(2,5)。

  • colRange:在已有矩阵中需要截取的列数范围,是一个Range变量,例如从第2列到第5列可以表示为Range(2,5),当不输入任何值时表示所有列都会被截取。

这种方式主要用于在原图中截图使用,不过需要注意的是,通过这种方式构造的Mat类与已有Mat类享有共同的数据,即如果两个Mat类中有一个数据发生更改,另一个也会随之更改。

二、Mat类的赋值

1、构造时赋值

代码清单2-11 在构造时赋值的方法

cv::Mat::Mat(int  rows,

               int  cols,

               int  type,

               const Scalar & s

               )
  • rows:矩阵的行数

  • cols:矩阵的列数

  • type:存储数据的类型

  • s:给矩阵中每个像素赋值的参数变量,例如Scalar(0, 0, 255)。

该种方式是在构造的同时进行赋值,将每个元素想要赋予的值放入Scalar结构中即可,这里需要注意的是,用此方法会将图像中的每个元素赋值相同的数值,例如Scalar(0, 0, 255)会将每个像素的三个通道值分别赋值0,0,255。我们可以使用如下的形式构造一个已赋值的Mat类

代码清单2-12 在构造时赋值示例

cv::Mat a(2, 2, CV_8UC3, cv::Scalar(0,0,255));//创建一个3通道矩阵,每个像素都是0,0,255

cv::Mat b(2, 2, CV_8UC2, cv::Scalar(0,255));//创建一个2通道矩阵,每个像素都是0,255

cv::Mat c(2, 2, CV_8UC1, cv::Scalar(255)); //创建一个单通道矩阵,每个像素都是255

Scalar结构中变量的个数一定要与定义中的通道数相对应,如果Scalar结构中变量个数大于通道数,则位置大于通道数之后的数值将不会被读取,例如执行a(2, 2, CV_8UC2, Scalar(0,0,255))后,每个像素值都将是(0,0),而255不会被读取。如果Scalar结构中变量数小于通道数,则会以0补充。

2、枚举赋值法

这种赋值方式是将矩阵中所有的元素都一一枚举出,并用数据流的形式赋值给Mat类。具体赋值形式如代码清单2-13所示。

代码清单2-13 利用枚举法赋值示例

cv::Mat a = (cv::Mat_<int>(3, 3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);

cv::Mat b = (cv::Mat_<double>(2, 3) << 1.0, 2.1, 3.2, 4.0, 5.1, 6.2);

 3、循环赋值

与通过枚举法赋值方法相类似,循环法赋值也是对矩阵中的每一位元素进行赋值,但是可以不在声明变量的时候进行赋值,而且可以对矩阵中的任意部分进行赋值。具体赋值形式如代码清单2-14所示。

代码清单2-14 利用枚举法赋值示例

cv::Mat c = cv::Mat_<int>(3, 3); //定义一个3*3的矩阵
for (int i = 0; i < c.rows; i++) //矩阵行数循环
{
  for (int j = 0; j < c.cols; j++) //矩阵列数循环
  {
    c.at<int>(i, j) = i+j;
  } }

4、类方法赋值

在Mat类里提供了可以快速赋值的方法,可以初始化指定的矩阵。例如生成单位矩阵、对角矩阵、所有元素都为0或者1的矩阵等。具体使用方法如代码清单2-15所示。

代码清单2-15 利用类方法赋值示例

cv::Mat a = cv::Mat::eye(3, 3, CV_8UC1);

cv::Mat b = (cv::Mat_<int>(1, 3) << 1, 2, 3);

cv::Mat c = cv::Mat::diag(b);

cv::Mat d = cv::Mat::ones(3, 3, CV_8UC1);

cv::Mat e = cv::Mat::zeros(4, 2, CV_8UC3);

上面代码中,每个函数作用及参数含义分别如下:

  • eye():构建一个单位矩阵,前两个参数为矩阵的行数和列数,第三个参数为矩阵存放的数据类型与通道数。如果行和列不相等,则在矩阵的 (1,1),(2,2),(3,3)等主对角位置处为1。

  • diag():构建对角矩阵,其参数必须是Mat类型的1维变量,用来存放对角元素的数值。

  • ones():构建一个全为1的矩阵,参数含义与eye()相同。

  • zeros():构建一个全为0的矩阵,参数含义与eye()相同。

5、利用数组进行赋值

这种方法与枚举法相类似,但是该方法可以根据需求改变Mat类矩阵的通道数,可以看作枚举法的拓展,在代码清单2-16中给出了这种方法的赋值形式。

代码清单2-16 利用数组赋值示例

float a[8] = { 5,6,7,8,1,2,3,4 };

cv::Mat b = cv::Mat(2, 2, CV_32FC2, a);

cv::Mat c = cv::Mat(2, 4, CV_32FC1, a);

这种赋值方式首先将需要存入到Mat类中的变量存入到一个数组中,之后通过设置Mat类矩阵的尺寸和通道数将数组变量拆分成矩阵,这种拆分方式可以自由定义矩阵的通道数,当矩阵中的元素数目大于数组中的数据时,将用-1.0737418e+08填充赋值给矩阵,如果矩阵中元素的数目小于数组中的数据时,将矩阵赋值完成后,数组中剩余数据将不再赋值。由数组赋值给矩阵的过程是首先将矩阵中第一个元素的所有通道依次赋值,之后再赋值下一个元素。

posted @ 2023-04-07 17:10  夏蝉沐雪  阅读(424)  评论(0编辑  收藏  举报