【学习OpenCV】—— 深入了解 cv::Mat

  • rows:行数,或者高度;cols:列数,或者宽度

实现原理

cv::Mat 有两个必不可少的组成部分,一个头部,一个数据块。

class CV_EXPORTS Mat
{
public:

    int flags;
    //! the matrix dimensionality, >= 2
    int dims;
    //! the number of rows and columns or (-1, -1) when the matrix has more than 2 dimensions
    int rows, cols;

    //! pointer to the data
    uchar* data;

}

cv::Mat 头部属性主要有:cols、rows 或 channels,而数据块(uchar* data)包含了图像中所有像素的值。

cv::Mat 有一个很重要的特性,就是只有在明确要求时((copyTo、clone)),内存块才会被复制。实际上,大多数操作都只仅仅复制了 cv::Mat 的头部信息,因此多个对象会同时指向同一个数据块。这种内存管理模式可以提高应用程序的运行效率,避免内存泄露。

cv::Mat image1(240, 320, CV_8U, 100);

我们需要指定每个矩阵元素的类型,CV_8U 表示每个像素对应一个字节,U表示无符号,字母S则是有符号。对于彩色图像,可用 CV_8UC3(C表示channel)

我们可以随时用 create 方法分配或重新分配图像的数据块,如果图像已经分配,首先其原来的内容会被释放。出于对性能的考虑,如果新的大小和类型与原来的相同,就不会重新分配内存(可以想象,会直接覆盖)。

// 重新分配一个新图像
// (仅在大小或类型不同时)
image1.create(200, 200, CV_8U);

一旦没有了指向 cv::Mat 对象的引用,分配的内存就会被自动释放。这一点可避免 C++ 动态内存分配(new)中常常发生的内存泄露问题。这是 OpenCV2 中的一个关键机制,通过 cv::Mat 实现引用计数(reference count)和浅复制。当在两个图像之间赋值时,图像数据(也即像素)并不会被复制,此时两个图像指向同一个内存块。

一些细节

cv::Mat image = cv::imread("...");
  • (1)Mat 类型

    if (image.type() == CV_8U)
        image.at(i, j) = ...;
    
    if (image.type() == CV_8UC3)
        image.at(i, j)[0] = ...;
        image.at(i, j)[1] = ...;
        image.at(i, j)[2] = ...;     

你可能感兴趣的:(opencv)