Recognize Mat
OpenCV has been around since 2001. In those days the library was built around a C interface and to store the image in the memory they used a C structure called IplImage. This is the one you’ll see in most of the older tutorials and educational materials. The problem with this is that it brings to the table all the minuses of the C language. The biggest issue is the manual memory management. It builds on the assumption that the user is responsible for taking care of memory allocation and deallocation. While this is not a problem with smaller programs, once your code base grows it will be more of a struggle to handle all this rather than focusing on solving your development goal.
OpenCV 于 2001 年问世。当时,该库是围绕 C 接口构建的,为了将图像存储在内存中,他们使用了名为 IplImage 的 C 结构。这是您在大多数较旧的教程和教育材料中都会看到的内容。这样做的问题是它暴露了 C 语言的所有缺点。最大的问题是手动内存管理。它建立在用户负责处理内存分配和释放的假设之上。虽然这对于较小的程序来说不是问题,但一旦您的代码库增长,处理所有这些问题将变得更加困难,而不是专注于解决您的开发目标。
Luckily C++ came around and introduced the concept of classes making easier for the user through automatic memory management (more or less). the good news is that C++ is fully compatible with C so no compatibility issues can arise from making the change. Therefore, OpenCV 2.0 introduced a new C++ interface which offered a new way of doing things which means you do not need to fiddle with memory management, making your code concise (less to write, to achieve more). the main downside of the C++ interface is that many embedded development systems at the moment support only C. Therefore, unless you are targeting embedded platforms, there’s no point to using the old methods (unless you’re a masochist programmer and you’re asking for trouble).
幸运的是,C++ 出现并引入了类的概念,通过自动内存管理(或多或少)使用户变得更容易。好消息是 C++ 与 C 完全兼容,因此进行更改不会出现兼容性问题。因此,OpenCV 2.0 引入了一个新的 C++ 接口,它提供了一种新的做事方式,这意味着您不需要摆弄内存管理,从而使您的代码简洁(编写更少,实现更多)。 C++ 接口的主要缺点是目前许多嵌入式开发系统仅支持 C。因此,除非您的目标是嵌入式平台,否则使用旧方法是没有意义的(除非您是一个受虐狂程序员并且您要求关于Mat,您首先需要了解的是,您不再需要手动分配其内存并在不需要时立即释放它。虽然这样做仍然是可能的,但大多数 OpenCV 函数都会自动分配其输出数据。如果您传递一个已经存在的 Mat 对象(该对象已经为矩阵分配了所需的空间),那么这是一个不错的奖励,它将被重用。换句话说,我们始终只使用执行任务所需的内存。
Mat is basically a class with two data parts: the matrix header (containing information such as the size of the matrix, the method used for storing, at which address is the matrix stored, and so on) and a pointer to the matrix containing the pixel values (taking any dimensionality depending on the method chosen for storing) . the matrix header size is constant, however the size of the matrix itself may vary from image to image and usually is larger by orders of magnitude.
Mat 基本上是一个具有两个数据部分的类:矩阵头(包含矩阵大小、使用的方法等信息)用于存储,存储矩阵的地址等等)和指向包含像素值的矩阵的指针(根据选择的存储方法采用任何维数)。矩阵头大小是恒定的,但是矩阵本身的大小可能因图像而异,并且通常会大几个数量级。
OpenCV is an image processing library. It contains a large collection of image processing functions. To solve a computational challenge, most of the time you will end up using multiple functions of the library. Because of this, passing images to functions is a common practice. We should not forget that we are talking about image processing algorithms, which tend to be quite computational heavy. The last thing we want to do is further decrease The speed of your program by making unnecessary copies of potentially large images.
OpenCV 是一个图像处理库。它包含大量图像处理功能。为了解决计算挑战,大多数时候您最终会使用库的多个函数。因此,将图像传递给函数是一种常见的做法。我们不应该忘记,我们正在谈论图像处理算法,这些算法往往计算量很大。我们最不想做的就是通过对可能很大的图像进行不必要的复制来进一步降低程序速度。
为了解决这个问题,OpenCV 使用了引用计数系统。这个想法是每个 Mat 对象都有自己的标头,但是可以通过让两个 Mat 对象的矩阵指针指向相同的地址来共享矩阵。此外,复制运算符只会复制标头和指向大矩阵的指针,而不是数据本身。
Mat A, C; // creates just the header parts
A = imread(argv[1], IMREAD_COLOR); // here we'll know the method used (allocate matrix)
Mat B(A); // Use the copy constructor
C = A; // Assignment operator
All the above objects, in the end, point to the same single data matrix and making a modification using any of them will affect all the other ones as well. In practice the different objects just provide different access methods to the same underlying data. Nevertheless, their header parts are different. the real interesting part is that you can create headers which refer to only a subsection of the full data. For example, to create a region of interest (ROI) in an image you just create a new header with the new boundaries:
上述所有对象,最终都指向同一个数据矩阵,使用其中任何一个进行修改都会影响其他对象。实际上,这些不同的对象只是提供了对同一底层数据的不同访问方法。不过,它们的头部部分是不同的。最有趣的部分是你可以创建只引用完整数据某个子部分的头部。例如,要在图像中创建感兴趣区域(ROI),你只需创建一个新的头部并设定新的边界:
Mat D (A, Rect(10, 10, 100, 100) ); // using a rectangle
Mat E = A(Range::all(), Range(1,3)); // using row and column boundaries
Now you may ask – if the matrix itself may belong to multiple Mat objects, who takes responsibility for cleaning it up when it’s no longer needed? The short answer is: The last object that used it. This is handled by using a reference counting mechanism. Whenever somebody copies a header of a Mat object, a counter is increased for the matrix. Whenever a header is cleaned, this counter is decreased. When the counter reaches zero the matrix is freed. Sometimes you will want to copy the matrix itself too, so OpenCV provides cv::Mat::clone() and cv::Mat::copyTo() functions.
现在您可能会问 - 如果矩阵本身可能属于多个 Mat 对象,那么当不再需要它时谁负责清理它?简短的答案是:最后一个使用它的对象。这是通过使用引用计数机制来处理的。每当有人复制 Mat 对象的标头时,矩阵的计数器就会增加。每当清理标头时,该计数器就会减少。当计数器达到零时,矩阵被释放。有时您也想复制矩阵本身,因此 OpenCV 提供了 cv::Mat::clone() 和 cv::Mat::copyTo() 函数。
Mat F = A.clone();
Mat G;
A.copyTo(G);
Output image allocation for OpenCV functions is automatic (unless specified otherwise).
You do not need to think about memory management with OpenCV’s C++ interface.
The assignment operator and The copy constructor only copy The header.
The underlying matrix of an image may be copied using the cv::Mat::clone() and cv::Mat::copyTo() functions.
OpenCV 函数的输出图像分配是自动的(除非另有指定)。
您无需考虑 OpenCV 的 C++ 接口的内存管理。
赋值运算符和复制构造函数仅复制标头。
可以使用 cv::Mat::clone() 和 cv::Mat::copyTo() 函数复制图像的基础矩阵。
显式创建 Mat 对象
cv::Mat M(2,2, CV_8UC3, cv::Scalar(0,0,255));
std::cout << "M = " << std::endl << " " << M << std::endl;
M =
[ 0, 0, 255, 0, 0, 255;
0, 0, 255, 0, 0, 255]
MATLAB 样式初始值设定项: cv::Mat::zeros 、 cv::Mat::ones 、 cv::Mat::eye 。指定要使用的大小和数据类型:
Mat E = Mat::eye(4, 4, CV_64F);
cout << "E = " << endl << " " << E << endl << endl;
Mat O = Mat::ones(2, 2, CV_32F);
cout << "O = " << endl << " " << O << endl << endl;
Mat Z = Mat::zeros(3,3, CV_8UC1);
cout << "Z = " << endl << " " << Z << endl << endl;
M =
[ 0, 0, 255, 0, 0, 255;
0, 0, 255, 0, 0, 255]
E =
[1, 0, 0, 0;
0, 1, 0, 0;
0, 0, 1, 0;
0, 0, 0, 1]
O =
[1, 1;
1, 1]
Z =
[ 0, 0, 0;
0, 0, 0;
0, 0, 0]