Cómo averiguar qué tipo de objeto Mat es con Mat :: type () en OpenCV

118

Estoy un poco confundido con el type()método de Matobjeto en OpenCV.
Si tengo las siguientes líneas:

mat = imread("C:\someimage.jpg");
type = mat.type();

y type = 16. ¿Cómo averiguo qué tipo de matriz de tapete es ?.
Intenté encontrar la respuesta en su manual o en un par de libros en vano.

Tae-Sung Shin
fuente
6
Para la interpretación humana, prefiera el uso de depth()y channels(), en lugar de usar type()que devuelve una combinación compleja entre el tipo de datos y el número de canales.
BConic
@Aldur, el valor de retorno de la profundidad () todavía no es legible por humanos. tienes que compararlo con los define: CV_8U, CV_8S, etc ...
Octopus
1
@octopus seguro, pero con un poco de práctica puedes aprender los depth()códigos comunes , que es mucho más difícil type().
BConic
Tenga en cuenta que depth () devuelve el valor de enumeración CV para este tipo (un poco engañoso para los principiantes). Si necesita el tamaño de un número almacenado en el Mat en bytes, use Mat.elemSize1 (). Si necesita el tipo en tiempo de ejecución, por ejemplo, dentro de una función donde se le pasan diferentes tipos, puede encontrar un tipo de plantilla TypeDepth <> (tal vez deberíamos cambiarle el nombre ya que no tiene profundidad de CV) aquí: stackoverflow.com/questions/ 15245262 /…
karsten

Respuestas:

196

Aquí hay una función útil que puede usar para ayudar a identificar sus matrices opencv en tiempo de ejecución. Lo encuentro útil para depurar, al menos.

string type2str(int type) {
  string r;

  uchar depth = type & CV_MAT_DEPTH_MASK;
  uchar chans = 1 + (type >> CV_CN_SHIFT);

  switch ( depth ) {
    case CV_8U:  r = "8U"; break;
    case CV_8S:  r = "8S"; break;
    case CV_16U: r = "16U"; break;
    case CV_16S: r = "16S"; break;
    case CV_32S: r = "32S"; break;
    case CV_32F: r = "32F"; break;
    case CV_64F: r = "64F"; break;
    default:     r = "User"; break;
  }

  r += "C";
  r += (chans+'0');

  return r;
}

Si Mes una var de tipo Mat, puede llamarlo así:

string ty =  type2str( M.type() );
printf("Matrix: %s %dx%d \n", ty.c_str(), M.cols, M.rows );

Dará salida a datos como:

Matrix: 8UC3 640x480 
Matrix: 64FC1 3x2 

Vale la pena señalar que también existen métodos Matrix Mat::depth()y Mat::channels(). Esta función es solo una forma práctica de obtener una interpretación legible por humanos a partir de la combinación de esos dos valores cuyos bits están todos almacenados en el mismo valor.

Pulpo
fuente
7
Gracias por esta función, ¡me hiciste la vida mucho más fácil! Es decepcionante que dicha función no esté ya integrada en opencv thow.
Milania
1
Creé Gist con el método de la respuesta en Objective-C. ¡Disfrutar!
Tomasz Bąk
1
Para obtener una descripción general de los tipos, consulte también esta respuesta (5 = 32F, 6 = 64F): stackoverflow.com/questions/12335663/…
Lenar Hoyt
¿Alguien puede convertir esto en una función útil para openCV?
Sharan Duggirala
1
Para obtener depthy chanspodría usar las macros CV_MAT_DEPTH(type)y CV_MAT_CN(type), respectivamente. Su tipo también debería ser int, lo que le permitiría usar en to_string(chans)lugar de chans+'0'.
Juan
151

Para fines de depuración en caso de que desee buscar un Mat sin formato: escriba un depurador:

+--------+----+----+----+----+------+------+------+------+
|        | C1 | C2 | C3 | C4 | C(5) | C(6) | C(7) | C(8) |
+--------+----+----+----+----+------+------+------+------+
| CV_8U  |  0 |  8 | 16 | 24 |   32 |   40 |   48 |   56 |
| CV_8S  |  1 |  9 | 17 | 25 |   33 |   41 |   49 |   57 |
| CV_16U |  2 | 10 | 18 | 26 |   34 |   42 |   50 |   58 |
| CV_16S |  3 | 11 | 19 | 27 |   35 |   43 |   51 |   59 |
| CV_32S |  4 | 12 | 20 | 28 |   36 |   44 |   52 |   60 |
| CV_32F |  5 | 13 | 21 | 29 |   37 |   45 |   53 |   61 |
| CV_64F |  6 | 14 | 22 | 30 |   38 |   46 |   54 |   62 |
+--------+----+----+----+----+------+------+------+------+

Entonces, por ejemplo, si type = 30, entonces el tipo de datos OpenCV es CV_64FC4. Si type = 50, entonces el tipo de datos OpenCV es CV_16UC (7).

Kevin Johnsrude
fuente
6
¿Qué significa la C (X)?
alanwsx
5
^ El número de canales en la matriz
Arijit
3
^ ¿Cuál es la diferencia entre C5 y C (5), entonces?
Mateen Ulhaq
1
No hay diferencia.
Kevin Johnsrude
1
Gracias. Esta debería ser la respuesta principal
regomodo
32

En el encabezado OpenCV " types_c.h " hay un conjunto de definiciones que las generan, el formato es CV_bits{U|S|F}C<number_of_channels>
Entonces, por ejemplo, CV_8UC3significa caracteres sin firmar de 8 bits, 3 canales de color: cada uno de estos nombres se asigna a un entero arbitrario con las macros en ese archivo.

Editar: consulte " types_c.h " por ejemplo:

#define CV_8UC3 CV_MAKETYPE(CV_8U,3)
#define CV_MAKETYPE(depth,cn) (CV_MAT_DEPTH(depth) + (((cn)-1) << CV_CN_SHIFT))

eg.
depth = CV_8U = 0
cn = 3
CV_CN_SHIFT = 3

CV_MAT_DEPTH(0) = 0
(((cn)-1) << CV_CN_SHIFT) = (3-1) << 3 = 2<<3 = 16

Entonces, CV_8UC3 = 16 pero se supone que no debe usar este número, solo verifique type() == CV_8UC3si necesita saber qué tipo es una matriz OpenCV interna.
Recuerde que OpenCV convertirá el jpeg en BGR (o escala de grises si pasa '0' a imread), por lo que no le dice nada sobre el archivo original.

Martin Beckett
fuente
Es útil saber que types_c.hestá ubicado en el módulo principal, por ejemplo, si tiene OpenCV instalado directamente en la unidad C en una carpeta opencv_2.4.11, el archivo de encabezado estaría en C: \ opencv_2.4.11 \ build \ include \ opencv2 \ core \ types_c .h
user3731622
Además, si está utilizando un IDE que incluye la funcionalidad "ir a la definición" como Visual Studio, puede escribir cv::CV_8Uclic derecho y seleccionar Go to Definitionpara abrir el archivo donde cv::CV_8Uestá definido types_c.h.
user3731622
8

Agregué algo de usabilidad a la función de la respuesta de @Octopus, para fines de depuración.

void MatType( Mat inputMat )
{
    int inttype = inputMat.type();

    string r, a;
    uchar depth = inttype & CV_MAT_DEPTH_MASK;
    uchar chans = 1 + (inttype >> CV_CN_SHIFT);
    switch ( depth ) {
        case CV_8U:  r = "8U";   a = "Mat.at<uchar>(y,x)"; break;  
        case CV_8S:  r = "8S";   a = "Mat.at<schar>(y,x)"; break;  
        case CV_16U: r = "16U";  a = "Mat.at<ushort>(y,x)"; break; 
        case CV_16S: r = "16S";  a = "Mat.at<short>(y,x)"; break; 
        case CV_32S: r = "32S";  a = "Mat.at<int>(y,x)"; break; 
        case CV_32F: r = "32F";  a = "Mat.at<float>(y,x)"; break; 
        case CV_64F: r = "64F";  a = "Mat.at<double>(y,x)"; break; 
        default:     r = "User"; a = "Mat.at<UKNOWN>(y,x)"; break; 
    }   
    r += "C";
    r += (chans+'0');
    cout << "Mat is of type " << r << " and should be accessed with " << a << endl;

}
shahar_m
fuente
6

Esto fue respondido por algunos otros, pero encontré una solución que funcionó muy bien para mí.

System.out.println(CvType.typeToString(yourMat));
ProgrammingCuber
fuente