Mat 类是OpenCV中的一个基本数据类型,它是一个n维密集数组类

Mat 类表示一个 n 维密集数值单通道或多通道数组。它可用于存储实数或复值向量和矩阵、灰度或彩色图像、体素体积、向量场、点云、张量、直方图(不过,非常高维的直方图可能更好地存储在 SparseMat 中)。数组M的数据布局由数组M.step[]定义,使得元素 ( i 0 , ⋯ , i M . d i m s − 1 ) (i_0,\cdots,i_{M.dims−1}) (i0​,⋯,iM.dims−1​)的地址,其中 0 ≤ i k < M . s i z e [ k ] 0≤i_k<M.size[k] 0≤ik​<M.size[k], 计算为:
a d d r ( M i 0 , ⋯ , i M . d i m s − 1 ) = M . d a t a + M . s t e p [ 0 ] ∗ i 0 + M . s t e p [ 1 ] ∗ i 1 + ⋯ + M . s t e p [ M . d i m s − 1 ] ∗ i M . d i m s − 1 addr(M_{i0},\cdots,i_{M.dims-1})=M.data+M.step[0]*i_0+M.step[1]*i_1+\cdots+M.step[M.dims-1]*i_{M.dims-1} addr(Mi0​,⋯,iM.dims−1​)=M.data+M.step[0]∗i0​+M.step[1]∗i1​+⋯+M.step[M.dims−1]∗iM.dims−1​

在二维数组的情况下,上述公式简化为:
a d d r ( M i , j ) = M . d a t a + M . s t e p [ 0 ] ∗ i + M . s t e p [ 1 ] ∗ j addr(M_{i,j})=M.data+M.step[0]*i+M.step[1]*j addr(Mi,j​)=M.data+M.step[0]∗i+M.step[1]∗j

请注意,M.step[i] >= M.step[i+1] (实际上,M.step[i] >= M.step[i+1]*M.size[i+1] )。 这意味着 2 维矩阵是逐行存储的,3 维矩阵是逐平面存储的,依此类推。M.step[M.dims-1] 是最小的并且总是等于元素大小 M.elemSize()

因此,Mat 中的数据布局与 OpenCV 1.x 中的 CvMat、IplImage 和 CvMatND 类型完全兼容。它还兼容标准工具包和 SDK 中的大多数密集数组类型,例如 Numpy (ndarray)Win32(独立设备位图),即任何使用步长(或步幅)来计算像素位置的数组。由于这种兼容性,可以为用户分配的数据创建一个 Mat 标头并使用 OpenCV 函数就地处理它。

有许多不同的方法可以创建一个 Mat 对象。下面列出了最流行的选择:

  • 使用 create(nrows, ncols, type) 方法或类似的 Mat(nrows, ncols, type[, fillValue]) 构造函数。分配了指定大小和类型的新数组。type 与 cvCreateMat 方法中的含义相同。例如,CV_8UC1 表示 8 位单通道数组,CV_32FC2 表示 2 通道(复数)浮点数组,以此类推。
// make a 7x7 complex matrix filled with 1+3j.
Mat M(7,7,CV_32FC2,Scalar(1,3));
// and now turn M to a 100x60 15-channel 8-bit matrix.
// The old content will be deallocated
M.create(100,60,CV_8UC(15));

测试代码

#include <opencv2/highgui.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>int main()
{cv::Mat M(3, 3, CV_32FC2, cv::Scalar(1, 3));// M.create(5, 5, CV_8UC(3));std::cout << "==默认风格==\n" << cv::format(M, cv::Formatter::FMT_DEFAULT) << std::endl;std::cout << "==Python风格==\n" << cv::format(M, cv::Formatter::FMT_PYTHON) << std::endl;std::cout << "==Numpy风格==\n" << cv::format(M, cv::Formatter::FMT_NUMPY) << std::endl;std::cout << "==C风格==\n" << cv::format(M, cv::Formatter::FMT_C) << std::endl;return 0;
}

输出如下

==默认风格==
[1, 3, 1, 3, 1, 3;1, 3, 1, 3, 1, 3;1, 3, 1, 3, 1, 3]
==Python风格==
[[[1, 3], [1, 3], [1, 3]],[[1, 3], [1, 3], [1, 3]],[[1, 3], [1, 3], [1, 3]]]
==Numpy风格==
array([[[1, 3], [1, 3], [1, 3]],[[1, 3], [1, 3], [1, 3]],[[1, 3], [1, 3], [1, 3]]], dtype='float32')
==C风格==
{1, 3, 1, 3, 1, 3,1, 3, 1, 3, 1, 3,1, 3, 1, 3, 1, 3}
==默认风格==
[  0,   0, 128,  63,   0,   0,  64,  64,   0,   0, 128,  63,   0,   0,  64;64,   0,   0, 128,  63,   0,   0,  64,  64,   0,   0, 128,  63,   0,   0;64,  64,   0,   0, 128,  63,   0,   0,  64,  64,   0,   0, 128,  63,   0;0,  64,  64,   0,   0, 128,  63,   0,   0,  64,  64,   0,   0, 128,  63;0,   0,  64,  64,   0,   0, 128,  63,   0,   0,  64,  64, 160,  63,  25]
==Python风格==
[[[  0,   0, 128], [ 63,   0,   0], [ 64,  64,   0], [  0, 128,  63], [  0,   0,  64]],[[ 64,   0,   0], [128,  63,   0], [  0,  64,  64], [  0,   0, 128], [ 63,   0,   0]],[[ 64,  64,   0], [  0, 128,  63], [  0,   0,  64], [ 64,   0,   0], [128,  63,   0]],[[  0,  64,  64], [  0,   0, 128], [ 63,   0,   0], [ 64,  64,   0], [  0, 128,  63]],[[  0,   0,  64], [ 64,   0,   0], [128,  63,   0], [  0,  64,  64], [160,  63,  25]]]
==Numpy风格==
array([[[  0,   0, 128], [ 63,   0,   0], [ 64,  64,   0], [  0, 128,  63], [  0,   0,  64]],[[ 64,   0,   0], [128,  63,   0], [  0,  64,  64], [  0,   0, 128], [ 63,   0,   0]],[[ 64,  64,   0], [  0, 128,  63], [  0,   0,  64], [ 64,   0,   0], [128,  63,   0]],[[  0,  64,  64], [  0,   0, 128], [ 63,   0,   0], [ 64,  64,   0], [  0, 128,  63]],[[  0,   0,  64], [ 64,   0,   0], [128,  63,   0], [  0,  64,  64], [160,  63,  25]]], dtype='uint8')
==C风格==
{  0,   0, 128,  63,   0,   0,  64,  64,   0,   0, 128,  63,   0,   0,  64,64,   0,   0, 128,  63,   0,   0,  64,  64,   0,   0, 128,  63,   0,   0,64,  64,   0,   0, 128,  63,   0,   0,  64,  64,   0,   0, 128,  63,   0,0,  64,  64,   0,   0, 128,  63,   0,   0,  64,  64,   0,   0, 128,  63,0,   0,  64,  64,   0,   0, 128,  63,   0,   0,  64,  64, 160,  63,  25}

由两者输出结果得出,create() 在当前数组的形状或类型与指定的不同时分配一个新数组。

  • 创建一个多维数组
// create a 100x100x100 8-bit array
int sz[] = {100, 100, 100};
Mat bigCube(3, sz, CV_8U, Scalar::all(0));

它将维度数 =1 传递给 Mat 构造函数,但创建的数组将是二维的,列数设置为 1。因此,Mat::dims 始终 >= 2(当数组为空时也可以为 0)。

  • 在右侧可以有数组或表达式的地方使用复制构造函数或赋值运算符(见下文)。如介绍中所述,数组赋值是一个 O(1) 操作,因为它只复制标头并增加引用计数器。Mat::clone() 方法可用于在需要时获取数组的完整(深层)副本。
  • 为另一个数组的一部分构造一个标头。它可以是单行、单列、多行、多列、数组中的矩形区域(在代数中称为小区域)或对角线。此类操作也是 O(1),因为新标头引用相同的数据。实际上可以使用此功能修改数组的一部分,例如:
// add the 5-th row, multiplied by 3 to the 3rd row
M.row(3) = M.row(3) + M.row(5)*3;
// now copy the 7-th column to the 1-st column
// M.col(1) = M.col(7); // this will not work
Mat M1 = M.col(1);
M.col(7).copyTo(M1);
// create a new 320x240 image
Mat img(Size(320,240),CV_8UC3);
// select a ROI
Mat roi(img, Rect(10,10,100,100));
// fill the ROI with (0,255,0) (which is green in RGB space);
// the original 320x240 image will be modified
roi = Scalar(0,255,0);

由于额外的 datastartdataend 成员,可以使用 locateROI() 计算主容器数组中的相对子数组位置

Mat A = Mat::eye(10, 10, CV_32S);
// extracts A columns, 1 (inclusive) to 3 (exclusive).
Mat B = A(Range::all(), Range(1, 3));
// extracts B rows, 5 (inclusive) to 9 (exclusive).
// that is, C \~ A(Range(5, 9), Range(1, 3))
Mat C = B(Range(5, 9), Range::all());
Size size; Point ofs;
C.locateROI(size, ofs);
// size will be (width=10,height=10) and the ofs will be (x=1, y=5)

与整个矩阵一样,如果您需要深度复制,请使用提取的子矩阵的 clone() 方法。

测试代码

#include <opencv2/highgui.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>int main()
{cv::Mat M(6, 6, CV_8UC3, cv::Scalar(23, 24, 25));std::cout << "==默认风格==\n" << cv::format(M, cv::Formatter::FMT_DEFAULT) << std::endl;std::cout << "==Python风格==\n" << cv::format(M, cv::Formatter::FMT_PYTHON) << std::endl;std::cout << "==Numpy风格==\n" << cv::format(M, cv::Formatter::FMT_NUMPY) << std::endl;std::cout << "==C风格==\n" << cv::format(M, cv::Formatter::FMT_C) << std::endl;std::cout << std::endl << std::endl << std::endl;M.row(3) = M.row(3) + M.row(5) * 3;cv::Mat M1;M.col(5).copyTo(M1);std::cout << "==默认风格==\n" << cv::format(M, cv::Formatter::FMT_DEFAULT) << std::endl;std::cout << "==Python风格==\n" << cv::format(M, cv::Formatter::FMT_PYTHON) << std::endl;std::cout << "==Numpy风格==\n" << cv::format(M, cv::Formatter::FMT_NUMPY) << std::endl;std::cout << "==C风格==\n" << cv::format(M, cv::Formatter::FMT_C) << std::endl;std::cout << "==Python风格==\n" << cv::format(M1, cv::Formatter::FMT_PYTHON) << std::endl;std::cout << std::endl << std::endl;cv::Mat img(cv::Size(320, 240), CV_8UC3);cv::Mat roi(img, cv::Rect(10, 10, 100, 100));roi = cv::Scalar(255, 0, 0);cv::imshow("image", img);cv::waitKey(0);cv::Mat A = cv::Mat::eye(10, 10, CV_32S);cv::Mat B = A(cv::Range::all(), cv::Range(1, 3));cv::Mat C = B(cv::Range(5, 9), cv::Range::all());cv::Size size; cv::Point ofs;C.locateROI(size, ofs);std::cout << cv::format(A, cv::Formatter::FMT_PYTHON) << std::endl;std::cout << cv::format(B, cv::Formatter::FMT_PYTHON) << std::endl;std::cout << cv::format(C, cv::Formatter::FMT_PYTHON) << std::endl;std::cout << "size = " << size << ", ofs = " << ofs << std::endl;return 0;
}

输出结果

==默认风格==
[ 23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25;23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25;23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25;23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25;23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25;23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25]
==Python风格==
[[[ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25]],[[ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25]],[[ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25]],[[ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25]],[[ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25]],[[ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25]]]
==Numpy风格==
array([[[ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25]],[[ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25]],[[ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25]],[[ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25]],[[ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25]],[[ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25]]], dtype='uint8')
==C风格==
{ 23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25}
==默认风格==
[ 23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25;23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25;23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25;92,  96, 100,  92,  96, 100,  92,  96, 100,  92,  96, 100,  92,  96, 100,  92,  96, 100;23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25;23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25]
==Python风格==
[[[ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25]],[[ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25]],[[ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25]],[[ 92,  96, 100], [ 92,  96, 100], [ 92,  96, 100], [ 92,  96, 100], [ 92,  96, 100], [ 92,  96, 100]],[[ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25]],[[ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25]]]
==Numpy风格==
array([[[ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25]],[[ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25]],[[ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25]],[[ 92,  96, 100], [ 92,  96, 100], [ 92,  96, 100], [ 92,  96, 100], [ 92,  96, 100], [ 92,  96, 100]],[[ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25]],[[ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25], [ 23,  24,  25]]], dtype='uint8')
==C风格==
{ 23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,92,  96, 100,  92,  96, 100,  92,  96, 100,  92,  96, 100,  92,  96, 100,  92,  96, 100,23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25,  23,  24,  25}
==Python风格==
[[ 23,  24,  25],[ 23,  24,  25],[ 23,  24,  25],[ 92,  96, 100],[ 23,  24,  25],[ 23,  24,  25]]

[[1, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 1, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 1, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 1, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 1, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 1, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 1, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 1, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 1]]
[[0, 0],[1, 0],[0, 1],[0, 0],[0, 0],[0, 0],[0, 0],[0, 0],[0, 0],[0, 0]]
[[0, 0],[0, 0],[0, 0],[0, 0]]
size = [10 x 10], ofs = [1, 5]
  • 为用户分配的数据创建一个标头。 执行以下操作可能很有用:
  1. 使用 OpenCV 处理“外部”数据(例如,当您实现 DirectShow* 过滤器或 gstreamer 的处理模块等时)
void process_video_frame(const unsigned char* pixels,int width, int height, int step)
{Mat img(height, width, CV_8UC3, pixels, step);GaussianBlur(img, img, Size(7,7), 1.5, 1.5);
}
  1. 快速初始化小矩阵 / 获得超快速元素访问
double m[3][3] = {{a, b, c}, {d, e, f}, {g, h, i}};
Mat M = Mat(3, 3, CV_64F, m).inv();

这种用户分配数据的部分但非常常见的情况是从 CvMatIplImageMat 的转换。为此,函数 cv::cvarrToMat 采用指向 CvMat 或 IplImage 的指针以及指示是否复制数据的可选标志。

Ptr<IplImage> iplimg(cvLoadImage(imagename.c_str())); // Ptr<T> is safe ref-counting pointer class
if(!iplimg)
{fprintf(stderr, "Can not load image %s\n", imagename.c_str());return -1;
}
Mat img = cv::cvarrToMat(iplimg); // cv::Mat replaces the CvMat and IplImage, but it's easy to convert
// between the old and the new data structures (by default, only the header
// is converted, while the data is shared)
  • 使用 MATLAB 风格的数组初始化器 zeros()、ones()、eye()
// create a double-precision identity matrix and add it to M.
M += Mat::eye(M.rows, M.cols, CV_64F);
  • 使用逗号分隔的初始化
// create a 3x3 double-precision identity matrix
Mat M = (Mat_<double>(3,3) << 1, 0, 0, 0, 1, 0, 0, 0, 1);

使用这种方法,您首先使用适当的参数调用 Mat 类的构造函数,然后只需将 << 运算符放在逗号分隔的值后面,这些值可以是常量、变量、表达式等。另外,请注意避免编译错误所需的额外括号。

测试代码

#include <opencv2/highgui.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>int main()
{cv::Mat M(5, 5, CV_64FC3, cv::Scalar(1, 3, 5));std::cout << cv::format(M, cv::Formatter::FMT_PYTHON) << std::endl;std::cout << std::endl;M += cv::Mat::eye(M.rows, M.cols, CV_64FC3);std::cout << cv::format(M, cv::Formatter::FMT_PYTHON) << std::endl;std::cout << std::endl;cv::Mat M1 = (cv::Mat_<double>(3, 3) << 1, 0, 0, 0, 1, 0, 0, 0, 1);std::cout << cv::format(M1, cv::Formatter::FMT_PYTHON) << std::endl;return 0;
}

输出结果

[[[1, 3, 5], [1, 3, 5], [1, 3, 5], [1, 3, 5], [1, 3, 5]],[[1, 3, 5], [1, 3, 5], [1, 3, 5], [1, 3, 5], [1, 3, 5]],[[1, 3, 5], [1, 3, 5], [1, 3, 5], [1, 3, 5], [1, 3, 5]],[[1, 3, 5], [1, 3, 5], [1, 3, 5], [1, 3, 5], [1, 3, 5]],[[1, 3, 5], [1, 3, 5], [1, 3, 5], [1, 3, 5], [1, 3, 5]]][[[2, 3, 5], [1, 3, 5], [1, 3, 5], [1, 3, 5], [1, 3, 5]],[[1, 3, 5], [2, 3, 5], [1, 3, 5], [1, 3, 5], [1, 3, 5]],[[1, 3, 5], [1, 3, 5], [2, 3, 5], [1, 3, 5], [1, 3, 5]],[[1, 3, 5], [1, 3, 5], [1, 3, 5], [2, 3, 5], [1, 3, 5]],[[1, 3, 5], [1, 3, 5], [1, 3, 5], [1, 3, 5], [2, 3, 5]]][[1, 0, 0],[0, 1, 0],[0, 0, 1]]

创建数组后,它会通过引用计数机制自动进行管理。如果数组头建立在用户分配的数据之上,你应该自己处理数据。 当没有人指向它时,数组数据被释放。如果要在调用数组析构函数之前释放数组头指向的数据,请使用 Mat::release()。

关于数组类的下一个重要知识是元素访问。 本手册已经描述了如何计算每个数组元素的地址。通常,不需要在代码中直接使用公式。 如果知道数组元素类型(可以使用方法 Mat::type() 检索),可以访问二维数组的元素 M i j M_{ij} Mij​,如下所示:

M.at<double>(i,j) += 1.f;

假设 M 是一个双精度浮点数组。 对于不同数量的维度,该方法有几种变体。如果您需要处理二维数组的一整行,最有效的方法是先获取指向该行的指针,然后只需使用普通的 C 运算符 [] :

// compute sum of positive matrix elements
// (assuming that M is a double-precision matrix)
double sum = 0;
for(int i = 0; i < M.rows; i++)
{const double* Mi = M.ptr<double>(i);for(int j = 0; j < M.cols; j++)sum += std::max(Mi[j], 0.);
}

某些操作,例如上面的操作,实际上并不依赖于数组形状。它们只是一个一个地处理一个数组的元素(或来自多个具有相同坐标的数组的元素,例如,数组加法)。这样的操作被称为 element-wise。 检查所有输入/输出数组是否连续是有意义的,即在每行的末尾没有间隙。如果是,则将它们作为长单行处理:

// compute the sum of positive matrix elements, optimized variant
double sum=0;
int cols = M.cols, rows = M.rows;
if(M.isContinuous())
{cols *= rows;rows = 1;
}
for(int i = 0; i < rows; i++)
{const double* Mi = M.ptr<double>(i);for(int j = 0; j < cols; j++)sum += std::max(Mi[j], 0.);
}

在连续矩阵的情况下,外部循环体只执行一次。 因此,开销较小,这在小矩阵的情况下尤其明显。最后,还有 STL 风格的迭代器,它们足够聪明,可以跳过连续行之间的间隙:

// compute sum of positive matrix elements, iterator-based variant
double sum=0;
MatConstIterator_<double> it = M.begin<double>(), it_end = M.end<double>();
for(; it != it_end; ++it)sum += std::max(*it, 0.);

测试代码

#include <opencv2/highgui.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>int main()
{cv::Mat M = (cv::Mat_<double>(3, 3) << -1, 0, 1, 0, 1, -1, 1, -1, 0);std::cout << cv::format(M, cv::Formatter::FMT_PYTHON) << std::endl;std::cout << std::endl;M.at<double>(2, 1) += 1.f;std::cout << cv::format(M, cv::Formatter::FMT_PYTHON) << std::endl;double sum = 0;int cols = M.cols, rows = M.rows;if (M.isContinuous()){cols *= rows;rows = 1;}for (int i = 0; i < rows; i++){const double* Mi = M.ptr<double>(i);for (int j = 0; j < cols; j++)sum += std::max(Mi[j], 0.);}std::cout << "sum = " << sum << std::endl;double sum1 = 0;cv::MatConstIterator_<double> it = M.begin<double>(), it_end = M.end<double>();for (; it != it_end; ++it)sum1 += (std::max)(*it, 0.);std::cout << "sum1 = " << sum1 << std::endl;return 0;
}

输出结果

[[-1, 0, 1],[0, 1, -1],[1, -1, 0]][[-1, 0, 1],[0, 1, -1],[1, 0, 0]]
sum = 3
sum1 = 3

OpenCV中基本数据类型Mat类使用简析相关推荐

  1. OpenCV中图像以Mat类型保存时各通道数据在内存中的组织形式及python代码访问各通道数据的简要方式...

    OpenCV中图像以Mat类型保存时各通道数据在内存中的组织形式及python代码访问各通道数据的简要方式 以最简单的4 x 5三通道图像为例,其在内存中Mat类型的数据组织形式如下: 每一行的每一列 ...

  2. OpenCV参考手册之Mat类详解

    OpenCV参考手册之Mat类详解(一) OpenCV参考手册之Mat类详解(二) OpenCV参考手册之Mat类详解(三)

  3. java jdbc 教程_java JDBC系列教程之JDBC类的简析与JDBC的基础操作

    什么是JDBC? 概念:JAVA Database Connectivity Javas数据库连接,Java语言操作数据库接口,然后由各个数据库厂商去实现这个接口,提供数据库驱动java包,我们可以使 ...

  4. Python中的基本函数及其常用用法简析

    分享Python中的基本函数及其常用用法简析,首先关于函数的解释函数是为了达到某种目的而采取的行为,函数是可重复使用的,用来实现某个单一功能或者功能片段的代码块,简单来说就是由一系列的程序语句组成的程 ...

  5. opencv mat用数组初始化_10、OpenCV中图像和Mat类型(一)

    Mat类型可以被认为是OpenCV库的核心. OpenCV库中绝大多数的函数都是Mat类的成员,以Mat作为参数,或者Mat作为返回值. Mat类用于表示任意维数的密集数组.即使对于数组中的该条目为零 ...

  6. OpenCV中IplImage/CvMat/Mat转化关系

    原文链接:http://www.cnblogs.com/summerRQ/articles/2406109.html 如对内容和版权有何疑问,请拜访原作者或者通知本人. opencv中常见的与图像操作 ...

  7. OpenCV学习三:Mat类详解

    目标 我们有多种方法可以获得从现实世界的数字图像:数码相机.扫描仪.计算机体层摄影或磁共振成像就是其中的几种.在每种情况下我们(人类)看到了什么是图像.但是,转换图像到我们的数字设备时我们的记录是图像 ...

  8. OpenCV参考手册之Mat类详解1

    Mat类 OpenCV c + + n 维稠密数组类 class CV_EXPORTS Mat { public: / / - -很多的方法... ... /*!包括几位字段: -神奇的签名 -连续性 ...

  9. OpenCV中 CvArr、Mat、CvMat、IplImage、BYTE转换(总结而来)

    一.Mat类型:矩阵类型,Matrix. 在openCV中,Mat是一个多维的密集数据数组.可以用来处理向量和矩阵.图像.直方图等等常见的多维数据. Mat有3个重要的方法: 1.Mat mat =  ...

最新文章

  1. SQL Server 判断数据库是否存在,表是否存在
  2. Matlab-PEAKS函数曲线
  3. unittest 多个测试文件只开一次浏览器_接口测试平台代码实现75: 多接口用例15
  4. 这几个在搞低功耗广域网的,才是物联网的黑马
  5. java编写一个程序_计算已知长和宽的长方形的周长,请教一下大佬们,我们java留了一个作业,编写程序,定义一个接口Comput,声明计算周长和面积的方法...
  6. Spring Boot 细节挖掘(全局异常处理)
  7. c++incline函数
  8. 小心投机分子绿坝软件的苦肉计
  9. hdu 4308 Saving Princess claire_ 广搜 多校联合赛第七题
  10. MySQL对分隔符的处理(一)
  11. 进化计算(八)——MOEA/D算法详解Ⅱ
  12. win10系统做T3服务器,win10系统安装用友t3的图文教程
  13. DCMP2.0项目总结_页面
  14. QTreeWidget的右键菜单实现
  15. fiash星空动画制作_Flash8简单制作酷炫的星空飞越动画特效
  16. Redis五类数据类型简述
  17. 普通人应该怎么赚钱,下班后可在家操作的四个兼职副业分享
  18. Verilog HDL——运算符
  19. 联想计算机网络唤醒是怎么回事,笔记本开启网络唤醒功能设置的操作方法
  20. 阿里高级技术专家张建飞:面对复杂业务,if-else coder 如何升级?

热门文章

  1. 移动硬盘磁盘未被格式化要怎样办啊
  2. C# 实现卡布列克数
  3. 深耕AI视觉“端智能”创新企业阅面科技完成数亿元B轮融资
  4. 大家有没有感觉今年的程序员找工作非常困难
  5. 专属Python开发者的完美终端工具—Rich
  6. 怎么查看笔记本显卡信息
  7. 诺禾:程序员是青春饭?
  8. 大连东软信息学院软件测试技术课程题库,自动化测试复习(大连东软信息学院整理版)...
  9. c语言学习笔记(8)c 语言面试题(二)
  10. oracle shutdown没有反应解决