您的位置:首页 > 运维架构

opencv的Mat类基本操作

2017-09-11 15:47 399 查看
    官方对mat介绍的原话:
    The class 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   灰度级空间 等。

     Mat和Matlab里的数组格式有点像,但一般是二维向量,如果是灰度图,一般存放<uchar>类型;如果是RGB彩色图,存放<Vec3b>类型。

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



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



     注意通道的顺序反转了:BGR。通常情况内存足够大的话图像的每一行是连续存放的,也就是在内存上图像的所有数据存放成一行,这中情况在访问时可以提供很大方便。可以用 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列元素的值

        fo
f497
r(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;


     显示结果:

         

 

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

     二:Create()

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


     结果:



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

     三: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;


     结果:

         


     mat的常见属性

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

     2:dims 矩阵的维度,例如5*6矩阵是二维矩阵,则dims=2,三维矩阵dims=3.

     3:rows  矩阵的行数

     4:cols   矩阵的列数

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

     6:channels 矩阵元素拥有的通道数

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

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

    关于使用data访问图像中像素的一些问题:http://blog.csdn.net/zy122121cs/article/details/47029431
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  opencv