tutorial para examples descargar opencv

para - opencv python



Tipos de elementos OpenCV Mat y sus tamaƱos (6)

Estoy confundido por los tipos de elemento OpenCV Mat. Esto es de los documentos:

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

Se sabe que el estándar de C ++ no define el tamaño de los tipos básicos en bytes, entonces, ¿cómo utilizan tales supuestos? ¿Y qué tipo debería esperar de, digamos, CV_32S, es int32_t o int?


Desarrollando a partir de la respuesta de Miki ,
En OpenCV 3 la definición se ha movido a modules / core / include / opencv2 / core / traits.hpp , donde puedes encontrar:

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

En la mayoría de los casos / compiladores , debería estar bien usando tipos de datos exactos de C ++. No tendría problemas con los tipos de datos de un solo byte ( CV_8U -> uint8_t y CV_8U -> int8_t ) definidos de manera no ambigua en C ++ . Lo mismo para flotante (32 bits) y doble (64 bits) . Sin embargo, es cierto que para otros tipos de datos es completamente seguro que utiliza el tipo de datos correcto (por ejemplo, cuando usa el método at<> ), debe usar, por ejemplo:

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

Como nota al margen, me sorprende que hayan decidido adoptar un enfoque tan ambiguo, en lugar de simplemente usar tipos de datos exactos.

Por lo tanto, con respecto a su última pregunta:

¿De qué tipo debería esperar, digamos, CV_32S ?

Creo que la respuesta más precisa, en OpenCV 3, es:

TypeDepth<CV_32S>::value_type


En core.hpp puedes encontrar lo siguiente:

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

Puede ver que CV_32S es el valor para el tipo int , no int32_t .


En resumen, la tabla que proporcionó es correcta. Si quiere acceder directamente a un píxel, lo encasilla al especificador a la derecha, por ejemplo, CV_32S es un signo de 32 bits. El S siempre significa un número integral con signo (signo firmado, firmado corto, firmado int). La F siempre significa un número de punto flotante (float, double). La U siempre significa un número integral sin signo.

La enumeración se usa solo al crear o convertir un Mat. Es una manera de decirle al tapete cuál es el tipo deseado, ya que entiendo que es el predecesor C para cuando no se usaron las plantillas.

Utilizo la funcionalidad C exclusivamente, y para crear una imagen, sería un error pasar lo siguiente:

cvCreateImage(mySize,char, nChannels);

En cambio, paso lo siguiente:

cvCreateImage(mySize, IPL_DEPTH_8U, nChannels);

Aquí, el IPL_DEPTH_8U es un indicador que usa la función. La función en sí tiene una declaración tipo interruptor que verifica la bandera. El valor real de la bandera generalmente no tiene sentido, ya que generalmente está controlado por declaraciones condicionales, no algebraicas.


He encontrado varios #define en el código de OpenCV relacionados con CV_8UC1, CV_32SC1, etc. Para que las enumeraciones funcionen, OpenCV pone códigos adicionales para convertir los números simples juntos como un parámetro (es decir, CV_8UC1, CV_16UC2 ... están todos representados por su números respectivos), y rompen la profundidad y los canales separados en la definición de CvMat (supongo que Mat puede tener códigos similares en su definición). Luego, usa create () para asignar espacios para la matriz. Como create () está en línea, solo puedo adivinar que es similar a malloc () o algo así.
Como los códigos fuente cambian mucho de 2.4.9 a 3.0.0, necesito publicar más pruebas más adelante. Permíteme un poco de tiempo para averiguar más y editar mi respuesta.



Si bien C ++ no define el tamaño de un elemento, la pregunta es hipotética: para los sistemas en los que se ejecuta OpenCV, se conocen los tamaños. Dado

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;

Entonces, ¿cómo puedes estar seguro de que es int ?

Un intento de llamar

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

será

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

Donde la mano izquierda se define a través de cv::Mat::flags - en este ejemplo como la profundidad predefinida de CV_32SC1 igual a

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

o

CV_DbgAssert( 4 == sizeof(int) )

Entonces, si lo logras, solo te quedará la endianidad. Y eso fue verificado cuando el cvconfig.h fue generado (por CMake).

TL; DR, espera los tipos dados en el encabezado y estarás bien.