openCV內部原始碼C++語法解析
阿新 • • 發佈:2019-02-12
因為看OpenCV原始碼時候,發現自己很是吃力,所以做出如下總結,與大家分享。
接下來我給大家展示一小部分原始碼:···(一定要往後看哦)···
接下來主要對標記0/1/2/3幾處進行詳細說明
語法解析:
0:類模板 + public繼承
1:typedef typename 作用
2:建構函式,引數初始化列表
3:()過載
//子類 0: template<class Op, class VecOp> struct MorphRowFilter : public BaseRowFilter { 1: typedef typename Op::rtype T; 2: MorphRowFilter( int _ksize, int _anchor ) : vecOp(_ksize, _anchor) { ksize = _ksize; anchor = _anchor; } 3: void operator()(const uchar* src, uchar* dst, int width, int cn) { int i, j, k, _ksize = ksize*cn; const T* S = (const T*)src; Op op; T* D = (T*)dst; if( _ksize == cn ) { for( i = 0; i < width*cn; i++ ) D[i] = S[i]; return; } int i0 = vecOp(src, dst, width, cn); width *= cn; for( k = 0; k < cn; k++, S++, D++ ) { for( i = i0; i <= width - cn*2; i += cn*2 ) { const T* s = S + i; T m = s[cn]; for( j = cn*2; j < _ksize; j += cn ) m = op(m, s[j]); D[i] = op(m, s[0]); D[i+cn] = op(m, s[j]); } for( ; i < width; i += cn ) { const T* s = S + i; T m = s[0]; for( j = cn; j < _ksize; j += cn ) m = op(m, s[j]); D[i] = m; } } } VecOp vecOp; };
//父類(基類) class CV_EXPORTS BaseColumnFilter { public: //! the default constructor BaseColumnFilter(); //! the destructor virtual ~BaseColumnFilter(); //! the filtering operator. Must be overrided in the derived classes. The vertical border interpolation is done outside of the class. virtual void operator()(const uchar** src, uchar* dst, int dststep, int dstcount, int width) = 0; //! resets the internal buffers, if any virtual void reset(); int ksize, anchor; };
0 :
template<class Op, class VecOp> struct MorphRowFilter : public BaseRowFilter
類模板 + public繼承
解釋:Op與VecOp只是抽象的名字, 定義了MorphRowFilter的模板類,並且共有繼承了BaseRowFilter
用簡單案例來說明 類模板:
//copyright @ hanshanbuleng #include <iostream> using namespace std; //對於類的宣告來說,我們會遇到兩個或多個類,其功能是相同的,僅僅是資料型別不相同 //如以下,int float 類 //int 型別 class compare_int { public: compare_int(int a, int b) //定義建構函式 { x_ = a; y_ = b; } int max() //利用三目運算子 求最大值 { return (x_ > y_) ? x_ : y_; } int min() //利用三目運算子 求最小值 { return (x_ < y_) ? x_ : y_; } private: int x_; int y_; }; //float 型別 class compare_float { public: compare_float(float a, float b) //定義建構函式 { x_ = a; y_ = b; } int max() //利用三目運算子 求最大值 { return (x_ > y_) ? x_ : y_; } int min() //利用三目運算子 求最小值 { return (x_ < y_) ? x_ : y_; } private: float x_; float y_; }; //類模板 template <class numtype> //template <class numtype> class compare //struct compare 在此處 class與struct可以替換 { public: compare(numtype a, numtype b) //定義建構函式 { x_ = a; y_ = b; } int max() //利用三目運算子 求最大值 { return (x_ > y_) ? x_ : y_; } int min() //利用三目運算子 求最小值 { return (x_ < y_) ? x_ : y_; } private: numtype x_; numtype y_; }; int main() { int flag = 0; //0正確 -1錯誤 int value0; float value1; compare <int> hanshanbuleng0(10, 20); //用類模板的方式進行初始化 value0 = hanshanbuleng0.max(); printf("value0:%d \n", value0); compare <float> hanshanbuleng1(10.0, 20.0); //用類模板的方式進行初始化 value1 = hanshanbuleng1.max(); printf("value0:%f \n", value1); return flag; }
1:
typedef typename Op::rtype T;
typedef typename 作用
語法讓人看著費解 但是當我們知道其含義和用法,就很好理解了
將以上內容進行縮寫:
template<class Op, class VecOp>
{
public:
typedef typename Op::rtype T; //與其等價typedef typename <Op>::rtype T
//...
};
我們刪去不懂的 typename Op::
template<class Op, class VecOp>
class MorphRowFilter
{
public:
typedef rtype T;
//...
};
這樣就看得很清晰了,MorphRowFilter::T是MorphRowFilter的巢狀型別定義,其實際等價於 rtype型別,也就是表明:
使用中宣告 MorphRowFilter ::T INT; <==> rtype INT;
為什麼使用typename關鍵字???
模板型別在例項化之前,編譯器並不知道MorphRowFilter<Op>::T 是什麼東西,事實上一共有三種可能:
靜態資料成員
靜態成員函式
巢狀型別
那麼此時typename的作用就在此時體現出來了————定義就不再模稜兩可。
typedef typename Op::rtype T; //與其等價typedef typename <Op>::rtype T
語句的真是面目是:
typedef建立了存在型別的別名,而typename告訴編譯器MorphRowFilter<Op>::rtype 是一個型別而不是一個成員。
2:
MorphRowFilter( int _ksize, int _anchor ) : vecOp(_ksize, _anchor)
建構函式,引數初始化列表 ===》本程式中是 用引數初始化表 對資料成員初始化
用vecOp(_ksize, _anchor) 對資料成員VecOp vecOp 初始化
我們要想知道VecOp具體是什麼型別,那麼我們需要知道是誰呼叫了
template<class Op, class VecOp> struct MorphRowFilter : public BaseRowFilter
呼叫原始碼擷取:
if( depth == CV_64F )
return Ptr<BaseRowFilter>(new MorphRowFilter< MinOp<double>, ErodeRowVec64f >(ksize, anchor));
==》 Op 對應 double, VecOp 對應 ErodeRowVec64f
引申:
通過顯示呼叫父類的建構函式對父類資料成員進行初始化
使用初始化列表有兩個原因:
原因1.必須這樣做:
《C++ Primer》中提到在以下三種情況下需要使用初始化成員列表:
一、需要初始化的資料成員是物件的情況(這裡包含了繼承情況下,通過顯示呼叫父類的建構函式對父類資料成員進行初始化);
二、需要初始化const修飾的類成員;
三、需要初始化引用成員資料
原因2.效率要求這樣做:
類物件的構造順序顯示,進入建構函式體後,進行的是計算,是對成員變數的賦值操作,
顯然,賦值和初始化是不同的,這樣就體現出了效率差異,如果不用成員初始化類表,
那麼類對自己的類成員分別進行的是一次隱式的預設建構函式的呼叫,和一次賦值操作符的呼叫,
如果是類物件,這樣做效率就得不到保障。
3:
void operator()(const uchar* src, uchar* dst, int width, int cn)
()過載
運算子過載使得指定的運算子不僅實現原來有的功能,而且實現在函式中指定的新功能。
一般格式如下:
函式型別 operator 運算子名稱 (形參表)
{
對運算子的過載處理
}