官方对mat介绍的原话:

Mat represents an n-dimensional dense numerical single-channel or multi-channel array. It can be used to store real or complex-valued vectors and matrices, grayscale or color images, voxel volumes, vector fields, point clouds, tensors, histograms (though, very high-dimensional histograms may be better stored in a SparseMat     译文:Mat类用于表示一个多维的单通道或者多通道的稠密数组。能够用来保存实数或复数的向量、矩阵,灰度或彩色图像,立体元素,点云,张量以及直方图(高维的直方图使用SparseMat保存比较好)。简而言之,Mat就是用来保存多维的矩阵的.

    opencv2的Mat类带来的改变:

    1不必手动开辟空间   2不必再在不需要的时候立即将空间释放

  Mat由两个数据部分组成:矩阵头(包含矩阵尺寸、存储方法、存储地址等信息)和一个指向存储所有像素值的矩阵的指针。

   

    问题:关于图像拷贝问题?

    OpenCV使用引用计数机制来解决复制图像的问题。其思路是让每个 Mat 对象有自己的信息头,但共享同一个矩阵。这通过让矩阵指针指向同一地址而实现。而拷贝构造函数则只拷贝信息头和矩阵指针 ,而不拷贝矩阵。

Mat A, C;                                 // 只创建信息头部分
A = imread(argv[1], CV_LOAD_IMAGE_COLOR); // 这里为矩阵开辟内存

Mat B(A);                                 // 使用拷贝构造函数

C = A;                                    // 赋值运算符

    以上代码中的所有Mat对象最终都指向同一个也是唯一一个数据矩阵。

如果想让各自对象都有一个信息头和矩阵,这时候可以使用cone()和copyTo()两个成员函数。   

Mat F = A.clone();
Mat G;
A.copyTo(G);

    问题:如何创建ROI?

    你可以创建只引用部分数据的信息头。比如想要创建一个感兴趣区域( ROI ),你只需要创建包含边界信息的信息头。

Mat D (A, Rect(10, 10, 100, 100) ); // using a rectangle
Mat E = A(Range:all(), Range(1,3)); // using row and column boundariesq

    其中Range()指定感兴趣行或列的范围,Range指从起始索引到终止索引(不包括终止索引)的一连续序列。

 

     问题:图像的存储方式

     存储像素值需要指定颜色空间和数据类型。

     常用的颜色空间:RGB   HSV   HLS   灰度级空间 等。

<uchar>类型;如果是RGB彩色图,存放<Vec3b>类型。

     单通道灰度图数据存放格式:

opencv如何保存16位深度图像 opencv 保存mat_数据类型

     多通道的图像中,每列并列存放通道数量的子列,如RGB三通道彩色图:

opencv如何保存16位深度图像 opencv 保存mat_opencv_02

isContinuous()函数来判断图像数组是否为连续的。

     问题:如何访问图像中的像素

     访问图像中像素的三个方法:

     1.指针访问:c操作符[]

     2.迭代器iterator

     3.动态地址计算

     三种方法在访问速度上有差异

    第一种:用指针访问  访问速度最快

    void colorreduce(Mat& inputImage,Mat& outputImage,int div)

      {

        outputImage=inputImage.clone();

        int rowNumber=outputImage.rows;

        int colNumber=outputImage.cols*outputImage.channels();//每一行元素的个数

        for(int i=0;i<rowNumber;i++)

         {

           uchar* data=outputImage.ptr<uchar>(i);

         //uchar* data=outputImage.ptr<uchar>(i)[j];//获取第i行第j列元素的值

        for(int j=0;j<colNumber;j++)

{             data[j] = data[j] / div*div + div / 2;

}          //*data++ = *data / div*div + div / 2; //所有方法中最快的

       

         }

 

     第二种:用迭代器操作像素

     这里,我们只需要获取图像矩阵的begin和end,然后增加迭代直至从begin到end。将*操作符添加到迭代指针前,即可访问当前指向的内容。相比指针容易产生越界的情况,迭代器是绝对安全的

     void colorReduce(Mat& inputImage,Mat& outputImage,int div)

      {

        outputImage = inputImage.clone();           Mat_<Vec3b>::iterator it = outputImage.begin<Vec3b>();           Mat_<Vec3b>::iterator itend = outputImage.end<Vec3b>();           for (; it != itend; ++it)             {              (*it)[0] = (*it)[0] / div*div + div / 2;              (*it)[1] = (*it)[1] / div*div + div / 2;              (*it)[2] = (*it)[2] / div*div + div / 2;             }       

     第三种:动态地址计算

     void colorReduce(Mat& inputImage,Mat& outputImage,int div)

       {

         outputImage = inputImage.clone();          int rowNumber = outputImage.rows;          int colNumber = outputImage.cols;          for (int i = 0; i < rowNumber; i++)           {            for (int j = 0; j < colNumber; j++)             {               outputImage.at<Vec3b>(i,j)[0]= 

outputImage.at<Vec3b>(i,j)[0]/div*div+div/2;               outputImage.at<Vec3b>(i,j)[1]=

outputImage.at<Vec3b>(i,j)[1]/div*div+div/2;               outputImage.at<Vec3b>(i,j)[2]=

outputImage.at<Vec3b>(i,j)[2]/div*div+div/2;

            }

           }

        }

      

      问题:如何显式地创建一个Mat对象

      Mat 不但是一个很赞的图像容器类,它同时也是一个通用的矩阵类,所以可以用来创建和操作多维矩阵。创建一个Mat对象有多种方法:

     一:Mat() 构造函数

Mat M(2,2, CV_8UC3, Scalar(0,0,255)); 
     cout << "M = " << endl << " " << M << endl << endl;

     显示结果:

         

opencv如何保存16位深度图像 opencv 保存mat_opencv如何保存16位深度图像_03

 

Scalar 是个short型vector。指定这个能够使用指定的定制化值来初始化矩阵.

     二:Create()

M.create(4,4, CV_8UC(2));
    cout << "M = "<< endl << " "  << M << endl << endl;

     结果:

opencv如何保存16位深度图像 opencv 保存mat_opencv_04

    这个创建方法不能为矩阵设初值,它只是在改变尺寸时重新为矩阵数据开辟内存

MATLAB形式的初始化方式: zeros(), ones(), :eyes() 。使用以下方式指定尺寸和数据类型:

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;

     结果:

         

opencv如何保存16位深度图像 opencv 保存mat_数据类型_05

     mat的常见属性

data  uchar型的指针。Mat类分为了两个部分:矩阵头和指向矩阵数据部分的指针,data就是指向矩阵数据的指针

dims

rows

cols

size 矩阵的大小,size(cols,rows),如果矩阵的维数大于2,则是size(-1,-1)

channels

     7:type    表示了矩阵中元素的类型以及矩阵的通道个数,它是一系列的预定义的常量,其命名规则为CV_(位数)+(数据类型)+(通道数)。具体的有以下值:

CV_8UC1

CV_8UC2

CV_8UC3

CV_8UC4

CV_8SC1

CV_8SC2

CV_8SC3

CV_8SC4

CV_16UC1

CV_16UC2

CV_16UC3

CV_16UC4

CV_16SC1

CV_16SC2

CV_16SC3

CV_16SC4

CV_32SC1

CV_32SC2

CV_32SC3

CV_32SC4

CV_32FC1

CV_32FC2

CV_32FC3

CV_32FC4

CV_64FC1

CV_64FC2

CV_64FC3

CV_64FC4

     8:depth   矩阵中元素的一个通道的数据类型,这个值和type是相关的。例如 type为 CV_16SC2,一个2通道的16位的有符号整数。那么,depth则是CV_16S。depth也是一系列的预定义值,