Как узнать, какой тип объекта Mat с Mat :: type () в OpenCV

118

Я немного смущен type()методом Matобъекта в OpenCV.
Если у меня есть следующие строки:

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

и type = 16. Как узнать, что это за мат-матрица ?.
Я тщетно пытался найти ответ в его мануале или в паре книг.

Тэ-Сун Шин
источник
6
Для интерпретации человеком предпочтительнее использовать depth()и channels()вместо использования, type()которое возвращает сложное сочетание типа данных и количества каналов.
BConic
@Aldur, возвращаемое значение depth () все еще не читается человеком. вы должны сравнить это с определениями: CV_8U, CV_8S и т. д.
Octopus
1
@octopus конечно, но немного попрактиковавшись, вы сможете изучить общие depth()коды, что намного сложнее type().
BConic
Обратите внимание, что depth () возвращает значение перечисления CV для этого типа (немного вводит в заблуждение новичков). Если вам нужен размер одного числа, хранящегося в Mat в байтах, используйте Mat.elemSize1 (). Если вам нужен тип во время выполнения, например, в функции, в которую передаются разные типы, вы можете найти тип шаблона TypeDepth <> (возможно, нам следует переименовать его, поскольку это не глубина CV) здесь: stackoverflow.com/questions/ 15245262 / ...
Карстен

Ответы:

196

Вот удобная функция, которую вы можете использовать, чтобы помочь с идентификацией ваших матриц opencv во время выполнения. По крайней мере, я считаю это полезным для отладки.

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

Если Mэто тип типа var, Matвы можете назвать его так:

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

Будет выводить такие данные, как:

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

Стоит отметить, что существуют также методы Matrix Mat::depth()и Mat::channels(). Эта функция - всего лишь удобный способ получить понятную для человека интерпретацию комбинации тех двух значений, биты которых хранятся в одном и том же значении.

Осьминог
источник
7
Спасибо за эту функцию, вы сделали мою жизнь намного проще! Обидно, что такая функция еще не интегрирована в opencv.
Милания
1
Я создал Gist с методом из ответа в Objective-C. Наслаждайтесь!
Tomasz Bk
1
Для обзора типов также см. Этот ответ (5 = 32F, 6 = 64F): stackoverflow.com/questions/12335663/…
Ленар Хойт,
Может ли кто-нибудь сделать из этого удобную функцию для openCV?
Шаран Дуггирала
1
Для получения depthи chansможно было использовать макросы CV_MAT_DEPTH(type)и CV_MAT_CN(type)соответственно. Их тип также должен быть таким int, чтобы вы могли использовать to_string(chans)вместо chans+'0'.
Джон
152

В целях отладки, если вы хотите найти необработанный Mat :: type в отладчике:

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

Так, например, если type = 30, то тип данных OpenCV - CV_64FC4. Если type = 50, то тип данных OpenCV - CV_16UC (7).

Кевин Джонсруд
источник
6
Что означает C (X)?
alanwsx
5
^ Количество каналов в матрице
Ариджит
3
^ В чем же тогда разница между C5 и C (5)?
Матин Улхак,
1
Нет никакой разницы.
Кевин Джонсруд
1
Спасибо. Это должен быть главный ответ
regomodo
32

В заголовке OpenCV « types_c.h » есть набор определений, которые их генерируют, формат таков,CV_bits{U|S|F}C<number_of_channels>
например, CV_8UC3означает 8-битные символы без знака, 3 цветовых канала - каждое из этих имен отображается на произвольное целое число с макросами в этом файле.

Изменить: см. " Types_c.h ", например:

#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

Итак, CV_8UC3 = 16 но вы не должны использовать это число, просто проверьте type() == CV_8UC3, нужно ли вам знать, какой тип внутреннего массива OpenCV.
Помните, что OpenCV преобразует jpeg в BGR (или шкалу серого, если вы передадите «0» imread) - поэтому он ничего не скажет вам об исходном файле.

Мартин Беккет
источник
Полезно знать, что types_c.hон находится в основном модуле, например, если у вас установлен OpenCV непосредственно на диске C в папке opencv_2.4.11, файл заголовка будет в C: \ opencv_2.4.11 \ build \ include \ opencv2 \ core \ types_c .h
user3731622
Кроме того, если вы используете IDE, которая включает в себя функцию «перейти к определению», например Visual Studio, вы можете cv::CV_8Uнажать правой кнопкой мыши и выбрать Go to Definitionоткрытие файла, в котором cv::CV_8Uопределено, что есть types_c.h.
user3731622
8

Я добавил удобство использования функции из ответа @Octopus для целей отладки.

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
источник
6

На этот вопрос ответили еще несколько человек, но я нашел решение, которое мне очень понравилось.

System.out.println(CvType.typeToString(yourMat));
ProgrammingCuber
источник