OpenCV基础(1)--Mat简介

本文介绍了OpenCV中的Mat容器,包括其数据类型定义、通道设置,以及Mat类的构造方式、多种赋值方法、基本运算和元素读取,如at读取、ptr指针和迭代器的使用。
摘要由CSDN通过智能技术生成

1. Mat容器

数字图像在计算机中都是以矩阵的形式存储的,矩阵数据表示这图像的亮度,颜色等。OpenCV提供了Mat(矩阵matrix)来存储矩阵。Mat是一个类,也是1个容器。

1.1 Mat简介

由于图像对数据准确性要求较高,否则易失真。因此opencv的数据类型定义得比较详细,如下图所示。

仅有数据类型还不够,还得给图像来个通道。例如灰度图像处理是单通道数据,彩色图像数据是3或4通道数据。OpenCV给定义的通道标识为C1,C2,C3,C4,分别表示1通道,2通道,3通道,4通道。将数据类型和通道数结合得到OpenCV对图像的数据类型的完整定义:

例如CV_8UC1:表示8位无符号1通道数据,用于表示8位灰度图。CV_8UC3表示8位无符号整数3通道,用于表示8位彩色图。

Mat a(640,480,CV_8UC3)        // 创建640*480的3通道矩阵存放彩色图像
Mat a(3,3,CV_8UC1)

1.2 Mat类构造与赋值

1.2.1 Mat构造

有以下3种方式:

// 1. 默认构造函数
Mat::Mat()

// 2. 根据输入图像矩阵和类型构造,type: CV_8UC1等
Mat::Mat(int rows, int cols, int type)

// 3. 根据已有矩阵构造
Mat::Mat(const Mat & m)

1.2.2 Mat赋值

5种赋值方式:

// 1. 构造时赋值
Mat::Mat(2, 2, CV_8UC3, Scalar(0,0,255))  // 创建3通道,每个像素都是0,0,255

// 2. 枚举法赋值:创建2 * 2的图像矩阵
Mat a = (Mat_<int>(2, 2) << 1, 2, 3, 4);

// 3. for循环赋值
Mat c = Mat_<int>(2, 2);
for (int i = 0; i < c.rows; i++)
{
    for (int j = 0; j < c.rols; j++)
    {
        c.at<int>(i, j) = i+j;    // Mat是个容器,at是容器常用赋值类函数
    }
}

// 4. 类方法构造
Mat d = Mat::ones(3, 3, CV_8UC1);    // 1矩阵,3*3矩阵,元素都为1
Mat e = Mat::zeros(4, 2, CV_8UC3);    // 0矩阵,4*2矩阵,元素都为0

// 5. 数组赋值
float a[8] = {1, 2, 3, 4, 5, 6, 7, 8}
Mat b = Mat(2, 2, CV_32FC2, a)
Mat c = Mat(2, 4, CV_32FC1, a)

/*
此时会自由拆分赋值:
b 为 2*2 , 所以b = 
[1,2     3,4
5,6      7,8]
c 为 2*4, 所以c = 
[1    2    3    4
 5    6    7    8]
*/

1.3 Mat支持的运算

处理数据时,需要做加减乘除的运算,例如对图像滤波,增强等都需要对像素数据操作。opencv提供的Mat类在操作加减乘除时只需要像矩阵一样直接使用加减乘除符号即可,类似于MATLAB。

示例:

e = a + b;
f = c - d;
g = 2 * a;
h = d / 2.0
i = a - 1         // 表示a矩阵每个元素减去1
j = c * d        // 表示矩阵相乘,就是数学里的 m*n X n*l = m*l
k = a.dot(b)      // 内积或叫做点乘, 得到double类型的数, a,b 只能是行或列向量,个数相等。
m = a.mul(b)      // 乘积,是矩阵对应位置相乘,需要长一样的 m*n

1.4 Mat元素读取

Mat类矩阵在计算机中存储时是将三维数据变成二维数据,先存储第1个元素每个通道的数据,再存储第2个元素每个通道的数据。每一行都是这样存储。Mat 类自身有以下属性可以直接调用:

  1. cols:列数
  2. rows:行数
  3. step:矩阵宽度,单位为字节;
  4. elemSize():单个元素占的字节数;
  5. total:元素个数
  6. channels: 通道数

1.4.1 at读取

示例:

Mat b(3, 4, CV_8UC3, Scalar(0, 0, 1));     // 初始化时赋值3*4 矩阵,每个像素为(0,0,1)
Vec3b vc3 = b.at<Vec3b>(0, 0);             // 使用at索引(0,0)数据,按照uchar读取
int num1 = (int)vc3.val[0];                //  依次取第1,2, 3个值
int num2 = (int)vc3.val[1];
int num3 = (int)vc3.val[2];

1.4.2 ptr指针读取

Mat类的数据存放是紧挨着,内存地址连续,索引可以通过指针依次索引。

int main()
{
    Mat b(2, 3, CV_8UC3, Scalar(10, 20, 30));
    for (int i = 0; i < b.rows; i++)
    {
        uchar* ptr = b.ptr<uchar>(i);
        for (int j = 0; j < b.cols * b.channels(); j++)
        {
            cout << (int)ptr[j] << " ";
        }
        cout << endl;
    }
}

1.4.3 迭代器iterator读取

示例:

#include <opencv2/opencv.hpp>  
#include <opencv2/core/core.hpp>  
#include <iostream>  
using namespace std;
using namespace cv;
int main()
{
    Mat a = (cv::Mat_<uchar>(2, 2) << 1, 2, 3, 4);
    MatIterator_<uchar> it_begin = a.begin<uchar>();
    MatIterator_<uchar> it_end = a.end<uchar>();
    for (int i = 0; it_begin != it_end; it_begin++)
    {
        cout << (int)(*it_begin) << " ";
        // 每行结束换新行
        if ((++i % a.cols) == 0)
        {
            cout << endl;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值