Opencv Mat详解

Opencv Mat详解

本文采用知识共享署名 4.0 国际许可协议进行许可,转载时请注明原文链接,图片在使用时请保留全部内容,可适当缩放并在引用处附上图片所在的文章链接。

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就是用来保存多维的矩阵的。

成员变量

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

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

  • rows: 矩阵的行数

  • cols: 矩阵的列数

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

  • channels: 矩阵元素拥有的通道数,例如常见的彩色图像,每一个像素由BGR三部分组成,则channels = 3。

  • type: 表示了矩阵中元素的类型以及矩阵的通道个数,它是一系列的预定义的常量,其命名规则为CV_(位数)+(数据类型)+(通道数)。这里U(unsigned integer)表示的是无符号整数,S(signed integer)是有符号整数,F(float)是浮点数。

例如:CV_16UC2,表示的是元素类型是一个16位的无符号整数,通道为2. C1,C2,C3,C4则表示通道是1,2,3,4。type一般是在创建Mat对象时设定,如果要取得Mat的元素类型,则无需使用type,使用下面的depth

在这里插入图片描述

  • depth :矩阵中元素的一个通道的数据类型,这个值和type是相关的。

例如 type为 CV_16SC2,一个2通道的16位的有符号整数。那么,depth则是CV_16S。depth也是一系列的预定义值,将type的预定义值去掉通道信息就是depth值:CV_8U CV_8S CV_16U CV_16S CV_32S CV_32F CV_64F

  • elemSize :矩阵一个元素占用的字节数,例如:type是CV_16SC3,那么elemSize = 3 * 16 / 8 = 6 bytes

  • elemSize1:矩阵元素一个通道占用的字节数,例如:type是CV_16CS3,那么elemSize1 = 16 / 8 = 2 bytes = elemSize / channels

Mat 通道理解

通道

一个图像的通道数是N,就表明每个像素点处有N个数,一个a×b的N通道图像,其图像矩阵实际上是b行N×a列的数字矩阵。

OpenCV中图像的通道可以是1、2、3和4。其中常见的是1通道和3通道,2通道和4通道不常见。

1通道的是灰度图。
3通道的是彩色图像,比如RGB图像。
4通道的图像是RGBA,是RGB加上一个A通道,也叫alpha通道,表示透明度。PNG图像是一种典型的4通道图像。alpha通道可以赋值0到1,或者0到255,表示透明到不透明。
2通道的图像是RGB555和RGB565。2通道图在程序处理中会用到,如傅里叶变换,可能会用到,一个通道为实数,一个通道为虚数,主要是编程方便。RGB555是16位的,2个字节,5+6+5,第一字节的前5位是R,后三位+第二字节是G,第二字节后5位是B,可见对原图像进行压缩了。

图像类型的转换与显示

Mat image=imread("../images/RGB.jpg");  
Mat imageGRAY,imageRGBA,imageRGB555;
cvtColor(image,imageGRAY,CV_RGB2GRAY);            //RGB转GRAY
cvtColor(image,imageRGBA,CV_RGB2BGRA);            //RGB转RGBA
cvtColor(image,imageRGB555,CV_RGB2BGR555);        //RGB转RGB555

//来看看通道数
int n = image.channels();                        //n=3
int nGRAY = imageGRAY.channels();                //nGRAY = 1
int nRGBA = imageRGBA.channels();                //nRGBA = 4
int nRGB555 = imageRGB555.channels();            //nRGB555 = 2

cout << "n: " << n << "  nGRAY: " << nGRAY << "  nRGBA: " << nRGBA << "  nRGB555: " << nRGB555 << endl;

//显示GRAY、RGB和RGBA图像
imshow("image",image);
imshow("imageGRAY",imageGRAY);
imshow("imageRGBA",imageRGBA);
//imshow("imageRGB555",imageRGB555);             //无法显示

在这里插入图片描述

RGB转GRAY是根据一个心理学公式来的:Gray = R0.299 + G0.587 + B*0.114

RGB转GRBA,默认A通道的数值是255,也就是不透明的。

通道的合成与分解

分解

C++: void split(const Mat& mtx, Mat* mv)
C++: void split(const Mat& mtx, vector<Mat>& mv)

参数:mtx 输入矩阵
mv 输出矩阵或矩阵数组
src 输入矩阵
dst0、dst1、dst2、dst3 最多4个单通道的输出矩阵

void Mat_split(void)
{
     Mat rgb(3, 4, CV_8UC3, Scalar(1, 2, 3, 4)); //这里 由于类型是 CV_8UC3 Scalar 第四个值没有用

     vector<Mat> channels;
     split(rgb, channels);
     Mat R = channels.at(0); //从vector中读数据用vector::at()
     Mat G = channels.at(1);
     Mat B = channels.at(2);

     cout << "RGB=" << endl
          << rgb << endl;

     cout << "R=" << endl
          << R << endl;

     cout << "G=" << endl
          << G << endl;

     cout << "B=" << endl
          << B << endl;
}
RGB=
[  1,   2,   3,   1,   2,   3,   1,   2,   3,   1,   2,   3;
   1,   2,   3,   1,   2,   3,   1,   2,   3,   1,   2,   3;
   1,   2,   3,   1,   2,   3,   1,   2,   3,   1,   2,   3]
R=
[  1,   1,   1,   1;
   1,   1,   1,   1;
   1,   1,   1,   1]
G=
[  2,   2,   2,   2;
   2,   2,   2,   2;
   2,   2,   2,   2]
B=
[  3,   3,   3,   3;
   3,   3,   3,   3;
   3,   3,   3,   3]

合成

C++: void merge(const Mat* mv, size_t count, OutputArray dst)
C++: void merge(const vector<Mat>& mv, OutputArray dst)

参数:mv 输入矩阵
count 当mv是C形式的array时,count表示输入矩阵个数
dst 输出矩阵
src0、src1、src2、src3 最多4个单通道的输入矩阵

void Mat_merge(void)
{
     Mat R(3, 4, CV_8UC1, Scalar(3));
     Mat G(3, 4, CV_8UC1, Scalar(2));
     Mat B(3, 4, CV_8UC1, Scalar(1));
     Mat RGB(3, 4, CV_8UC3);
     vector<Mat> src;
     src.push_back(R); //往vector里存数据要用vector::push_back()
     src.push_back(G);
     src.push_back(B);
     merge(src, RGB);

     cout << "R=" << endl
          << R << endl;

     cout << "G=" << endl
          << G << endl;

     cout << "B=" << endl
          << B << endl;

     cout << "RGB=" << endl
          << RGB << endl;
}
R=
[  3,   3,   3,   3;
   3,   3,   3,   3;
   3,   3,   3,   3]
G=
[  2,   2,   2,   2;
   2,   2,   2,   2;
   2,   2,   2,   2]
B=
[  1,   1,   1,   1;
   1,   1,   1,   1;
   1,   1,   1,   1]
RGB=
[  3,   2,   1,   3,   2,   1,   3,   2,   1,   3,   2,   1;
   3,   2,   1,   3,   2,   1,   3,   2,   1,   3,   2,   1;
   3,   2,   1,   3,   2,   1,   3,   2,   1,   3,   2,   1]

split( )和merge( )都是mixChannels( )的特例

C++: void mixChannels(const Mat* src, int nsrc, Mat* dst, int ndst, const int* fromTo, size_t npairs)
C++: void mixChannels(const vector<Mat>& src, vector<Mat>& dst, const int* fromTo, int npairs)

参数:src 输入的矩阵,可以是一个矩阵也可以是多个矩阵构成的vector
nsrc 输入矩阵的个数
dst 输出矩阵,可以是一个矩阵也可以是多个矩阵构成的vector
ndst 输出矩阵的个数
fromTo src到dst通道对应数组
npairs fromTo中有几组对应关系

mixChannels( )本质是改变了几个通道的顺序,输入一共有几个通道,输出肯定也有几个通道,所以定义fromTo时,要知道有多少个通道,而且通道的编号一定是0,1,2,…

void Mat_mixchannels(void)
{
     Mat RGB(3, 4, CV_8UC3, Scalar(1, 2, 3, 4));
     Mat A(3, 4, CV_8UC1, Scalar(6));
     cout << "RGB=" << endl
          << RGB << endl;
     cout << "A=" << endl
          << A << endl;

     //RGB+A合成为RGBA
     cout << "RGB+A合成为RGBA" << endl;
     Mat RGBA(3, 4, CV_8UC4);
     Mat in[] = {RGB, A};
     int fromTo1[] = {0, 0, 1, 1, 2, 2, 3, 3};
     mixChannels(in, 2, &RGBA, 1, fromTo1, 4);
     cout << "RGBA=" << endl
          << RGBA << endl;

     //RGB分解为R+GB
     cout << "RGB分解为R+GB" << endl;
     Mat R(3, 4, CV_8UC1);
     Mat GB(3, 4, CV_8UC2);
     Mat out[] = {R, GB};
     int fromTo2[] = {0, 2, 1, 1, 2, 0};
     mixChannels(&RGB, 1, out, 2, fromTo2, 3);
     cout << "R=" << endl
          << R << endl;
     cout << "GB=" << endl
          << GB << endl;
}
RGB=
[  1,   2,   3,   1,   2,   3,   1,   2,   3,   1,   2,   3;
   1,   2,   3,   1,   2,   3,   1,   2,   3,   1,   2,   3;
   1,   2,   3,   1,   2,   3,   1,   2,   3,   1,   2,   3]
A=![在这里插入图片描述](https://img-blog.csdnimg.cn/20210709123948440.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTE1NTkwNDY=,size_16,color_FFFFFF,t_70)

[  6,   6,   6,   6;
   6,   6,   6,   6;
   6,   6,   6,   6]
RGB+A合成为RGBA
RGBA=
[  1,   2,   3,   6,   1,   2,   3,   6,   1,   2,   3,   6,   1,   2,   3,   6;
   1,   2,   3,   6,   1,   2,   3,   6,   1,   2,   3,   6,   1,   2,   3,   6;
   1,   2,   3,   6,   1,   2,   3,   6,   1,   2,   3,   6,   1,   2,   3,   6]
RGB分解为R+GB
R=
[  3,   3,   3,   3;
   3,   3,   3,   3;
   3,   3,   3,   3]
GB=
[  2,   1,   2,   1,   2,   1,   2,   1;
   2,   1,   2,   1,   2,   1,   2,   1;
   2,   1,   2,   1,   2,   1,   2,   1]

创建一个Mat

void Mat_demo()
{
    cv::Mat M(2, 2, CV_8UC3, Scalar(0, 0, 255));
    cout << M << endl;

    cv::Mat Z = cv::Mat::zeros(3, 3, CV_64F);
    cout << Z << endl;

    cv::Mat F = cv::Mat::ones(2, 2, CV_64F);
    cout << F << endl;

    cv::Mat M0(1,2,CV_8UC3);
    cout << M0 << endl;

    float K[3][3] = {1, 0, 1, 0, 1, 1, 0, 0, 1};
    cv::Mat M1 = cv::Mat(3,3,CV_32FC1,K);
    cout << M1 << endl;

    cv::Mat M2 = (cv::Mat_<float>(3,3) << 0,-1,0,-1,5,-1,0,-1,0);
    cout << M2 << endl;

    cv::Mat M3 = (Mat_<double>(3, 3) << 0, 1, 2, 1, 2, 3, 2, 3, 4);
    cout << M3 << endl;
}

Scalar

Scalar是一个由长度为4的数组作为元素构成的结构体,Scalar最多可以存储四个值,没有提供的值默认是0。

  typedef struct Scalar
  {
      double val[4];
 }Scalar;
// 创建一个2通道,且每个通道的值都为(1,3),深度为32,4行4列的图像矩阵。
Mat M(4, 4, CV_32FC2, Scalar(1, 3));

/*
[1, 3, 1, 3, 1, 3, 1, 3;
 1, 3, 1, 3, 1, 3, 1, 3;
 1, 3, 1, 3, 1, 3, 1, 3;
 1, 3, 1, 3, 1, 3, 1, 3]
 */
// 创建一个3通道,且每个通道的值都为(1,2,3),深度为32,4行4列的图像矩阵。
Mat M(4, 4, CV_32FC3, Scalar(1, 2, 3));

/*
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3;
 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3;
 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3;
 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
*/
// 创建一个4通道,且每个通道的值都为(1,2,3,0)(默认为0),深度为32,4行4列的图像矩阵。
Mat M(4, 4, CV_32FC4, Scalar(1, 2, 3));

/*
[1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0;
 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0;
 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0;
 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0]
*/
Mat blue_m(256, 256, CV_8UC3, Scalar(255, 0, 0));
//cout<<blue_m<<endl;
Mat green_m(256, 256, CV_8UC3, Scalar(0, 255, 0));
//cout<<green_m<<endl;
Mat red_m(256, 256, CV_8UC3, Scalar(0, 0, 255));
//cout<<red_m<<endl;
Mat previewImg(256, 256, CV_8UC3);
//CV_EXPORTS void hconcat(InputArray src1, InputArray src2, OutputArray dst);
hconcat(blue_m, green_m, previewImg);
hconcat(previewImg, red_m, previewImg);
imshow("previewImg", previewImg);
waitKey(0);

在这里插入图片描述

cv::Mat::ones

Mat m = Mat::ones(2, 2, CV_8UC3); 相当于:Mat m = Mat(2, 2, CV_8UC3, 1);

// OpenCV replaces 1 with Scalar(1,0,0)相当于每个像素的第一个通道为1,其余两个通道为0;

cv::Mat F = cv::Mat::ones(3, 3, CV_64F);
cout << F << endl;
/*
[1, 1, 1;
 1, 1, 1;
 1, 1, 1]
*/

cv::Mat::zeros

Mat m = Mat::zeros(2, 2, CV_8UC3);
//相当于创建一张黑色的图,每个像素的每个通道都为0,Scalar(0,0,0)

cv::Mat Z = cv::Mat::zeros(3, 3, CV_64F);
cout << Z << endl;
/*
[0, 0, 0;
 0, 0, 0;
 0, 0, 0]
*/

cv::Mat::eye

cv::Mat Y = cv::Mat::eye(3, 3, CV_64F);
cout << Y << endl;
/*
[1, 0, 0;
 0, 1, 0;
 0, 0, 1]
*/

Mat类中数据部分组成

  • 矩阵头:包括矩阵尺寸、存储方法、存储地址等。
  • 指针:该指针指向存储所有像素值的矩阵。
    因为图片的数据量比较大,所以OpenCV中的Mat定义都是只申请了矩阵头和指针,尽量避免对指针指向的内容进行拷贝操作。
void Mat_demo1()
{
    Mat A, C; // Identify header only
    cout << "sizeof(A): " << sizeof(A) << "; sizeof(C): " << sizeof(C) << endl;
    cout << "A:\n"
         << A << endl;
    A = Mat::ones(Size(3, 3), CV_8UC1);
    C = A;
    cout << "sizeof(A): " << sizeof(A) << "; sizeof(C): " << sizeof(C) << endl;
    cout << "A:\n"
         << A << endl;

    Mat B(A);
    cout << "B:\n"
         << B << endl;
    B.at<uchar>(1, 1) = 255;
    cout << "C:\n"
         << C << endl;

    Mat D = A.clone();
    cout << "D:\n"
         << D << endl;
    D.at<uchar>(0, 0) = 123;
    cout << "A:\n"
         << A << endl;
    cout << "D:\n"
         << D << endl;

    Mat E;
    A.copyTo(E);
    cout << "E:\n"
         << E << endl;
    E.at<uchar>(2, 2) = 100;
    cout << "A:\n"
         << A << endl;
    cout << "E:\n"
         << E << endl;
}

Mat类型的变量定义以及赋值分为:

  • 公用一个数据块
=
构造函数
  • 不公用一个数据块
clone
copyto

参考

OpenCV CV_RGB2GRAY与CV_BGR2GRAY的区别

学习OpenCV2——Mat之通道的理解

  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
OpenCV中,Mat是一个非常重要的类,它用于表示图像或矩阵数据。可以使用不同的方法来创建Mat对象。其中一种方法是使用构造函数,如Mat img(100,100,CV_8UC3, Scalar(255,255,255)),这会创建一个大小为100x100的3通道图像,像素值为(255,255,255)。另一种方法是使用create()函数,如img.create(100,100, CV_8UC3),这也会创建一个大小为100x100的3通道图像。此外,还可以使用zeros()、eye()和ones()函数来创建全零矩阵、对角为1的对角矩阵和全1矩阵。还可以使用逗号数组的方式来创建对象,如Mat img = (Mat_<double>(2,2) << 0,1,1,0)。这种方式按行填充数据。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [opencv mat介绍](https://download.csdn.net/download/cockcomputer/10833601)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [OpenCVMat的详细介绍](https://blog.csdn.net/PRML_MAN/article/details/124482661)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [openCV学习(一)——Mat详解](https://blog.csdn.net/lvyaer_1122/article/details/124454244)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

002237

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值