1 CV_8U
、CV_8UC3
的含义
在定义Mat对象的时候,像素的数据类型经常使用CV_8U
、CV_8UC3
来表示,例如:
/** @overload
@param rows Number of rows in a 2D array.
@param cols Number of columns in a 2D array.
@param type Array type. Use CV_8UC1, ..., CV_64FC4 to create 1-4 channel matrices, or
CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices.
*/
//Mat(int rows, int cols, int type);
Mat img(3, 3, CV_8U);
它们都是宏常量,OpenCV的源码中,将像素的数据类型进行了编号,而构造函数根据传入的type值(类型编号)确定像素的具体类型,例如0就代表unsigned char
,这里用0、1、2 这些太过突兀,为了使其含义更清晰,所以使用了宏,例如:
/*
#define CV_8U 0
#define CV_8S 1
#define CV_16U 2
#define CV_16S 3
#define CV_32S 4
#define CV_32F 5
#define CV_64F 6
#define CV_16F 7
*/
像素的数据类型与C++中基本数据类型的对应的关系如下:
有些图像是多通道,那么一个像素实际上是包含了多个数,Mat类中把这多个数当成一个“像素”处理(只是这个像素比较“长”而已),并且为其声明了类型,即CV_8UC2、CV_8UC3、CV_8UC4、CV_8SC2、CV_8SC3
等,它们的组成形式为:cv_<bit_depth>(S|U|F)C<number_of_channels>
,即在单通道类型的基础上加上了一个C和数字,1表示1个通道,2表示2个通道,最多能表示4个通道。
多于4个通道时(例如5个通道),则使用宏函数,例如CV_8UC(5)
,宏函数最多只能表示512个通道
关于多个通道的宏与常数的对应关系如下表所示:(如果CV_8SC2,查表时则是查CV_8S所在行和C2所在列)
例如:
printf("CV_8U: %d\n", CV_8U);
printf("CV_8UC1: %d\n", CV_8UC1);
printf("CV_8UC3: %d\n", CV_8UC3);
输出
CV_8U: 0
CV_8UC1: 0
CV_8UC3: 16
可以看到CV_8UC1
和CV_8U
没差。
2 利用at访问矩阵中的元素时,必须指定数据类型
at虽然是Mat类的成员函数,但它确实模板函数,它使用时必须指定类型,而CV_8U
、CV_8UC3
等,它们是宏,而不是类型,不能用到模板中。
若图像为单通道,模板中的类型列表应该用基本数据类型,对于多通道,则应该使用opencv源码中定义的向量类型(稍后会介绍)
//单通道
Mat img(3, 3, CV_8U);
cout << (int)img.at<uchar>(0, 1) << endl; //访问第0行第1列的元素
//多通道
Mat img2(3, 3, CV_8UC2);
Vec2b v2b = img.at<Vec2b>(0, 1);
cout << v2b << endl; //访问第0行第1列的像素,这是一个二维向量
cout << (int)v2b[0] << endl;
输出
205
[205, 205]
205
这里出现了Vec2b,它其实是与CV_8UC2相匹配的向量类型,使用at访问像素时,向量的类型必须和像素类型严格匹配
opencv中的像素类型声明宏与向量类型的对应关系如下: