Mat类型中的CV_8UC3、CV_32FC3以及对应的迭代器模板参数Vec3b,Vec3f的一点自己的理解

来源:互联网 发布:分时量比曲线源码 编辑:程序博客网 时间:2024/06/10 01:56

贴上一段很简单的测试代码

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。

0 1