OpenCV之Mat

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37385181/article/details/81772535

目录

Mat类简析

Mat的构造

Mat基本操作汇总

Mat 类型转换

 imread函数

imwrite函数

像素值的存储方法


Mat类简析


    Mat类是用于保存图像以及其他矩阵数据的数据结构,默认情况下其尺寸为0。
    OpenCV 2.x 采用全新的图像数据结构Mat来代替C接口 cvMat 和 IplImage,这样使得开发效率大大提高。全新Mat结构不需要我们为其手动开辟空间,也不需要立即释放存储空间,Mat类能够自动管理内存Mat类由矩阵头和指向存储所有像素值的矩阵的指针构成。Mat类表示一个n维的密集数值单通道或多通道数组,它可用于存储实数或复数值的向量和矩阵、灰度或彩色图像、体素、向量场、点云、张量、直方图等。
    class CV_EXPORTS Mat
{
    public:
    //标志位
    int flags;
    //数组的维数,>=2
    int dims;
    //行和列的数量 或 (-1,-1),此时数组已超过2维
    int rows,cols;
    //指向数据的指针
    uchar *data;
    //指针的引用计数器,当阵列指向用户分配的数据时,指针为NULL。
    int * refcount;

}

    矩阵头用来刻画矩阵尺寸、存储方法、存储地址及引用次数等信息,矩阵头大小是一个常数,不会随图像的大小变化而变化,但是保存图像像素数据的矩阵则会随图像的大小变化而改变,通常数据量会很大,比矩阵头大几个数量级。这样在图像复制和传递过程中,内存主要的开销是由存放图像像素的矩阵引起的。因此,OpenCV使用了引用次数,当进行图像复制和传递时,不再复制整个Mat数据,而只是复制矩阵头和指向像素矩阵的指针。


关于flags:
https://blog.csdn.net/yiyuehuan/article/details/43701797

从定义可以看出flags是int类型,共占32位,结合上图可以看出各位所代表的意思。

从低位到高位:

0-2位代表depth即数据类型(如CV_8U),OpenCV的数据类型共7类,故只需3位即可全部表示。

3-11位代表通道数channels,因为OpenCV默认最大通道数为512,故只需要9位即可全部表示,可参照下面求通道数的部分。

0-11位共同代表type即通道数和数据类型(如CV_8UC3)

12-13位暂没发现用处,也许是留着后用,待发现了再补上。

14位代表Mat的内存是否连续,一般由creat创建的mat均是连续的,如果是连续,将加快对数据的访问

15位代表该Mat是否为某一个Mat的submatrix,一般通过ROI以及row()、col()、rowRange()、colRange()等得到的mat均为submatrix。

16-31代表magic signature,暂理解为用来区分Mat的类型,如果Mat和SparseMat

参考链接:https://blog.csdn.net/yiyuehuan/article/details/43701797

Mat的构造


方法1:使用Mat()构造函数
    (1)Mat::Mat() 无参数构造方法
    (2)Mat::Mat(int rows, int cols, int type)创建行数为rows,列数为cols,类型为type的图像.
    (3)Mat::Mat(Size size, int type) 创建大小为size, 类型为type的图像
    (4)Mat::Mat(int rows, int cols, int type, const Scalar& s) 创建行数为rows,列数为cols,类型为type的图像。并将所有元素初始化为s。
    (5)Mat::Mat(Size size, int type, const Scalar& s)创建大小为size,类型为type的图像,并将所有元素初始化为值s。
    (6)Mat::Mat(const Mat& m) 将m赋值给新创建的对象,此处不会对图像数据进行复制,m和新对象公用图像数据。

注意!其中的type一般为:CV_[位数][带符号与否][类型前缀]C[通道数]
    
    示例: Mat M(2, 2, CV_8UC3, Scalar(0, 0, 255));
    
方法二、指定维数创建Mat
    示例:
    int sz[3] = {2, 2, 2};
    Mat L(3, sz, CV_8UC, Scalar::all(0));
    上面示例演示了如何创建一个超过两维的矩阵,指定维数,然后传递一个指向一个数组的指针,这个数组包含每个维度的尺寸。


方法三、为已存在的IplImage指针创建信息头
    示例:
    IplImage* img = cvLoadImage("1.jpg",1);
    Mat mtx(img);        //转换IplImage * -> Mat

方法四、利用Create()函数
    利用Mat类中的Create()成员函数进行Mat类的初始化操作,示例:
    Mat M;
    M.create(4, 4, CV_8UC(2));
    需要注意的是,此创建方法不能为矩阵设初值,只是在改变尺寸时重新为矩阵数据开辟内存而已。

方法五、采用Matlab式的初始化方法
    zero(),ones(),eyes()

方法六、对肖局长使用逗号分隔式初始化函数
    Mat C = (Mat_<double(3,3)<< 0, -1, 0, -1, 5, -1, 0, -1, 0);

方法七、为已存在的对象新建新信息头
    深拷贝:clone()
    浅拷贝:copyTo()

Mat基本操作汇总


函数                                    功能
Mat::row                    创建一个具有指定了矩阵头中行数的参数的矩阵
Mat::col                      创建一个具有指定了矩阵头中列数的参数的矩阵
Mat::rowRange         为指定的行span创建一个新的矩阵头,可取指定行区间元素
Mat::colRange          为指定的列span创建一个矩阵头,可取指定列区间元素
Mat::clone                 创建一个数组及其基础数据的完整副本
Mat::copyTo              把矩阵复制到另一个矩阵中
Mat::convertTo         在缩放或不缩放的情况下转换为另一种数据类型
Mat::zeros                 返回一个指定的大小和类型全为0的数组
Mat::ones                  返回一个指定的大小和类型全为1的数组
Mat::channels           返回矩阵通道的数目

Mat::empty                如果数组没有元素,则返回true
Mat::at                       返回对指定数组元素的引用

Mat 类型转换


    OpenCV2.x 中图像数据容器一般有Mat、cvMat和IplImage, Mat是一个多维的密集数据数组,常用于进行计算性较高的矩阵、图像、直方图操作等。cvMat和IplImage是OpenCV1.x中提供的基于C语言版本的图像数据容器,侧重于图像数据本身的处理性能
    (1)Mat转换为IplImage类型和CvMat类型
    cv::Mat img;
    CvMat cvMatImg = img;
    IplImage IplImg = img;
    需要注意的是,转换后Mat、IplImage和CvMat共享图像矩阵数据,传递的是矩阵头,并不复制数据,IplImage和CvMat就没有引用计数功能。如果代码中的Img的数据被提前释放,cvMatImg和IplImg也就失去了相应数据,所以在释放数据时需要谨慎。
    (2)IplImage类型和CvMat类型转换为Mat类型
    IplImage * IplImg = cvLoadImage("fruits.jpg");
    Mat img(IplImg,true);
    OpenCV2.x中提供Mat类兼容OpenCV1.x中的IplImage和CvMat的两个构造函数:Mat::Mat(const CvMat* m, bool copyData = false) 和 Mat::Mat(const IplImage* img, bool copyData = false).如果copyData的值是false,那么Mat将与IplImage或CvMat共用同一矩阵数据;如果copyData的值是true,Mat会新申请内存空间,然后将IplImage或CvMat的数据复制到Mat的数据区

#图像读取显示保存

    OpenCV中实现类似MATLAB的读取显示图像函数是highgui模块中的imread、namedWindow、imshow和imwrite函数。

 

 imread函数


    函数imread返回的是Mat对象,如果读取文件失败,函数会返回一个空矩阵,那么srcImage.data的值是NULL,因此正常读取完文件后,我们可以利用srcImage.data或srcImage.empty()函数进行返回值检查,以确保文件正常载入。
    Mat imread(const string& filename, int flags = 1)
    函数解析:
    读取文件图像,参数filename表示读取文件的地址文件名;flags表示读取图像的颜色类型,默认参数为1,函数返回3通道图像。参数flags设置为CV_LOAD_IMAGE_ANYDEPTH,表示返回16bit或32bit图像(当输入为相同深度时),否则返回8bit图像;设置为CV_LOAD_IMAGE_COLOR,函数返回为单色图像;设置为CV_LOAD_IMAGE_GRAYSCALE,函数返回为通道图像。另外flags可设置为0,该函数返回单通道图像;flags小于0,则函数不对图像进行通道转换;flags大于0,函数将强制返回3通道图像。
    


imwrite函数


    bool imwrite(const string& filename, InputArray img, const vector<int>& params = vector<int>() )
    函数解析:
    保存文件图像。参数filename表示写入文件的格式及文件扩展名;img表示待写入图像源;params表示文件格式的一些细节信息,参数里面的数值跟文件格式有关,其中JPEG表示图像的质量,取值范围从0到100; PNG表示压缩级别,取值范围是从0到9;PPM、PGM或PBM表示文件是以二进制还是纯文本方式存储,取值为0或1.
    在应用以上函数进行文件相关操作时需要注意,Mat对象操作对某一函数有其特定格式要求,例如文件保存是支持8位单通道还是3通道BRG矩阵。对于16U格式图像文件,只能采用PNG、JPEG2000或TIFF格式,如果图像文件的格式、深度或通道顺序不符合要求时,可利用OpenCV提供的Mat::convertTo()、cvtColor()等相关函数进行转换。

像素值的存储方法


    存储像素值需要指定颜色空间和数据类型。其中,颜色空间是指针对一个给定的颜色,如何组合颜色元素已对其编码。不论哪种方式都是把颜色分成三个或者四个基元素,通过组合基元素可以产生所有的颜色。RGB颜色空间是最常用的一种颜色空间,这归功于它也是人眼内部构成颜色的方式。它的基色是红色、绿色和蓝色,有时为了表示透明颜色也会加入第四个元素alpha(A)
    颜色系统有很多,它们各有优势,具体如下:

  •     RGB 是最常见的,这是因为人眼采用相似的工作机制,它也被显示设备所采用
  •     HSV和HLS把颜色分解成色调、饱和度和亮度/明度,这是描述颜色更自然的方式,比如可以通过抛弃最后一个元素,使算法对输入图像的光照条件不敏感。
  •     YCrCb在JPEG图像格式中广泛使用
  •     CIE L*a*b是一种在感知上均匀的颜色空间,它适合用来度量两个颜色之间的距离。

    每个组成元素都有其自己的定义域,而定义域取决于其数据类型,如何存储一个元素决定了我们在其定义域上能够控制的精度。最小的数据类型是char,占一个字节或者8位,可以是由符号型(0到255之间)或无符号型(-127 到 +127)。尽管使用三个char型元素已经表示1600万种可能的颜色(使用RGB颜色空间),但若使用float(4字节,32位)或double(8字节,64位)则能给出更加精细的颜色分辨能力。但同时也要切记,增加元素的尺寸也会增加图像所占的内存空间。

猜你喜欢

转载自blog.csdn.net/qq_37385181/article/details/81772535