Cách tìm loại đối tượng Mat là gì với Mat :: type () trong OpenCV


118

Tôi hơi nhầm lẫn với type()phương thức của Matđối tượng trong OpenCV.
Nếu tôi có những dòng sau:

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

type = 16. Làm thế nào để tôi tìm ra loại ma trận mat là gì?
Tôi đã cố gắng tìm câu trả lời trong sách hướng dẫn của nó hoặc trong một vài cuốn sách trong vô vọng.


6
Đối với diễn giải của con người, hãy ưu tiên sử dụng depth()channels()thay vì sử dụng type()trả về sự kết hợp phức tạp giữa kiểu dữ liệu và số kênh.
BConic

@Aldur, Giá trị trả về của chiều sâu () vẫn không thể đọc được. bạn phải so sánh nó với các định nghĩa: CV_8U, CV_8S, v.v.
Octopus,

1
@octopus chắc chắn nhưng với một chút thực hành, bạn có thể học các depth()mã phổ biến , điều này khó hơn nhiều type().
BConic

Xin lưu ý rằng deep () trả về giá trị CV enum cho kiểu này (hơi gây hiểu lầm cho người mới bắt đầu). Nếu bạn cần kích thước của một số được lưu trữ trong Mat theo byte, hãy sử dụng Mat.elemSize1 (). Nếu bạn cần loại trong thời gian chạy, ví dụ như trong một hàm nơi các loại khác nhau được chuyển vào nó, bạn có thể tìm thấy loại mẫu TypeDepth <> (có thể chúng ta nên đổi tên nó vì nó không có độ sâu CV) tại đây: stackoverflow.com/questions/ 15245262 /…
karsten 27/09/17

Câu trả lời:


196

Đây là một chức năng hữu ích mà bạn có thể sử dụng để giúp xác định ma trận opencv của bạn trong thời gian chạy. Tôi thấy nó hữu ích cho việc gỡ lỗi, ít nhất.

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

Nếu Mlà kiểu var, Matbạn có thể gọi nó như vậy:

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

Sẽ xuất dữ liệu như:

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

Đáng chú ý của nó là cũng có các phương pháp Ma trận Mat::depth()Mat::channels(). Hàm này chỉ là một cách tiện dụng để con người có thể đọc được từ sự kết hợp của hai giá trị mà các bit của chúng đều được lưu trữ trong cùng một giá trị.


7
Cảm ơn vì chức năng này, bạn đã làm cho cuộc sống của tôi dễ dàng hơn nhiều! Thật thất vọng khi một chức năng như vậy chưa được tích hợp trong opencv thow.
Milania

1
Tôi đã tạo Gist với phương thức từ câu trả lời trong Objective-C. Thưởng thức!
Tomasz Bąk

1
Đối với một tổng quan về các loại cũng thấy câu trả lời này (5 = 32F, 6 = 64F): stackoverflow.com/questions/12335663/...
LENAR Hoyt

Ai đó có thể thực sự biến điều này thành một hàm tiện dụng cho openCV không?
Sharan Duggirala

1
Để lấy depthchansbạn có thể sử dụng các macro CV_MAT_DEPTH(type)CV_MAT_CN(type)tương ứng. Loại của họ cũng phải là int, sẽ cho phép bạn sử dụng to_string(chans)thay vì chans+'0'.
John

151

Đối với mục đích gỡ lỗi trong trường hợp bạn muốn tra cứu Mat thô :: gõ vào trình gỡ lỗi:

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

Vì vậy, ví dụ, nếu kiểu = 30 thì kiểu dữ liệu OpenCV là CV_64FC4. Nếu kiểu = 50 thì kiểu dữ liệu OpenCV là CV_16UC (7).


6
C (X) có nghĩa là gì?
alanwsx

5
^ Số lượng kênh trong ma trận
Arijit

3
^ Vậy sự khác biệt giữa C5 và C (5) là gì?
Mateen Ulhaq

1
Không có sự khác biệt.
Kevin Johnsrude

1
Cảm ơn. Đây hẳn là câu trả lời hàng đầu
regomodo

32

Trong tiêu đề OpenCV " styles_c.h " có một tập hợp các định nghĩa tạo ra chúng, định dạng là CV_bits{U|S|F}C<number_of_channels>
Vì vậy, ví dụ: CV_8UC3có nghĩa là 8 bit không dấu, 3 kênh màu - mỗi tên này ánh xạ vào một số nguyên tùy ý với các macro trong tệp đó.

Chỉnh sửa: Xem " type_c.h " chẳng hạn:

#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

Vì vậy, CV_8UC3 = 16 nhưng bạn không được phép sử dụng số này, chỉ cần kiểm tra type() == CV_8UC3xem bạn có cần biết loại mảng OpenCV nội bộ là gì không.
Hãy nhớ OpenCV sẽ chuyển đổi jpeg thành BGR (hoặc thang màu xám nếu bạn chuyển '0' thành imread) - vì vậy nó không cho bạn biết bất cứ điều gì về tệp gốc.


Sẽ rất hữu ích nếu bạn biết nó types_c.hnằm trong mô-đun lõi, ví dụ: nếu bạn đã cài đặt OpenCV trực tiếp trên ổ C trong thư mục opencv_2.4.11, tệp tiêu đề sẽ ở C: \ opencv_2.4.11 \ build \ include \ opencv2 \ core \ type_c .h
user3731622

Ngoài ra, nếu bạn đang sử dụng IDE bao gồm chức năng "bắt đầu định nghĩa" như Visual Studio, bạn có thể nhập cv::CV_8Unhấp chuột phải và chọn Go to Definitionđể mở tệp cv::CV_8Uđược xác định ở đâu types_c.h.
user3731622


8

Tôi đã thêm một số khả năng hữu dụng vào chức năng từ câu trả lời của @Octopus, cho mục đích gỡ lỗi.

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

Điều này đã được trả lời bởi một số người khác nhưng tôi đã tìm thấy một giải pháp thực sự hiệu quả cho tôi.

System.out.println(CvType.typeToString(yourMat));
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.