Comment savoir quel type d'objet Mat est avec Mat :: type () dans OpenCV

118

Je suis un peu confus avec la type()méthode de l' Matobjet dans OpenCV.
Si j'ai des lignes suivantes:

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

et type = 16. Comment puis-je savoir quel est le type de matrice de tapis?.
J'ai essayé de trouver la réponse dans son manuel ou dans quelques livres en vain.

Tae-Sung Shin
la source
6
Pour l'interprétation humaine, préférez l'utilisation de depth()et channels(), au lieu d'utiliser type()qui renvoie un mélange complexe entre le type de données et le nombre de canaux.
BConic
@Aldur, La valeur de retour de depth () n'est toujours pas lisible par l'homme. vous devez le comparer aux définitions: CV_8U, CV_8S, etc ...
Octopus
1
@octopus bien sûr, mais avec un peu de pratique, vous pouvez apprendre les depth()codes communs , ce qui est beaucoup plus difficile type().
BConic
Veuillez noter que depth () renvoie la valeur d'énumération CV pour ce type (un peu trompeur pour les débutants). Si vous avez besoin de la taille d'un nombre stocké dans le Mat en octets, utilisez Mat.elemSize1 (). Si vous avez besoin du type au moment de l'exécution, par exemple dans une fonction où différents types y sont passés, vous pouvez trouver un type de modèle TypeDepth <> (peut-être devrions-nous le renommer puisqu'il n'y a pas de profondeur de CV) ici: stackoverflow.com/questions/ 15245262 /…
karsten

Réponses:

196

Voici une fonction pratique que vous pouvez utiliser pour vous aider à identifier vos matrices opencv au moment de l'exécution. Je trouve cela utile pour le débogage, au moins.

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 Mest une var de type, Matvous pouvez l'appeler comme ceci:

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

Sortira des données telles que:

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

Il convient de noter qu'il existe également des méthodes Matrix Mat::depth()et Mat::channels(). Cette fonction est juste un moyen pratique d'obtenir une interprétation lisible par l'homme à partir de la combinaison de ces deux valeurs dont les bits sont tous stockés dans la même valeur.

Poulpe
la source
7
Merci pour cette fonction, vous m'avez rendu la vie beaucoup plus facile! Décevant qu'une telle fonction ne soit pas déjà intégrée dans opencv thow.
Milania
1
J'ai créé Gist avec la méthode de la réponse en Objective-C. Prendre plaisir!
Tomasz Bąk
1
Pour un aperçu des types, voir également cette réponse (5 = 32F, 6 = 64F): stackoverflow.com/questions/12335663/…
Lenar Hoyt
Quelqu'un peut-il réellement en faire une fonction pratique pour openCV?
Sharan Duggirala
1
Pour obtenir depthet chansvous pouvez utiliser les macros CV_MAT_DEPTH(type)et CV_MAT_CN(type), respectivement. Leur type devrait également être int, ce qui vous permettrait d'utiliser à la to_string(chans)place de chans+'0'.
John
151

À des fins de débogage, au cas où vous souhaiteriez rechercher un type Mat :: brut dans un débogueur:

+--------+----+----+----+----+------+------+------+------+
|        | 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 |
+--------+----+----+----+----+------+------+------+------+

Par exemple, si type = 30, le type de données OpenCV est CV_64FC4. Si type = 50, le type de données OpenCV est CV_16UC (7).

Kevin Johnsrude
la source
6
Que signifie le C (X)?
alanwsx
5
^ Le nombre de canaux dans la matrice
Arijit
3
^ Quelle est la différence entre C5 et C (5), alors?
Mateen Ulhaq
1
Il n'y a pas de différence.
Kevin Johnsrude
1
Merci. Cela devrait être la meilleure réponse
regomodo
32

Dans l'en-tête OpenCV " types_c.h ", il y a un ensemble de définitions qui les génèrent, le format est CV_bits{U|S|F}C<number_of_channels>
Donc, par exemple, CV_8UC3signifie 8 bits de caractères non signés, 3 canaux de couleur - chacun de ces noms correspond à un entier arbitraire avec les macros dans ce fichier.

Edit: Voir " types_c.h " par exemple:

#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

Donc, CV_8UC3 = 16 mais vous n'êtes pas censé utiliser ce numéro, vérifiez simplement type() == CV_8UC3si vous avez besoin de savoir de quel type est un tableau OpenCV interne.
N'oubliez pas qu'OpenCV convertira le jpeg en BGR (ou en échelle de gris si vous passez '0' à imread) - donc il ne vous dit rien sur le fichier original.

Martin Beckett
la source
Il est utile de savoir qu'il types_c.hse trouve dans le module principal, par exemple, si OpenCV est installé directement sur le lecteur C dans un dossier opencv_2.4.11, le fichier d'en-tête se trouvera dans C: \ opencv_2.4.11 \ build \ include \ opencv2 \ core \ types_c .h
user3731622
En outre, si vous utilisez un IDE qui inclut la fonctionnalité «go do definition» comme Visual Studio, vous pouvez taper cv::CV_8Uun clic droit et sélectionner Go to Definitionpour ouvrir le fichier où cv::CV_8Uest défini ce qui est types_c.h.
user3731622
8

J'ai ajouté une certaine convivialité à la fonction à partir de la réponse de @Octopus, à des fins de débogage.

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
la source
6

Quelques autres ont répondu à cette question, mais j'ai trouvé une solution qui fonctionnait vraiment bien pour moi.

System.out.println(CvType.typeToString(yourMat));
ProgrammationCuber
la source