我对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?
答案 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_t
和CV_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_32S
是int
类型的值,而不是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语句,用于检查标志。标志的实际价值通常是毫无意义的,因为它通常由条件语句而非代数语句控制。