OpenCV Mat元素类型及其大小

时间:2013-03-06 10:49:57

标签: opencv

我对OpenCV Mat元素类型感到困惑。这来自文档:

There is a limited fixed set of primitive data types the library can operate on.
That is, array elements should have one of the following types:

8-bit unsigned integer (uchar) 
8-bit signed integer (schar)
16-bit unsigned integer (ushort)
16-bit signed integer (short)
32-bit signed integer (int)
32-bit floating-point number (float)
64-bit floating-point number (double)
...

For these basic types, the following enumeration is applied:
enum { CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 };

众所周知,C ++标准没有以字节为单位定义基本类型的大小,那么他们如何使用这些假设呢?我应该期待什么类型,比方说CV_32S,是int32_t还是int?

6 个答案:

答案 0 :(得分:5)

Miki's answer发展,
在OpenCV 3中,定义已移至modules / core / include / opencv2 / core / traits.hpp ,您可以在其中找到:

/** @brief A helper class for cv::DataType

The class is specialized for each fundamental numerical data type supported by OpenCV. It provides
DataDepth<T>::value constant.
*/
template<typename _Tp> class DataDepth
{
public:
    enum
    {
        value = DataType<_Tp>::depth,
        fmt   = DataType<_Tp>::fmt
    };
};



template<int _depth> class TypeDepth
{
    enum { depth = CV_USRTYPE1 };
    typedef void value_type;
};

template<> class TypeDepth<CV_8U>
{
    enum { depth = CV_8U };
    typedef uchar value_type;
};

template<> class TypeDepth<CV_8S>
{
    enum { depth = CV_8S };
    typedef schar value_type;
};

template<> class TypeDepth<CV_16U>
{
    enum { depth = CV_16U };
    typedef ushort value_type;
};

template<> class TypeDepth<CV_16S>
{
    enum { depth = CV_16S };
    typedef short value_type;
};

template<> class TypeDepth<CV_32S>
{
    enum { depth = CV_32S };
    typedef int value_type;
};

template<> class TypeDepth<CV_32F>
{
    enum { depth = CV_32F };
    typedef float value_type;
};

template<> class TypeDepth<CV_64F>
{
    enum { depth = CV_64F };
    typedef double value_type;
};

大多数情况/编译器中,使用C ++精确数据类型应该没问题。您不会将单字节数据类型(CV_8U - &gt; uint8_tCV_8U - &gt; int8_t)作为unambiguously defined in C++出现问题。 float (32bit) and double (64bit)也是如此。但是,对于其他数据类型来说,确实使用正确的数据类型(例如使用at<>方法时),您应该使用例如:

typedef TypeDepth<CV_WHATEVER_YOU_USED_TO_CREATE_YOUR_MAT>::value_type access_type;
myMat.at<access_type>(y,x) = 0;

作为旁注,我很惊讶他们决定采用这种模棱两可的方法,而不是简单地使用确切的数据类型。

因此,关于你的上一个问题:

  

我应该期待什么类型,让我们说CV_32S

我相信OpenCV 3中最准确的答案是:

TypeDepth<CV_32S>::value_type

答案 1 :(得分:4)

core.hpp中,您可以找到以下内容:

/*!
  A helper class for cv::DataType

  The class is specialized for each fundamental numerical data type supported by OpenCV.
  It provides DataDepth<T>::value constant.
*/
template<typename _Tp> class DataDepth {};

template<> class DataDepth<bool> { public: enum { value = CV_8U, fmt=(int)'u' }; };
template<> class DataDepth<uchar> { public: enum { value = CV_8U, fmt=(int)'u' }; };
template<> class DataDepth<schar> { public: enum { value = CV_8S, fmt=(int)'c' }; };
template<> class DataDepth<char> { public: enum { value = CV_8S, fmt=(int)'c' }; };
template<> class DataDepth<ushort> { public: enum { value = CV_16U, fmt=(int)'w' }; };
template<> class DataDepth<short> { public: enum { value = CV_16S, fmt=(int)'s' }; };
template<> class DataDepth<int> { public: enum { value = CV_32S, fmt=(int)'i' }; };
// this is temporary solution to support 32-bit unsigned integers
template<> class DataDepth<unsigned> { public: enum { value = CV_32S, fmt=(int)'i' }; };
template<> class DataDepth<float> { public: enum { value = CV_32F, fmt=(int)'f' }; };
template<> class DataDepth<double> { public: enum { value = CV_64F, fmt=(int)'d' }; };
template<typename _Tp> class DataDepth<_Tp*> { public: enum { value = CV_USRTYPE1, fmt=(int)'r' }; };

您可以看到CV_32Sint类型的值,而不是int32_t

答案 2 :(得分:1)

虽然C ++没有定义元素的大小,但问题是假设:对于运行OpenCV的系统,大小是已知的。给定

cv::Mat m(32,32,CV_32SC1, cv:Scalar(0));
std::cout << "size of the element in bytes: " << m.depth() << std::endl;
std::cout << "or " << m.step.p[ m.dims-1 ]/m.channels() << std::endl;

那你怎么能确定它是int

试图打电话

int pxVal = m.at<int>(0,0);

CV_DbgAssert( elemSize()==sizeof(int) );

左手是通过cv::Mat::flags定义的 - 在此示例中,CV_32SC1的预定义深度等于

CV_DbgAssert( m.depth() == sizeof(int) )

CV_DbgAssert( 4 == sizeof(int) )

所以如果你成功了,你只剩下了字节序。当cvconfig.h生成时(CMake)检查了这一点。

TL; DR,期待标题中给出的类型,你会没事的。

答案 3 :(得分:0)

您可以在opencv的源代码中找到所有问题的定义。

请参阅https://github.com/Itseez/opencv/blob/master/modules/core/include/opencv2/core/cvdef.h文件。

答案 4 :(得分:0)

我在OpenCV的代码中找到了几个与CV_8UC1,CV_32SC1等相关的#define。为了使枚举有效,OpenCV添加了其他代码将普通数字作为参数转换(即CV_8UC1,CV_16UC2。 ..全部由它们各自的数字表示),并在CvMat的定义中打破深度和通道(我猜Mat在其定义中可能有类似的代码)。然后,它使用create()为矩阵分配空间。由于create()是内联的,我只能猜测它类似于malloc()或其他东西。
由于源代码从2.4.9变为3.0.0,我需要在以后发布更多证据。请允许我花一点时间了解更多内容并编辑我的答案。

答案 5 :(得分:-3)

简而言之,您提供的表格是正确的。 如果要直接访问像素,则将其类型化为右侧的说明符,例如CV_32S是带符号的32位。 S总是表示有符号整数(signed char,signed short,signed int) F总是表示浮点数(浮点数,双精度数) U总是表示无符号整数。

枚举仅在创建或转换Mat时使用。这是一种告诉mat是所需类型的方法,据我所知,它是不使用模板时的C前身。

我专门使用C功能,为了创建图像,传递以下内容是错误的:

cvCreateImage(mySize,char, nChannels);

相反,我传递了以下内容:

cvCreateImage(mySize, IPL_DEPTH_8U, nChannels);

这里,IPL_DEPTH_8U是函数使用的标志。函数本身有一个switch-type语句,用于检查标志。标志的实际价值通常是毫无意义的,因为它通常由条件语句而非代数语句控制。