zoukankan      html  css  js  c++  java
  • OpenCV 之 Mat 类

      数字图像可看作一个数值矩阵, 其中每个元素代表一个像素点,如下:

       

       OpenCV 中,用 Mat 表示数值矩阵,Mat 是很关键的一种数据结构,因为 OpenCV 中的大部分函数都和 Mat 有关:

       有的是 Mat 的成员函数;有的把 Mat 作为参数;还有的将 Mat 作为返回值。

     1  Mat 简介

      Mat 表示的是 N 维稠密矩阵,与稠密矩阵相对的是稀疏矩阵(只存储非零的像素值),后者常用于直方图处理中,OpenCV 中对应为 cv::SparseMat

      如下所示:第一个为稠密矩阵的存储方式,存储所有的像素数值;第二个为稀疏矩阵的存储方式,只存储非零的像素值

          $quad egin{bmatrix} 0 & 2 & 0 \ 1 & 0 & 1 \ 0 & 2 & 0 end{bmatrix} $        $quad egin{bmatrix}  & 2 &  \ 1 &  & 1 \  & 2 &  end{bmatrix} $

      当 N=1 时,所有像素存储为一行;当 N=2 时,所有像素按照一行行的顺序排列;当 N=3 时,所有像素按照一面面的顺序排列,其中一行行的像素构成一个平面。

      下图左,为灰度图的存储方式;图右,为 RGB 图像的存储方式,注意其存储顺序为 BGR (Blue->Green->Red)

             

    2  Mat 特点

    2.1  组成

       Mat 类包含两部分,一是 矩阵头 (matrix header),二是 矩阵指针 (pointer to matrix),部分矩阵头如下:

    int  flags;  // signaling the contents of the matrix
    int  dims;   // dimensions
    int  rows, cols;  // rows and columns 
    MatSize  size;  // 
    MatStep  step;  //

      矩阵指针如下,指向包含所有像素值的矩阵

    uchar* data;  // pointer to the data

    2.2  赋值算子

      Mat 类中的赋值算子 "=" 和 拷贝构造函数,涉及的是浅拷贝,因此,当执行这两个操作时,仅仅是复制了矩阵头。

      如果想要深拷贝,达到复制图像矩阵的目的,应使用 clone()copyTo() 函数,如下图所示 (摘自参考资料 -- 4):

      

    2.3  代码示例

      简单验证如下,将矩阵 m3 由 copyTo() 函数复制给 m1,而 m2 由 m1 直接赋值,二者指向的是同样的数据。因此,如果改变了 m1,则 m2 对应的矩阵数值,也会进行相应的改变。

    Mat m1(3, 3, CV_32FC1, Scalar(1.1f) );
    cout << "m1 = " << endl << " " << m1 << endl << endl;
    // using assign operator Mat m2
    = m1; cout << "m2 = " << endl << " " << m2 << endl << endl; Mat m3(3, 3, CV_32FC1, Scalar(3.3f) ); m3.copyTo(m1); cout << "m1 = " << endl << " " << m1 << endl << endl; cout << "m2 = " << endl << " " << m2 << endl << endl;

    3  Mat 创建

    3.1  数据类型

      在创建 Mat 之前,首先了解 Mat 中元素的数据类型,其格式为 CV_{8U, 16S, 16U, 32S, 32F, 64F}C{1, 2, 3}CV_{8U, 16S, 16U, 32S, 32F, 64F}C(n)

      第一个 {} 表示数据的类型:

    CV_8U  - 8-bit 无符号整数 ( 0..255 )
    CV_8S  - 8-bit 有符号整数 ( -128..127 )
    CV_16U - 16-bit 无符号整数 ( 0..65535 )
    CV_16S - 16-bit 有符号整数 ( -32768..32767 )
    CV_32S - 32-bit 有符号整数 ( -2147483648..2147483647 )
    CV_32F - 32-bit 浮点数 ( -FLT_MAX..FLT_MAX, INF, NAN )
    CV_64F - 64-bit 浮点数 ( -DBL_MAX..DBL_MAX, INF, NAN )

     第二个 {} 或 (n),表示的是通道:

    CV_8UC3 等价于 CV_8UC(3) - 3通道 8-bit 无符号整数

    3.2  创建方式

    3.2.1  构造函数

      创建一个 3 行 5 列,3 通道 32 位,浮点型的矩阵,通道 1, 2, 3 的值分别为 1.1f,2.2f,3.3f

    Mat m(3, 5, CV_32FC3, Scalar(1.1f, 2.2f, 3.3f) );
    cout << "m = " << endl << " " << m << endl << endl;

      输出的矩阵如下:

      

    3.2.2  create 函数

      使用 Mat() + create() + setTo(),也可以构建如上的数值矩阵

    Mat m;
    // Create data area for 3 rows and 10 columns of 3-channel 32-bit floats m.create(
    3,5,CV_32FC3);
    // Set the values in the 1st channel to 1.0, the 2nd to 0.0, and the 3rd to 1.0 m.setTo(Scalar(
    1.1f, 2.2f,3.3f)); cout << "m = " << endl << " " << m << endl << endl;

    3.2.3  特殊矩阵

      单位矩阵 (ones),对角矩阵 (eye),零矩阵 (zeros),如下所示:

    // 单位矩阵
    Mat O = Mat::ones(3, 3, CV_32F);
    cout << "O = " << endl << " " << O << endl << endl;
    // 零矩阵
    Mat Z = Mat::zeros(3, 3, CV_8UC1);
    cout << "Z = " << endl << " " << Z << endl << endl;
    // 对角矩阵
    Mat E = Mat::eye(3, 3, CV_64F);
    cout << "E = " << endl << " " << E << endl << endl;

    4  Mat 遍历

    4.1  at<>() 函数

       常用来遍历 Mat 元素的基本函数为 at<>(),其中 <> 内的数据类型,取决于 Mat 中元素的数据类型,二者的对应关系如下:

    CV_8U  --  Mat.at<uchar>(y,x)
    CV_8S  --  Mat.at<schar>(y,x)
    CV_16U --  Mat.at<ushort>(y,x)
    CV_16S --  Mat.at<short>(y,x)
    CV_32S --  Mat.at<int>(y,x)
    CV_32F --  Mat.at<float>(y,x)
    CV_64F --  Mat.at<double>(y,x)

      简单的遍历如下,使用了 Qt 的 qDebug() 来显示输出

    Mat m1 = Mat::eye(10, 10, CV_32FC1);
    // use qDebug() qDebug()
    << "Element (3,3) is : " << m1.at<float>(3,3); Mat m2 = Mat::eye(10, 10, CV_32FC2);
    // use qDebug()
    qDebug()
    << "Element (3,3) is " << m2.at<cv::Vec2f>(3,3)[0] << "," << m2.at<cv::Vec2f>(3,3)[1];

      注意:at<>() 函数中 () 内行索引号在前,列索引号在后,也即 (y, x)

    4.2  遍历方式

    4.2.1  高效遍历

    Mat& ScanImageAndReduceC(Mat& I, const uchar* const table)
    {
        // accept only char type matrices
        CV_Assert(I.depth() == CV_8U);
        int channels = I.channels();
        int nRows = I.rows;
        int nCols = I.cols * channels;
        if (I.isContinuous())
        {
            nCols *= nRows;
            nRows = 1;
        }
        int i,j;
        uchar* p;
        for(i=0; i<nRows; ++i)
        {
            p = I.ptr<uchar>(i);
            for (j = 0; j<nCols; ++j)
            {
                p[j] = table[p[j]];
            }
        }
        return I;
    }

    4.2.2  迭代器遍历

    Mat& ScanImageAndReduceIterator(Mat& I, const uchar* const table)
    {
        // accept only char type matrices
        CV_Assert(I.depth() == CV_8U);
        const int channels = I.channels();
        switch(channels)
        {
        case 1:
            {
                MatIterator_<uchar> it, end;
                for(it=I.begin<uchar>(), end=I.end<uchar>(); it!=end; ++it)
                    *it = table[*it];
                break;
            }
        case 3:
            {
                MatIterator_<Vec3b> it, end;
                for(it=I.begin<Vec3b>(), end=I.end<Vec3b>(); it!=end; ++it)
                {
                    (*it)[0] = table[(*it)[0]];
                    (*it)[1] = table[(*it)[1]];
                    (*it)[2] = table[(*it)[2]];
                }
            }
        }
        return I;
    }

     4.2.3  耗时计算

      比较上面两种方法的耗时,可使用如下代码来进行计算:

    double t = (double)getTickCount();
    // do something ...
    t = ((double)getTickCount() - t)/getTickFrequency();
    qDebug() << "Times passed in seconds: " << t << endl; // using qDebug()

    参考资料:

     1.  <Learning OpenCV3> chapter 4

     2.  OpenCV Tutorials / The Core Functionality (core module) / Mat - The Basic Image Container

     3.  OpenCV Tutorials / The Core Functionality (core module) / How to scan images, lookup tables and time measurement with OpenCV

     4.  OpenCV基础篇之Mat数据结构 

  • 相关阅读:
    C语言I博客作业09
    C语言I博客作业08
    C语言I作业07
    C语言博客作业06
    C语言I博客作业05
    C语言I博客作业04
    C语言I博客作业03
    C语言|博客作业07
    C语言|博客作业06
    C语言|博客作业05
  • 原文地址:https://www.cnblogs.com/xinxue/p/7298683.html
Copyright © 2011-2022 走看看