152

I am kind of confused with type() method of Mat object in OpenCV.
If I have following lines:

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

and type = 16, how do I find out what type of mat matrix is?.
I tried to find the answer in its manual and in a couple of books in vain.

Milan
  • 1,743
  • 2
  • 13
  • 36
Tae-Sung Shin
  • 20,215
  • 33
  • 138
  • 240
  • 9
    For human interpretation, prefer the use of `depth()` and `channels()`, instead of using `type()` which returns a complex mix between datatype and number of channels. – BConic Feb 28 '14 at 08:14
  • @Aldur, The return value of depth() still isn't human readable. you have to compare it to the defines: CV_8U, CV_8S, etc... – Octopus Jul 31 '15 at 16:21
  • 1
    @octopus sure but with a bit of practice you can learn the common `depth()` codes, which is far harder for `type()`. – BConic Jul 31 '15 at 16:29
  • 1
    Please note that depth() returns the CV enum value for this type (a bit misleading to beginners). If you need size of one number stored in the Mat in bytes use Mat.elemSize1(). If you need the type at runtime, e.g. within a function where different types are passed into it, you can find a template type TypeDepth<> (maybe we should rename it since it is no CV depth) here: https://stackoverflow.com/questions/15245262/opencv-mat-element-types-and-their-sizes – karsten Sep 27 '17 at 16:07

6 Answers6

261

Here is a handy function you can use to help with identifying your opencv matrices at runtime. I find it useful for debugging, at least.

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

If M is a var of type Mat you can call it like so:

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

Will output data such as:

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

Its worth noting that there are also Matrix methods Mat::depth() and Mat::channels(). This function is just a handy way of getting a human readable interpretation from the combination of those two values whose bits are all stored in the same value.

user202729
  • 3,358
  • 3
  • 25
  • 36
Octopus
  • 8,075
  • 5
  • 46
  • 66
  • 1
    I've created Gist with method from the answer in Objective-C. [Enjoy!](https://gist.github.com/tomaszbak/798adb4e1d3b5710ece2) – Tomasz Bąk Dec 18 '14 at 09:57
  • 1
    For an overview of the types also see this answer (5=32F, 6=64F): http://stackoverflow.com/questions/12335663/getting-enum-names-e-g-cv-32fc1-of-opencv-image-types – Lenar Hoyt Jan 22 '16 at 00:04
  • 1
    Can someone actually make this into a handy function for openCV? – SDG Jan 30 '17 at 10:18
  • 3
    To get `depth` and `chans` you could use the macros `CV_MAT_DEPTH(type)` and `CV_MAT_CN(type)`, respectively. Their type should also be `int`, which would allow you to use `to_string(chans)` instead of `chans+'0'`. – John Sep 01 '17 at 13:46
  • 1
    @John On the other hand, `to_string` is slightly slower if it's known in advance that the number is exactly 1-digit. – user202729 Aug 14 '21 at 01:42
  • @user202729 I would still use `to_string` here, since it is more explicit. Usually getting the type of an image should not be relevant for the performance in comparison to the operations you do on an image. Yet a good comment and it might be useful to remember in general, thanks. – John Aug 14 '21 at 19:19
  • Mats can have **upto 512 channels**. this code will struggle beyond 9 channels. since that's very unusual, it's something to fix but not an immediate problem. – Christoph Rackwitz Jul 02 '22 at 11:33
261

For debugging purposes in case you want to look up a raw Mat::type in a debugger:

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

So for example, if type = 30 then OpenCV data type is CV_64FC4. If type = 50 then the OpenCV data type is CV_16UC(7).

empty
  • 5,194
  • 3
  • 32
  • 58
35

In OpenCV header "types_c.h" there are a set of defines which generate these, the format is CV_bits{U|S|F}C<number_of_channels>
So for example CV_8UC3 means 8 bit unsigned chars, 3 colour channels - each of these names map onto an arbitrary integer with the macros in that file.

Edit: See "types_c.h" for example:

#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

So CV_8UC3 = 16 but you aren't supposed to use this number, just check type() == CV_8UC3 if you need to know what type an internal OpenCV array is.
Remember OpenCV will convert the jpeg into BGR (or grey scale if you pass '0' to imread) - so it doesn't tell you anything about the original file.

Angie Quijano
  • 4,167
  • 3
  • 25
  • 30
Martin Beckett
  • 94,801
  • 28
  • 188
  • 263
  • It's useful to know that `types_c.h` is located in the core module, e.g. if you have OpenCV installed directly on C drive in a folder opencv_2.4.11 the header file would be at C:\opencv_2.4.11\build\include\opencv2\core\types_c.h – user3731622 Aug 29 '16 at 17:49
  • Also, if you're using an IDE which includes "go do definition" functionality like Visual Studio you can type `cv::CV_8U` right-click and select `Go to Definition` to open the file where `cv::CV_8U` is defined which is `types_c.h`. – user3731622 Aug 29 '16 at 17:53
17

This was answered by a few others but I found a solution that worked really well for me.

System.out.println(CvType.typeToString(yourMat.type()));
tommybee
  • 2,409
  • 1
  • 20
  • 23
ProgrammingCuber
  • 377
  • 4
  • 14
16

I've added some usability to the function from the answer by @Octopus, for debugging purposes.

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;
    
}
user202729
  • 3,358
  • 3
  • 25
  • 36
shahar_m
  • 3,461
  • 5
  • 41
  • 61
  • Mats can have **upto 512 channels**. this code will struggle beyond 9 channels. since that's very unusual, it's something to fix but not an immediate problem. – Christoph Rackwitz Jul 02 '22 at 11:36
5

Base on @Matt Edding's comment (Thanks Mat(T) pun intended ;)):

cout << cv::typeToString(inputMat.type()) << endl;

Works like a charm.

YScharf
  • 1,638
  • 15
  • 20