贴上一段很简单的测试代码
int main() { Mat a(100,100,CV_8UC3,Scalar(366,366,366)); MatIterator_<Vec3b> it = a.begin<Vec3b>(); cout << int((*it)[0]) << endl; imshow("a",a); Mat b(100,100,CV_32FC3,Scalar(366,366,366)); MatIterator_<Vec3f> itc = b.begin<Vec3f>(); cout << (*itc)[0] << endl; imshow("b",b); waitKey(0); return 0; } 输出结果如下图:
这段代码能够说明一些问题,即图片a中的CV_8UC3指的就是Mat里面的类型是uchar类型的,并且通道数是3,当我们用Scalar(366,366,366)给其赋值,输出他的B通道像素值还是255,这是由于uchar类型的范围就是在[0,255]之间决定的。
而图片b中的CV_32FC3指的就是Mat里面的类型是float类型的,并且通道数是3,当我们用Scalar(366,366,366)给其赋值,输出的B通道的像素值就是我们所赋的366,因为float类型的范围远大于366,是可以输出的,原因是一个float所占的内存也要比uchar多,uchar是一个字节,float是4个字节,所以其能表示的范围也更大。
在三通道的时候,我们用MatIterator迭代器或者Mat.at<T>方法访问像素的时候,需要根据Mat类型来选取相应的模板类型。还是以上述代码为例,当我们的Mat类型是CV_8UC3的时候,我们就要用Vec3b,而当时CV_8UC1的时候,我们直接就用uchar来访问,有人可能会有疑惑为什么依照Vec3b的规律用Vec1b来访问,事实上我们可以查看到Vec3b的定义如下:
typedef Vec<uchar, 2> Vec2b; typedef Vec<uchar, 3> Vec3b; typedef Vec<uchar, 4> Vec4b; 你会发现根本没有Vec1b这一说,为什么呢?当时CV_8UC3的时候表示是3个通道每个通道是uchar类型的,而当时CV_8UC1的时候,表示一个通道,其类型是uchar,既然如此,都一个通道了,直接用uchar访问不就好了?还用得着Vec1b吗?当然以后可能opencv也会提供这样的访问方式,但本质上还是一个uchar。同理可得,可看Vec3f的定义:
typedef Vec<float, 2> Vec2f; typedef Vec<float, 3> Vec3f; typedef Vec<float, 4> Vec4f; typedef Vec<float, 6> Vec6f; 同样还是没有Vec1f,原因同上,对类型为CV_32FC1访问的时候用float做模板类型即可访问,例 Mat c(100,100,CV_32FC1,Scalar(366)); MatIterator_<float> itc; 写了以上这些,希望对大家能有一些帮助,最后总结下就是用迭代器或者at方法访问图片像素的时候,一定要根据Mat图片的数据类型(uchar,int,float,double)以及通道数 (1,2,3...)来决定,否则会出现一些因为数据类型不对而难以检查出来的bug。