【问题标题】:How to find out what type of a Mat object is with Mat::type() in OpenCV?如何在 OpenCV 中使用 Mat::type() 找出 Mat 对象的类型
【发布时间】:2012-04-27 09:27:11
【问题描述】:

我对 OpenCV 中 Mat 对象的 type() 方法有点困惑。
如果我有以下几行:

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

type = 16。如何找出 mat 矩阵的类型?
我试图在其手册或几本书中找到答案,但徒劳无功。

【问题讨论】:

  • 对于人工解释,最好使用depth()channels(),而不是使用type(),后者会返回数据类型和通道数之间的复杂组合。
  • @Aldur,depth() 的返回值仍然不是人类可读的。您必须将其与定义进行比较:CV_8U、CV_8S 等...
  • @octopus 当然可以,但是通过一些练习,您可以学习常见的depth() 代码,这对于type() 来说要困难得多。
  • 请注意 depth() 返回此类型的 CV 枚举值(对初学者有点误导)。如果您需要存储在 Mat 中的一个数字的大小(以字节为单位),请使用 Mat.elemSize1()。如果您在运行时需要该类型,例如在传入不同类型的函数中,您可以在此处找到模板类型 TypeDepth(也许我们应该重命名它,因为它没有 CV 深度):stackoverflow.com/questions/15245262/…

标签: opencv opencv-mat


【解决方案1】:

基于@Matt Edding 的评论(感谢 Mat(T) 双关语;)):

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

像魅力一样工作。

【讨论】:

    【解决方案2】:

    出于调试目的,我从@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;
        
    }
    

    【讨论】:

      【解决方案3】:

      这是一个方便的函数,您可以使用它来帮助在运行时识别您的 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;
      }
      

      如果MMat 类型的var,你可以这样称呼它:

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

      会输出如下数据:

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

      值得注意的是,还有矩阵方法Mat::depth()Mat::channels()。这个函数只是一种方便的方法,可以从这两个值的组合中获得人类可读的解释,这两个值的位都存储在同一个值中。

      【讨论】:

      • 我用 Objective-C 中的答案中的方法创建了 Gist。 Enjoy!
      • 有关类型的概述,另请参阅此答案(5=32F,6=64F):stackoverflow.com/questions/12335663/…
      • 有人真的可以把它变成一个方便的 openCV 函数吗?
      • 要获得depthchans,您可以分别使用宏CV_MAT_DEPTH(type)CV_MAT_CN(type)。它们的类型也应该是int,这将允许您使用to_string(chans) 而不是chans+'0'
      • @John 另一方面,to_string 如果事先知道该数字恰好是 1 位,则速度会稍慢。
      【解决方案4】:

      出于调试目的,如果您想在调试器中查找原始 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)

      【讨论】:

      • C(X) 是什么意思?
      • ^矩阵中的通道数
      • ^ 那么C5和C(5)有什么区别呢?
      • 没有区别。
      • @MateenUlhaq 只是一个小提示:您可以创建不带括号(在类型参数中)的最多 4 位通道的图像(Mat Objects),但创建 >=5 通道的图像将返回错误.示例:Mat img(23, 53, CV_64FC(5)) 有效但 Mat img(23, 53, CV_64FC5) 无效。
      【解决方案5】:

      其他一些人回答了这个问题,但我找到了一个非常适合我的解决方案。

      System.out.println(CvType.typeToString(yourMat.type()));
      

      【讨论】:

      • C++: cv::typeToString
      • 注意:这个 API 是从 3.4.2 开始为 3.x 分支添加的。 4.x 分支从 4.0.0 开始就有这个 API。
      【解决方案6】:

      在 OpenCV 头文件“types_c.h”中有一组定义生成这些,格式为CV_bits{U|S|F}C&lt;number_of_channels&gt;
      因此,例如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 但你不应该使用这个数字,如果你需要知道内部 OpenCV 数组是什么类型,只需检查type() == CV_8UC3
      请记住,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
      • 另外,如果您使用的 IDE 包含像 Visual Studio 这样的“执行定义”功能,您可以键入 cv::CV_8U 右键单击​​并选择 Go to Definition 以打开 cv::CV_8U 所在的文件被定义为types_c.h
      猜你喜欢
      • 1970-01-01
      • 2018-07-09
      • 2012-12-27
      • 1970-01-01
      • 1970-01-01
      • 2013-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多