2013-03-06 132 views
31

我很困惑OpenCV Mat元素类型。这是从文档: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?

+2

类型在OpenCV中是很容易理解。 CV_numbitsType。所以CV_16S是一个16位长的有符号整数。 – 2013-03-06 11:03:23

+0

那么为什么他们在文档(int,float等)中为它们使用这样的名称,而(例如)int可以是64位而不是32位? – lizarisk 2013-03-06 11:14:35

+2

我真的不知道底层结构,但是当您使用类型CV_32S创建一个垫子时: 'Mat myMat(10,10,CV_32S);' 您可以用 'myMat.at (1,1) = 1;' – sfotiadis 2013-03-06 11:20:49

回答

-3

总之你提供的表是正确的。 如果你想直接访问一个像素,你可以将它转换为右侧的说明符,例如CV_32S是一个有符号的32位。 S始终表示有符号整数(有符号字符,有符号短符号,有符号整数) F总是表示浮点数(float,double) U总是表示无符号整数。

枚举仅在创建或转换Mat时使用。这是告诉席子是否是所需类型的一种方式,因为我知道它是不使用模板时的C前任。

我使用C功能完全,并且为了创建一个图像,这将是一个错误通过如下:

cvCreateImage(mySize,char, nChannels); 

相反,我通过了以下内容:

cvCreateImage(mySize, IPL_DEPTH_8U, nChannels); 

这里,IPL_DEPTH_8U是该函数使用的标志。该函数本身具有检查标志的开关式语句。标志的实际值通常是毫无意义的,因为它通常由条件而不是代数语句来控制。

+0

这是无关紧要的。问题在于opencv2,答案与opencv1 – mkuse 2014-02-16 14:53:50

2

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_32S是该类型int,不int32_t值。

0

我在OpenCV的CV_8UC1,CV_32SC1等相关代码中发现了几个#define。为了使枚举工作,OpenCV将附加代码转换为一个参数的简单数字(即CV_8UC1,CV_16UC2 ...所有代表都由它们各自的数字表示),并在CvMat的定义中突破深度和通道(我猜,Mat在其定义中可能有类似的代码)。然后,它使用create()为矩阵分配空间。由于create()是内联的,我只能猜测它与malloc()或类似。
随着源代码从2.4.9改变到3.0.0,我需要稍后发布更多的证据。请让我花一点时间来了解更多信息并编辑我的答案。

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)) 

or

CV_DbgAssert(4 == sizeof(int)) 

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

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

+0

有关。m.depth()不是以字节为单位,而是为类型提供EV枚举值。 CV_8U。 – karsten 2017-09-27 15:43:14

+0

改为使用elemSize1()。请注意,elemSize()== elemSize1()*通道() – karsten 2017-09-27 15:43:26

4

Miki's answer发展,
在OpenCV的3定义已经转移到模块/核心/包括/ opencv2 /核心/ 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_8Uuint8_tCV_8Uint8_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 
+0

伟大的答案谢谢..在大多数情况下,OpenCV不遵循C++诽谤。虽然它是一个梦幻般的计算机视觉库,但我讨厌在C++中处理它。它总是刹车我的代码,并使我写代码,我觉得他们感到羞耻。 – 2016-05-27 13:47:40

+0

你如何访问value_type?你的例子在OpenCV 3.0中不适用于我,因为它是一个成员而不是公共的。 – John 2016-10-21 18:40:24

+0

@John:是的,只需将“class”替换为“struct”即可。用我的OpenCV 2.4.5版本没有hader,我不得不手动将代码添加到我的源代码中。 请注意Mat :: elemSize1()方法,它也显示了存储在Mat中的一个数字的字节大小。 – karsten 2017-09-27 15:59:23