web-dev-qa-db-fra.com

Types d'élément OpenCV Mat et leurs tailles

Je suis dérouté par les types d'élément OpenCV Mat. Cela vient de la documentation:

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 };

On sait que la norme C++ ne définit pas la taille des types de base en octets. Comment utilisent-ils de telles hypothèses? Et à quel type devrais-je m'attendre, disons, CV_32S, est-ce int32_t ou int?

33
lizarisk

Développer à partir de réponse de Miki ,
Dans OpenCV 3, la définition est passée à modules/core/include/opencv2/core/traits.hpp, où vous pouvez trouver:

/** @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;
};

Dans la plupart des observations/compilateurs, vous devriez utiliser les types de données exacts C++. Vous n'auriez pas de problèmes avec les types de données à un octet (CV_8U -> uint8_t et CV_8U -> int8_t) en tant que défini sans ambiguïté en C++ . Même chose pour float (32bit) et double (64bit) }. Cependant, il est vrai que pour que les autres types de données soient complètement sûrs d'utiliser le bon type de données (par exemple, lorsque vous utilisez la méthode at<>), vous devez utiliser par exemple:

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

En passant, je suis surpris qu'ils aient décidé d'adopter une approche aussi ambiguë au lieu d'utiliser simplement des types de données exacts.

Par conséquent, concernant votre dernière question:

À quel type devrais-je m'attendre, disons, CV_32S?

Je pense que la réponse la plus précise, dans OpenCV 3, est la suivante:

TypeDepth<CV_32S>::value_type
5
Antonio

Dans core.hpp vous pouvez trouver ce qui suit:

/*!
  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' }; };

Vous pouvez voir que CV_32S est la valeur pour le type int, pas int32_t.

3
Miki

Bien que C++ ne définisse pas la taille d'un élément, la question est hypothétique: pour les systèmes sur lesquels OpenCV est exécuté, les tailles sont connues. Donné

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;

Alors, comment pouvez-vous être sûr que c'est int?

Une tentative d'appel

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

volonté

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

Où la main gauche est définie via le cv::Mat::flags - dans cet exemple, la profondeur prédéfinie du CV_32SC1 est égale à

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

ou

CV_DbgAssert( 4 == sizeof(int) )

Donc, si vous avez réussi, il ne vous reste que l’endianisme. Et cela a été vérifié lorsque le fichier cvconfig.h a été généré (par CMake).

TL; DR, attendez-vous aux types donnés dans l'en-tête et tout ira bien.

1
mainactual

Vous pouvez trouver toutes les définitions de vos questions dans les sources d’opencv.

Voir https://github.com/Itseez/opencv/blob/master/modules/core/include/opencv2/core/cvdef.h file. 

0
Andrey Smorodov

J'ai trouvé plusieurs #define dans le code d'OpenCV lié à CV_8UC1, CV_32SC1, etc. Pour que les énumérations fonctionnent, OpenCV a mis des codes supplémentaires pour convertir les nombres simples ensemble en tant que paramètre (CV_8UC1, CV_16UC2, etc.) sont tous représentés par leur numéros respectifs) et séparez la profondeur et les canaux de la définition de CvMat (je suppose que Mat peut avoir des codes similaires dans sa définition). Ensuite, il utilise create () pour allouer des espaces à la matrice. Puisque create () est en ligne, je ne peux que deviner que cela ressemble à malloc () ou quelque chose du genre. 
Comme les codes sources changent beaucoup de 2.4.9 à 3.0.0, je dois poster plus de preuves plus tard. S'il vous plaît, laissez-moi un peu de temps pour en savoir plus et éditer ma réponse. 

0
Aurus Huang