2013-03-06 93 views
31

我很困惑OpenCV Mat元素類型。這是從文檔:OpenCV Mat元素類型及其大小

There is a limited fixed set of primitive data types the library can operate on. 
That is, array elements should have one of the following types: 

8-bit unsigned integer (uchar) 
8-bit signed integer (schar) 
16-bit unsigned integer (ushort) 
16-bit signed integer (short) 
32-bit signed integer (int) 
32-bit floating-point number (float) 
64-bit floating-point number (double) 
... 

For these basic types, the following enumeration is applied: 
enum { CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 }; 

據瞭解,C++標準沒有定義以字節爲單位基本類型的大小,所以他們是如何使用這樣的假設?我應該指望什麼類型的CV_32S,它是int32_t還是int?

+2

類型在OpenCV中是很容易理解。 CV_numbitsType。所以CV_16S是一個16位長的有符號整數。 – 2013-03-06 11:03:23

+0

那麼爲什麼他們在文檔(int,float等)中爲它們使用這樣的名稱,而(例如)int可以是64位而不是32位? – lizarisk 2013-03-06 11:14:35

+2

我真的不知道底層結構,但是當您使用類型CV_32S創建一個墊子時: 'Mat myMat(10,10,CV_32S);' 您可以用 'myMat.at (1,1) = 1;' – sfotiadis 2013-03-06 11:20:49

回答

-3

總之你提供的表是正確的。 如果你想直接訪問一個像素,你可以將它轉換爲右側的說明符,例如CV_32S是一個有符號的32位。 S始終表示有符號整數(有符號字符,有符號短符號,有符號整數) F總是表示浮點數(float,double) U總是表示無符號整數。

枚舉僅在創建或轉換Mat時使用。這是告訴席子是否是所需類型的一種方式,因爲我知道它是不使用模板時的C前任。

我使用C功能完全,並且爲了創建一個圖像,這將是一個錯誤通過如下:

cvCreateImage(mySize,char, nChannels); 

相反,我通過了以下內容:

cvCreateImage(mySize, IPL_DEPTH_8U, nChannels); 

這裏,IPL_DEPTH_8U是該函數使用的標誌。該函數本身具有檢查標誌的開關式語句。標誌的實際值通常是毫無意義的,因爲它通常由條件而不是代數語句來控制。

+0

這是無關緊要的。問題在於opencv2,答案與opencv1 – mkuse 2014-02-16 14:53:50

2

core.hpp,你可以找到以下內容:

/*! 
    A helper class for cv::DataType 

    The class is specialized for each fundamental numerical data type supported by OpenCV. 
    It provides DataDepth<T>::value constant. 
*/ 
template<typename _Tp> class DataDepth {}; 

template<> class DataDepth<bool> { public: enum { value = CV_8U, fmt=(int)'u' }; }; 
template<> class DataDepth<uchar> { public: enum { value = CV_8U, fmt=(int)'u' }; }; 
template<> class DataDepth<schar> { public: enum { value = CV_8S, fmt=(int)'c' }; }; 
template<> class DataDepth<char> { public: enum { value = CV_8S, fmt=(int)'c' }; }; 
template<> class DataDepth<ushort> { public: enum { value = CV_16U, fmt=(int)'w' }; }; 
template<> class DataDepth<short> { public: enum { value = CV_16S, fmt=(int)'s' }; }; 
template<> class DataDepth<int> { public: enum { value = CV_32S, fmt=(int)'i' }; }; 
// this is temporary solution to support 32-bit unsigned integers 
template<> class DataDepth<unsigned> { public: enum { value = CV_32S, fmt=(int)'i' }; }; 
template<> class DataDepth<float> { public: enum { value = CV_32F, fmt=(int)'f' }; }; 
template<> class DataDepth<double> { public: enum { value = CV_64F, fmt=(int)'d' }; }; 
template<typename _Tp> class DataDepth<_Tp*> { public: enum { value = CV_USRTYPE1, fmt=(int)'r' }; }; 

你可以看到,CV_32S是該類型int,不int32_t值。

0

我在OpenCV的CV_8UC1,CV_32SC1等相關代碼中發現了幾個#define。爲了使枚舉工作,OpenCV將附加代碼轉換爲一個參數的簡單數字(即CV_8UC1,CV_16UC2 ...所有代表都由它們各自的數字表示),並在CvMat的定義中突破深度和通道(我猜,Mat在其定義中可能有類似的代碼)。然後,它使用create()爲矩陣分配空間。由於create()是內聯的,我只能猜測它與malloc()或類似。
隨着源代碼從2.4.9改變到3.0.0,我需要稍後發佈更多的證據。請讓我花一點時間來了解更多信息並編輯我的答案。

1

雖然C++沒有定義元素的大小,但問題是假設:對於系統OpenCV運行,大小是已知的。鑑於

cv::Mat m(32,32,CV_32SC1, cv:Scalar(0)); 
std::cout << "size of the element in bytes: " << m.depth() << std::endl; 
std::cout << "or " << m.step.p[ m.dims-1 ]/m.channels() << std::endl; 

那麼你怎麼能確定它是int

試圖調用

int pxVal = m.at<int>(0,0); 

CV_DbgAssert(elemSize()==sizeof(int)); 

當左手經由cv::Mat::flags定義 - 在本例中作爲CV_32SC1相等的預定深度,以

CV_DbgAssert(m.depth() == sizeof(int)) 

or

CV_DbgAssert(4 == sizeof(int)) 

所以如果你成功了,你只剩下字節序。這是cvconfig.h生成(CMake)時檢查。

TL; DR,期待在標題中給出的類型,你會沒事的。

+0

有關。m.depth()不是以字節爲單位,而是爲類型提供EV枚舉值。 CV_8U。 – karsten 2017-09-27 15:43:14

+0

改爲使用elemSize1()。請注意,elemSize()== elemSize1()*通道() – karsten 2017-09-27 15:43:26

4

Miki's answer發展,
在OpenCV的3定義已經轉移到模塊/核心/包括/ opencv2 /核心/ traits.hpp,在這裏你可以找到:

/** @brief A helper class for cv::DataType 

The class is specialized for each fundamental numerical data type supported by OpenCV. It provides 
DataDepth<T>::value constant. 
*/ 
template<typename _Tp> class DataDepth 
{ 
public: 
    enum 
    { 
     value = DataType<_Tp>::depth, 
     fmt = DataType<_Tp>::fmt 
    }; 
}; 



template<int _depth> class TypeDepth 
{ 
    enum { depth = CV_USRTYPE1 }; 
    typedef void value_type; 
}; 

template<> class TypeDepth<CV_8U> 
{ 
    enum { depth = CV_8U }; 
    typedef uchar value_type; 
}; 

template<> class TypeDepth<CV_8S> 
{ 
    enum { depth = CV_8S }; 
    typedef schar value_type; 
}; 

template<> class TypeDepth<CV_16U> 
{ 
    enum { depth = CV_16U }; 
    typedef ushort value_type; 
}; 

template<> class TypeDepth<CV_16S> 
{ 
    enum { depth = CV_16S }; 
    typedef short value_type; 
}; 

template<> class TypeDepth<CV_32S> 
{ 
    enum { depth = CV_32S }; 
    typedef int value_type; 
}; 

template<> class TypeDepth<CV_32F> 
{ 
    enum { depth = CV_32F }; 
    typedef float value_type; 
}; 

template<> class TypeDepth<CV_64F> 
{ 
    enum { depth = CV_64F }; 
    typedef double value_type; 
}; 

大部分案例/編譯器你應該很好使用C++精確數據類型。您不會遇到單字節數據類型(CV_8Uuint8_tCV_8Uint8_t)作爲unambiguously defined in C++的問題。對於float (32bit) and double (64bit)也是如此。但是,這是事實,對於其他數據類型是完全確定你(使用at<>方法時爲例),你應該使用例如使用正確的數據類型:

typedef TypeDepth<CV_WHATEVER_YOU_USED_TO_CREATE_YOUR_MAT>::value_type access_type; 
myMat.at<access_type>(y,x) = 0; 

作爲一個方面說明,我很驚訝他們決定採取這種模糊的方法,而不是簡單地使用確切的數據類型。

因此,關於你的最後一個問題:

我應該,比方說有什麼期望類型,CV_32S

我相信最準確的答案,在OpenCV中3,是:

TypeDepth<CV_32S>::value_type 
+0

偉大的答案謝謝..在大多數情況下,OpenCV不遵循C++誹謗。雖然它是一個夢幻般的計算機視覺庫,但我討厭在C++中處理它。它總是剎車我的代碼,並使我寫代碼,我覺得他們感到羞恥。 – 2016-05-27 13:47:40

+0

你如何訪問value_type?你的例子在OpenCV 3.0中不適用於我,因爲它是一個成員而不是公共的。 – John 2016-10-21 18:40:24

+0

@John:是的,只需將「class」替換爲「struct」即可。用我的OpenCV 2.4.5版本沒有hader,我不得不手動將代碼添加到我的源代碼中。 請注意Mat :: elemSize1()方法,它也顯示了存儲在Mat中的一個數字的字節大小。 – karsten 2017-09-27 15:59:23