39

我对 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?

4

6 回答 6

7

根据Miki 的回答
在 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++ 精确数据类型应该没问题。您不会遇到C++ 中明确定义的CV_8U单字节数据类型( ->uint8_tCV_8U-> int8_t)的问题。float (32bit) 和 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
于 2016-05-27T13:36:38.737 回答
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是 type 的值int,而不是int32_t.

于 2015-09-19T03:01:08.280 回答
2

虽然 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,期待标题中给出的类型,你会没事的。

于 2016-02-04T23:51:52.230 回答
0

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

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

于 2014-07-01T06:21:53.230 回答
0

我在 OpenCV 的代码中发现了几个与 CV_8UC1、CV_32SC1 等相关的#define。为了使枚举工作,OpenCV 放置了额外的代码来将普通数字作为参数一起转换(即 CV_8UC1、CV_16UC2 ......各自的数字),并在 CvMat 的定义中将深度和通道分开(我猜 Mat 的定义中可能有类似的代码)。然后,它使用 create() 为矩阵分配空间。由于 create() 是内联的,我只能猜测它类似于 malloc() 什么的。
由于源代码从 2.4.9 到 3.0.0 发生了很大变化,我需要稍后发布更多证据。请给我一点时间来了解更多信息并编辑我的答案。

于 2015-09-22T03:39:15.170 回答
-3

简而言之,您提供的表格是正确的。如果要直接访问像素,请将其类型转换为右侧的说明符,例如 CV_32S 是有符号的 32 位。S 始终表示有符号整数(signed char、signed short、signed int) F 始终表示浮点数(float、double) U 始终表示无符号整数。

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

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

cvCreateImage(mySize,char, nChannels);

相反,我通过以下内容:

cvCreateImage(mySize, IPL_DEPTH_8U, nChannels);

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

于 2013-03-06T12:30:21.227 回答