Como descobrir que tipo de objeto Mat é com Mat :: type () no OpenCV


118

Estou meio confuso com o type()método do Matobjeto no OpenCV.
Se eu tiver as seguintes linhas:

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

e type = 16. Como faço para descobrir que tipo de matriz de esteira é ?.
Tentei encontrar a resposta em seu manual ou em alguns livros em vão.


6
Para interpretação humana, prefira o uso de depth()e channels(), em vez de usar type()que retorna uma mistura complexa entre o tipo de dados e o número de canais.
BConic

@Aldur, O valor de retorno de depth () ainda não é legível por humanos. você tem que compará-lo com as definições: CV_8U, CV_8S, etc ...
Octopus

1
@octopus claro, mas com um pouco de prática você pode aprender os depth()códigos comuns , o que é muito mais difícil type().
BConic

Observe que depth () retorna o valor enum CV para este tipo (um pouco enganador para iniciantes). Se você precisar do tamanho de um número armazenado no Mat em bytes, use Mat.elemSize1 (). Se você precisar do tipo em tempo de execução, por exemplo, dentro de uma função onde diferentes tipos são passados ​​para ela, você pode encontrar um tipo de modelo TypeDepth <> (talvez devêssemos renomeá-lo, pois não tem profundidade de CV) aqui: stackoverflow.com/questions/ 15245262 /…
karsten

Respostas:


196

Aqui está uma função útil que você pode usar para ajudar a identificar suas matrizes opencv em tempo de execução. Acho útil para depuração, pelo 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;
}

Se Mfor uma var do tipo, Matvocê pode chamá-lo assim:

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

Produzirá dados como:

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

É importante notar que também existem métodos Matrix Mat::depth()e Mat::channels(). Essa função é apenas uma maneira prática de obter uma interpretação legível por humanos da combinação desses dois valores cujos bits estão todos armazenados no mesmo valor.


7
Obrigado por esta função, você facilitou muito minha vida! É decepcionante que tal função ainda não esteja integrada no Opencv Thow.
Milânia

1
Criei Gist com método a partir da resposta em Objective-C. Aproveitar!
Tomasz Bąk

1
Para uma visão geral dos tipos, consulte também esta resposta (5 = 32F, 6 = 64F): stackoverflow.com/questions/12335663/…
Lenar Hoyt

Alguém pode realmente fazer isso em uma função útil para openCV?
Sharan Duggirala

1
Para obter depthe chansvocê pode usar as macros CV_MAT_DEPTH(type)e CV_MAT_CN(type), respectivamente. Seu tipo também deve ser int, o que permitirá que você use em to_string(chans)vez de chans+'0'.
John

151

Para fins de depuração, caso você queira procurar um Mat :: type bruto em um 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 |
+--------+----+----+----+----+------+------+------+------+

Portanto, por exemplo, se tipo = 30, o tipo de dados OpenCV é CV_64FC4. Se tipo = 50, o tipo de dados OpenCV é CV_16UC (7).


6
O que significa C (X)?
alanwsx

5
^ O número de canais na matriz
Arijit

3
^ Qual é a diferença entre C5 e C (5), então?
Mateen Ulhaq

1
Não há diferença.
Kevin Johnsrude,

1
Obrigado. Esta deve ser a melhor resposta
regomodo

32

No cabeçalho OpenCV " types_c.h " há um conjunto de definições que os geram, o formato é CV_bits{U|S|F}C<number_of_channels>
Então, por exemplo, CV_8UC3significa caracteres sem sinal de 8 bits, 3 canais de cores - cada um desses nomes mapeia para um inteiro arbitrário com as macros naquele arquivo.

Editar: Veja " types_c.h " por exemplo:

#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

Então, CV_8UC3 = 16 mas você não deve usar esse número, apenas verifique type() == CV_8UC3se você precisa saber qual é o tipo de um array OpenCV interno.
Lembre-se de que o OpenCV irá converter o jpeg em BGR (ou escala de cinza se você passar '0' para imread) - então ele não informa nada sobre o arquivo original.


É útil saber que types_c.hestá localizado no módulo principal, por exemplo, se você tiver o OpenCV instalado diretamente na unidade C em uma pasta opencv_2.4.11, o arquivo de cabeçalho estará em C: \ opencv_2.4.11 \ build \ include \ opencv2 \ core \ types_c .h
user3731622

Além disso, se você estiver usando um IDE que inclui a funcionalidade "go do definition" como o Visual Studio, você pode digitar cv::CV_8Ucom o botão direito e selecionar Go to Definitionpara abrir o arquivo onde cv::CV_8Uestá definido types_c.h.
user3731622


8

Eu adicionei alguma usabilidade à função da resposta de @Octopus, para fins de depuração.

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;

}

6

Algumas pessoas responderam a essa pergunta, mas encontrei uma solução que funcionou muito bem para mim.

System.out.println(CvType.typeToString(yourMat));
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.