基础图像容器Mat

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_39504764/article/details/100550620

一: Mat结构的使用

  • Mat类:
  1. 不必再手动为其开辟空间
  2. 不必再在不需要的时候立即将空间释放
  • Mat是一个图像容器类,这个数据结构由两部分组成:

    • 1–矩阵头–即class Mat类所实例化的类对象所开辟的空间里面存储的数据—就是这个矩阵的信息,当我们以 Mat object;这样声明类对象的时候,也仅仅是创建了一个Mat的信息头,并没有创建矩阵体,也就是说,我们并没有给将要存储的图像开辟相应的空间。
    • 2–矩阵头–包含:
      1–矩阵的尺寸:比如class Mat这个类中的数据成员rows,cols就可以指定图像的尺寸。
      2–存储方法:对应各种Mat的构造函数
      3–存储地址
      4–和一个指向存储所有像素值的矩阵的指针
  • OpenCV使用了计数机制:让每个Mat对象有自己的信息头,但共享同一个矩阵。这通过让矩阵指针指向同一地址而实现。拷贝构造函数只复制信息头和矩阵指针,而不复制矩阵。

  • 如果矩阵属于多个Mat对象,那么当不再需要它时,谁来负责清理呢?

最后一个使用它的对象。通过计数机制来实现。无论什么时候复制一个Mat对象的信息头,都会增加矩阵的引用次数。反之,当一个头被释放之后,这个计数被减一;当计数值为0,矩阵会被清理。

  • 复制矩阵本身(不只是信息头和矩阵指针),可以使用clone()或者copyTo()
#include <opencv2/opencv.hpp>
using namespace cv;

int main()
{
    Mat A,C; //仅创建信息头部分
    A = imread("1.jpg",CV_LOAD_IMAGE_COLOR); //为矩阵开辟内存
    Mat B(C); //拷贝构造函数
    C = A; //赋值运算符
    Mat D(A,Rect(10,10,100,100)); //使用矩阵界定
    Mat E = A(Range::all(),Range(1,3)); //用行和列来界定
    Mat F = A.clone();
    Mat G;
    A.copyTo(G); //改变F或者G就不会影响Mat信息头所指向的矩阵
}

总结:

  1. OpenCV函数中输出图像的内存分配是自动完成的(如果不特别指定的话)。
  2. 使用OpenCV的C++接口时不需要考虑内存释放问题。
  3. 赋值运算符和拷贝构造函数只复制信息头。
  4. 使用函数clone()或者copyTo()来复制一幅图像的矩阵。

二:像素值的存储方法

显式创建Mat对象的七种方法

1. 使用Mat()构造函数
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;

int main()
{
    Mat M(3,2,CV_8UC3,Scalar(0,0,255));
    /*
       3 行 2 列
       CV_[位数][带符号与否][类型前缀]C[通道数]
       CV_8UC3 : 表示使用8位的unsigned char型,每个像素由三个元素组成三通道
       Scalar : short类型的向量
     */
    cout << "M = " << endl << " " << M << endl << endl;
    return 0;
}

在这里插入图片描述

2. 在C/C++中通过构造函数进行初始化
//创建一个超过二维的矩阵;指定维数,然后传递一个指向一个数组的指针,这个数组包含每个维度的尺寸。
 int sz[3] = {2,2,2};
 Mat M(3,sz,CV_8UC3,Scalar::all(0));
3. 为已存在的IplImage指针创建信息头

针对直接用IplImage类型指针初始化Mat对象报错的解决办法: 查看

IplImage* img = cvLoadImage("1.jpg",1);
Mat mtx = cvarrToMat(img);
4. 利用Create()函数
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;

int main()
{
    Mat M;
    M.create(4, 4, CV_8UC(2));
    cout << "M = " << endl << " " << M << endl << endl;
    return 0;
}

在这里插入图片描述

5. 采用Matlab式的初始化方式
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;

int main()
{
    Mat M = Mat::eye(4,4,CV_64F);
    cout << "Z = " << endl << " " << Z << 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;
    return 0;
}

在这里插入图片描述

6. 对小矩阵使用逗号分隔式初始化函数
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;

int main()
{
    Mat C = (Mat_<double>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
    cout << "C = " << endl << " " << C << endl << endl;
    return 0;
}

在这里插入图片描述

7. 为已存在的对象创建新信息头
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;

int main()
{
    Mat C = (Mat_<double>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
    cout << "C = " << endl << " " << C << endl << endl;
    Mat RowClone = C.row(1).clone();
    cout << "RowClone = " << endl << " " << RowClone << endl << endl;
    return 0;
}

在这里插入图片描述

三:OpenCV中的格式化输出方法

1. OpenCV默认风格
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;

int main()
{
    Mat r = Mat(10, 3, CV_8UC3);
    randu(r, Scalar::all(0), Scalar::all(255));
    cout << "r(openCV默认风格) = "<< r <<";" <<endl <<endl;

    return 0;
}

在这里插入图片描述

2. Python风格
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;

int main()
{
    Mat r = Mat(10, 3, CV_8UC3);
    randu(r, Scalar::all(0), Scalar::all(255));
    cout << "r(Python风格) = "<< format(r,Formatter::FMT_PYTHON) <<";" <<endl <<endl;

    return 0;
}

在这里插入图片描述

3. 逗号分隔风格
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;

int main()
{
    Mat r = Mat(10, 3, CV_8UC3);
    randu(r, Scalar::all(0), Scalar::all(255));
    cout << "r(逗号分隔风格) = "<< format(r,Formatter::FMT_CSV) <<";" <<endl <<endl;

    return 0;
}

在这里插入图片描述

4. Numpy风格
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;

int main()
{
    Mat r = Mat(10, 3, CV_8UC3);
    randu(r, Scalar::all(0), Scalar::all(255));
    cout << "r(Numpy风格) = "<< format(r,Formatter::FMT_NUMPY) <<";" <<endl <<endl;

    return 0;
}

在这里插入图片描述

5. C语言风格
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;

int main()
{
    Mat r = Mat(10, 3, CV_8UC3);
    randu(r, Scalar::all(0), Scalar::all(255));
    cout << "r(C语言风格) = "<< format(r,Formatter::FMT_C) <<";" <<endl <<endl;

    return 0;
}

在这里插入图片描述

四:输出其他OpenCV常用结构

1. 定义和输出二维点
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;

int main()
{
    Point2f p(6.2,2);
    cout << p <<endl;
    return 0;
}

//[6.2, 2]
2. 定义和输出基于Mat的std::vector
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;

int main()
{
    vector<float> v;
    v.push_back(1.2);
    v.push_back(2.1);
    v.push_back(3);
    cout << "【基于Mat的vector】shortvec = \n" << Mat(v) << endl ;
    return 0;
}

在这里插入图片描述

3. 定义和输出std::vector点
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;

int main()
{
    vector<Point2f> points(20);
    for(int i = 0; i < points.size();i++)
    {
        points[i] = Point2f(i*5, i%7);
    }
    cout << "【二维点向量】points = \n" << points <<endl;
    return 0;
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_39504764/article/details/100550620