OpenCV的Mat类用于获取图像信息的常用属性与方法

前言:Mat是OpenCV的最基本的类型,他有很多常见的属性和方法,可以获取这张图片的基本信息,帮助我们更好地理解图片,本文做了一个简单的小结,并说明了一些常见的易错点。

一、Mat对象常见的属性以及方法一览

cout << image.cols << endl;         //相片的列数,一共有多少列,对应width
cout << image.rows << endl;         //相片的行数,一共有多少行,对应height
cout << image.dims << endl;         //相片的维度,这里都是二维

cout << image.type() << endl;       //16,其实是CV_8U3,即8位无符号三通道
cout << image.total() << endl;      //156500  总共有多少个元素,即rows*cols
cout << image.channels() << endl;   //相片的通道数,可能是1、3、4
	
//几个需要特别注意的方法,在下面一个一个说明
cout << image.step << endl;         //1500
cout << image.step1() << endl;      //1500
cout << image.elemSize() << endl;   //3
cout << image.elemSize1() << endl;  //1

	cout << typeid(image.data).name() << endl;

1、type()方法

该方法返回的是一个int类型的整数,表示的是每一个像素(i,j)的数据类型,常见的比如:

  • CV_8U:8位单通道无符号,即灰度图像,返回的是0
  • CV_8UC3:8位三通道无符号,即常见的RGB图像,返回的是16
  • CV_32FC3:32位浮点数三通道,返回的是21
  • 等等

2、elemSize1()方法

每一个像素位置(i,j)处单个通道所占用的字节数,是以字节byte为单位的。

  • CV_8U:8位单通道无符号,即灰度图像,只有一个通道,它为1byte
  • CV_8UC3:8位三通道无符号,即常见的RGB图像,每一个通道是8bit,依然为1byte
  • CV_32FC3:32位浮点数三通道,每一个通道是32位,所以为4byte
  • 等等

3、elemSize()方法

每一个像素位置(i,j)处所有通道所占用的字节数,是以字节byte为单位的。

  • CV_8U:8位单通道无符号,即灰度图像,只有一个通道,它为1byte
  • CV_8UC3:8位三通道无符号,即常见的RGB图像,每一个通道是8bit,有三个通道,所以为3byte
  • CV_32FC3:32位浮点数三通道,每一个通道是32位,即4byte,一共有三个通道所以是 12byte
  • 等等

注意:elemSize() 和elemSize1()的区别。

4、step属性

这个属性表示的是图片每一行的字节数,一字节byte为单位,

  • 单通道8位灰度图:由于每一个像素只有一个通道,且为8位,即1字节,所以 step=1*cols;
  • 三通道8位RGB图:由于每一个像素包含三个通道,每一个通道为1字节,所以一个像素占3字节,所以step=3*cols;
  • 对于三通道32位浮点数:即上面的CV_32FC3,每一个像素有三个通道,每一个通道占用32位即4字节,所以每一个像素占用3*4字节,所以step=3*4*cols。

5、step1()方法

这个是最容易出错的,step1()=step/elemSize1()

 

二、Mat类的元素高效遍历方法

Mat类的元素便利有很多的方法,但是油的方法比较慢,这里提供一种高校的元素遍历方法,即通过image.data指针来实现。

2.1 data指针到底是什么意思

需要特别注意的是,

  • data指针指向的是Mat的首元素的指针,即位置(0,0)处的指针,它是将每一个像素点当成一个一维数组,然后指向这个数组的首元素,如果是单通道,则这个一位数组只有一个元素,如果是三通道,则这个一维数组是三个元素;
  • 而且无论图像是什么类型,他总是返回的是unsigned char * 指针类型,即uchar类型,所以需要注意类型转换。

(1)对于单通道灰度图

//8位单通道,每个像素仅仅占用 1 byte
for (int i = 0; i < rows; i++)
{
    uchar * pixel = a.data + i * a.step;  //将指针移动到每一行的开始
	for (int j = 0; j < 5; j++)
	{
		cout << pixel[0] << endl;  //单通道只有一个元素
        pixel+=1;   //将指针移动到下一列
	}
	cout << endl;
}

(2)对于三通道RGB图像

//8位单通道,每个像素仅仅占用 1 byte
for (int i = 0; i < rows; i++)
{
    uchar * pixel = a.data + i * a.step;  //将指针移动到每一行的开始
	for (int j = 0; j < 5; j++)
	{
		cout << pixel[0] << endl;  //三通道第一个元素
        cout << pixel[1] << endl;  //三通道第二个元素
        cout << pixel[2] << endl;  //三通道第三个元素

        pixel+=3;   //将指针移动到下一列的首元素
	}
	cout << endl;
}

(3)对于三通道32位浮点数,即CV_32FC3

//8位单通道,每个像素仅仅占用 1 byte
for (int i = 0; i < rows; i++)
{
    float * pixel = (float *)a.data + i * a.step/4;  //将指针移动到每一行的开始需要转换,为什么需要除以4,一定要弄清楚它的本质
	for (int j = 0; j < 5; j++)
	{
		cout << pixel[0] << endl;  //三通道第一个元素
        cout << pixel[1] << endl;  //三通道第二个元素
        cout << pixel[2] << endl;  //三通道第三个元素

        pixel+=3;   //将指针移动到下一列的首元素
	}
	cout << endl;
}

两个需要注意的点:

(1)第一:什么时候需要除以一个数,这取决于每一个像素的每一个通道占用几个字节

 float * pixel = (float *)a.data + i * a.step/4; 

(2)第二:什么时候加1,什么时候加3,这取决于相片的通道数目

pixel+=3; 

 

 

 

 

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值