OPENCV中的数据结构总结
生活随笔
收集整理的這篇文章主要介紹了
OPENCV中的数据结构总结
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
最近在寫自己的算法,其實就是對一些傳統算法的改進。傳統算法可以參考opecv的源代碼。在閱讀源代碼的過程中,我慢慢領會到了opencv的強大之處,并不是因為它實現了各種算法,而是在于它對于基本數據結構的設計,是得其他人可以很方便的使用這些數據結構來實現自己的算法。在幫助手冊中,已經對于這些數據結構有比較詳細的描述了。今天我就為英語不好的孩子們服務一下,簡單的介紹一下它們。
首先介紹2維點對Point_,它的是一個模板類。我們可以直接訪問數據成員x,y。它不僅定了+、-、==、!=這4個基本的操作,還定義了點乘、叉乘等操作。特別的這個類還提供了inside函數來判斷一個點是否在矩形區域內。此外,還定義了一些其他的類型轉化函數,比如轉化為1.X版本的CvPoint。
為了方便使用,opencv又對常用的類型進行了定義:
typedef Point_<int> Point2i;
typedef Point2i Point;
typedef Point_<float> Point2f;
typedef Point_<double> Point2d;
同理還有Point3_,只不過它是一個3維點(x,y,z)而已。它的常用類型是:
typedef Point3_<int> Point3i;
typedef Point3_<float> Point3f;
typedef Point3_<double> Point3d;
介紹完點,就可以介紹Size_了。它也是模板類。
typedef Size_<int> Size2i;
typedef Size2i Size;
typedef Size_<float> Size2f
Size能夠訪問的成員變量是height和width。還定義了area函數來求面積。其他的操作基本都是類型轉化函數。
下來介紹Rect_模版類。它是由左上角點和長度、寬度定義的。在opecv中,一般定義為左開右閉區間。有意思的是,這個類竟然也提供了一個Rect+Point的函數,作用是對矩形的偏移,還有一個Rect + Size的函數,在左上角不變的情況下,重新調整矩形的大小。其他的操作還有與&和|,是求兩個矩形的交集和并集。
int?main(void)?? {?? ????Mat?bg(200,200,CV_8UC3,Scalar(0));?? ????imshow("",bg);?? ????RotatedRect?rRect(Point2f(100,100),Size(100,100),40);??? ????Point2f?vertices[4];?? ????rRect.points(vertices);?? ????for(int?i?=?0;?i?<?4;++i)?? ????????line(bg,vertices[i],vertices[(i+1)%4],Scalar(0,255,0));?? ????Rect?brect?=?rRect.boundingRect();?? ????rectangle(bg,brect,Scalar(255,0,0));?? ????imshow("",bg);?? ????waitKey();?? ????return?0;?? }??
下面介紹Matx類,這也是一個模板類,用來記錄一些小的矩形。這些矩形在編譯前大小就固定了:
typedef Matx<float, 1, 2> Matx12f;
typedef Matx<double, 1, 2> Matx12d;
...
typedef Matx<float, 1, 6> Matx16f;
typedef Matx<double, 1, 6> Matx16d;
typedef Matx<float, 2, 1> Matx21f;
typedef Matx<double, 2, 1> Matx21d;
...
typedef Matx<float, 6, 1> Matx61f;
typedef Matx<double, 6, 1> Matx61d;
typedef Matx<float, 2, 2> Matx22f;
typedef Matx<double, 2, 2> Matx22d;
...
typedef Matx<float, 6, 6> Matx66f;
typedef Matx<double, 6, 6> Matx66d;
如果要使用靈活的矩形,還是用Mat吧。
下面介紹Vec類,它其實是元素較少的向量。
typedef Vec<uchar, 2> Vec2b;
typedef Vec<uchar, 3> Vec3b;
typedef Vec<uchar, 4> Vec4b;
typedef Vec<short, 2> Vec2s;
typedef Vec<short, 3> Vec3s;
typedef Vec<short, 4> Vec4s;
typedef Vec<int, 2> Vec2i;
typedef Vec<int, 3> Vec3i;
typedef Vec<int, 4> Vec4i;
typedef Vec<float, 2> Vec2f;
typedef Vec<float, 3> Vec3f;
typedef Vec<float, 4> Vec4f;
typedef Vec<float, 6> Vec6f;
typedef Vec<double, 2> Vec2d;
typedef Vec<double, 3> Vec3d;
typedef Vec<double, 4> Vec4d;
typedef Vec<double, 6> Vec6d;
它支持加、減、數乘、相等、不等、求范數等運算。
Scalar_類其實是用Vec<tp,4>派生下來的,也就是說,它是一個4元組:typedef Scalar_<double> Scalar;
他通常用來傳遞像素。
Range類用來指定連續的子序列。比如矩陣的一部分,比較簡單,我們直接看定義:
class?CV_EXPORTS?Range?? {?? public:?? ????Range();?? ????Range(int?_start,?int?_end);?? ????Range(const?CvSlice&?slice);?? ????int?size()?const;?? ????bool?empty()?const;?? ????static?Range?all();?? ????operator?CvSlice()?const;?? ?? ????int?start,?end;?? };??
講完這些簡單的類型之后,我們看一個非常重要的類型;Mat。Mat是opencv中的一種非常重要的數據結構,當剛開始使用時,我僅僅把它當做一個儲存圖像的數據結構,后來才慢慢理解,它不僅可以儲存二維矩陣,也可以儲存高維矩陣,這在模式識別、機器學習中是非常常用的。對于這類問題,我們就沒有必要自己手動分配內存了,直接使用它們就可以了。這個類的內容很多,但opencv的幫助手冊,很好的幫我們理清的其中的內容。
其中的核心數據成員data的儲存方式在前一篇博客《我的OpenCV學習筆記(23):Mat中實際數據是如何保存的》中已經討論過了,這里只做一個補充,就是多維情況:
int?main(void)?? {?? ????int?sz[]={4,5,6};?? ????Mat?img(3,sz,CV_8U);//3維數組?? ????cout<<img.dims<<endl;?? ????cout<<img.size[0]<<endl;?? ????cout<<img.size[1]<<endl;?? ????cout<<img.size[2]<<endl;?? ?? ????cout<<img.step[0]<<endl;?? ????cout<<img.step[1]<<endl;?? ????cout<<img.step[2]<<endl;?? ????//遍歷每個元素?? ????for(int?i?=?0;?i?<?4;++i)?? ????{?? ????????for(int?j?=?0;?j?<?5;++j)?? ????????{?? ????????????for(int?k?=?0;?k?<?6;++k)?? ????????????{?? ????????????????cout<<(int)*(B.data?+?B.step[0]*i?+?B.step[1]*j?+?B.step[2]*k)<<endl;?? ????????????}?? ????????}?? ????}?? ????return?0;?? }?? 我們建立了一個3維數組,數組的每一維長度分別為4,5,6。這可以通過size來獲得。由于每個第一維向量中包含5個第二維的數組,而每個第二維數組中又包含了6個第三維數組,所以第一維每增加一步,相當于整個地址移動了5*6.所以step[0],等于30.
下面我們主要是看看Mat提供的函數。
首先是構造函數,光構造函數就有很多種,這里介紹幾種常用的方式:
1.使用(nrows, ncols, type),初始化2維矩陣
// 創建一個7*7的2通道浮點矩陣,通常這樣的矩陣用來表示復矩陣
Mat M(7,7,CV_32FC2,Scalar(1,3));
//改變為100*60的15通道uchar矩陣,原先的數據將會被釋放
M.create(100,60,CV_8UC(15));
創建高維矩陣
//創建100*100*100的3維矩陣
int sz[] = {100, 100, 100};
Mat bigCube(3, sz, CV_8U, Scalar::all(0));
下面是一些簡單的對整行、整列的操作
// 第5行*3 + 第3行,這樣的操作在線性代數中很常見
M.row(3) = M.row(3) + M.row(5)*3;
// 把第7列拷貝到第1列
// M.col(1) = M.col(7); // 不能這樣寫
Mat M1 = M.col(1);
M.col(7).copyTo(M1);
用源圖像的一部分創建新圖像
// 創建一個320*240的圖像
Mat img(Size(320,240),CV_8UC3);
// 選擇感興趣區域
Mat roi(img, Rect(10,10,100,100));
// 將區域改為綠色,原圖像也會發生修改
roi = Scalar(0,255,0);
B是A的[1,3)列,對B的修改會影響A int?main(void)?? {?? ????Mat?A?=?Mat::eye(5,5,CV_8U);?? ?? ????Mat?B?=?A(Range::all(),Range(1,3));?? ????B.setTo(100);?? ????for(int?i?=?0;?i?<?5;++i)?? ????{?? ????????for(int?j?=?0;?j?<?5;++j)?? ????????{?? ????????????cout<<(int)A.at<uchar>(i,j)<<endl;?? ????????}?? ????}?? ????return?0;?? }??
如果需要深拷貝,則使用clone方法。
對于初始化Mat,還有其他的一些方法:
比如Matlab風格的 zeros(), ones(), eye():
M += Mat::eye(M.rows, M.cols, CV_64F);
Mat M = (Mat_<double>(3,3) << 1, 0, 0, 0, 1, 0, 0, 0, 1);
如果是處理“外來”的數據,那么則在構造函數中加上data則會非常方便的將外來數據轉化為Mat結構: void?process_video_frame(const?unsigned?char*?pixels,int?width,?int?height,?int?step)?? {?? ????Mat?img(height,?width,?CV_8UC3,?pixels,?step);?? ????GaussianBlur(img,?img,?Size(7,7),?1.5,?1.5);?? }?? ?? double?m[3][3]?=?{{a,?b,?c},?{d,?e,?f},?{g,?h,?i}};?? Mat?M?=?Mat(3,?3,?CV_64F,?m).inv();??
特別的,對于與opencv1.X中的IplImage結構的交互: IplImage*?img?=?cvLoadImage("greatwave.jpg",?1);?? Mat?mtx(img);?//?convert?IplImage*?->?Mat?? CvMat?oldmat?=?mtx;?//?convert?Mat?->?CvMat??
說完了,構造、初始化,應該討論元素訪問的方法,這個在之前的博客中也有提過《我的OpenCV學習筆記(二):操作每個像素》這里就不再重復了。
首先介紹2維點對Point_,它的是一個模板類。我們可以直接訪問數據成員x,y。它不僅定了+、-、==、!=這4個基本的操作,還定義了點乘、叉乘等操作。特別的這個類還提供了inside函數來判斷一個點是否在矩形區域內。此外,還定義了一些其他的類型轉化函數,比如轉化為1.X版本的CvPoint。
為了方便使用,opencv又對常用的類型進行了定義:
typedef Point_<int> Point2i;
typedef Point2i Point;
typedef Point_<float> Point2f;
typedef Point_<double> Point2d;
同理還有Point3_,只不過它是一個3維點(x,y,z)而已。它的常用類型是:
typedef Point3_<int> Point3i;
typedef Point3_<float> Point3f;
typedef Point3_<double> Point3d;
介紹完點,就可以介紹Size_了。它也是模板類。
typedef Size_<int> Size2i;
typedef Size2i Size;
typedef Size_<float> Size2f
Size能夠訪問的成員變量是height和width。還定義了area函數來求面積。其他的操作基本都是類型轉化函數。
下來介紹Rect_模版類。它是由左上角點和長度、寬度定義的。在opecv中,一般定義為左開右閉區間。有意思的是,這個類竟然也提供了一個Rect+Point的函數,作用是對矩形的偏移,還有一個Rect + Size的函數,在左上角不變的情況下,重新調整矩形的大小。其他的操作還有與&和|,是求兩個矩形的交集和并集。
除了基本的矩形之外,opecv還提供了一個可以旋轉的矩形RotatedRect,它是由中心、變長、旋轉角度決定的。你可以訪問它的這三個成員,也可以使用points函數返回它的4個頂點,使用boundingRect求出它的外接矩形(非旋轉),下面是一個例子:
[cpp]?view plaincopy
下面介紹Matx類,這也是一個模板類,用來記錄一些小的矩形。這些矩形在編譯前大小就固定了:
typedef Matx<float, 1, 2> Matx12f;
typedef Matx<double, 1, 2> Matx12d;
...
typedef Matx<float, 1, 6> Matx16f;
typedef Matx<double, 1, 6> Matx16d;
typedef Matx<float, 2, 1> Matx21f;
typedef Matx<double, 2, 1> Matx21d;
...
typedef Matx<float, 6, 1> Matx61f;
typedef Matx<double, 6, 1> Matx61d;
typedef Matx<float, 2, 2> Matx22f;
typedef Matx<double, 2, 2> Matx22d;
...
typedef Matx<float, 6, 6> Matx66f;
typedef Matx<double, 6, 6> Matx66d;
如果要使用靈活的矩形,還是用Mat吧。
下面介紹Vec類,它其實是元素較少的向量。
typedef Vec<uchar, 2> Vec2b;
typedef Vec<uchar, 3> Vec3b;
typedef Vec<uchar, 4> Vec4b;
typedef Vec<short, 2> Vec2s;
typedef Vec<short, 3> Vec3s;
typedef Vec<short, 4> Vec4s;
typedef Vec<int, 2> Vec2i;
typedef Vec<int, 3> Vec3i;
typedef Vec<int, 4> Vec4i;
typedef Vec<float, 2> Vec2f;
typedef Vec<float, 3> Vec3f;
typedef Vec<float, 4> Vec4f;
typedef Vec<float, 6> Vec6f;
typedef Vec<double, 2> Vec2d;
typedef Vec<double, 3> Vec3d;
typedef Vec<double, 4> Vec4d;
typedef Vec<double, 6> Vec6d;
它支持加、減、數乘、相等、不等、求范數等運算。
Scalar_類其實是用Vec<tp,4>派生下來的,也就是說,它是一個4元組:typedef Scalar_<double> Scalar;
他通常用來傳遞像素。
Range類用來指定連續的子序列。比如矩陣的一部分,比較簡單,我們直接看定義:
[cpp]?view plaincopy
講完這些簡單的類型之后,我們看一個非常重要的類型;Mat。Mat是opencv中的一種非常重要的數據結構,當剛開始使用時,我僅僅把它當做一個儲存圖像的數據結構,后來才慢慢理解,它不僅可以儲存二維矩陣,也可以儲存高維矩陣,這在模式識別、機器學習中是非常常用的。對于這類問題,我們就沒有必要自己手動分配內存了,直接使用它們就可以了。這個類的內容很多,但opencv的幫助手冊,很好的幫我們理清的其中的內容。
其中的核心數據成員data的儲存方式在前一篇博客《我的OpenCV學習筆記(23):Mat中實際數據是如何保存的》中已經討論過了,這里只做一個補充,就是多維情況:
[cpp]?view plaincopy
下面我們主要是看看Mat提供的函數。
首先是構造函數,光構造函數就有很多種,這里介紹幾種常用的方式:
1.使用(nrows, ncols, type),初始化2維矩陣
// 創建一個7*7的2通道浮點矩陣,通常這樣的矩陣用來表示復矩陣
Mat M(7,7,CV_32FC2,Scalar(1,3));
//改變為100*60的15通道uchar矩陣,原先的數據將會被釋放
M.create(100,60,CV_8UC(15));
創建高維矩陣
//創建100*100*100的3維矩陣
int sz[] = {100, 100, 100};
Mat bigCube(3, sz, CV_8U, Scalar::all(0));
下面是一些簡單的對整行、整列的操作
// 第5行*3 + 第3行,這樣的操作在線性代數中很常見
M.row(3) = M.row(3) + M.row(5)*3;
// 把第7列拷貝到第1列
// M.col(1) = M.col(7); // 不能這樣寫
Mat M1 = M.col(1);
M.col(7).copyTo(M1);
用源圖像的一部分創建新圖像
// 創建一個320*240的圖像
Mat img(Size(320,240),CV_8UC3);
// 選擇感興趣區域
Mat roi(img, Rect(10,10,100,100));
// 將區域改為綠色,原圖像也會發生修改
roi = Scalar(0,255,0);
B是A的[1,3)列,對B的修改會影響A
[cpp]?view plaincopy
如果需要深拷貝,則使用clone方法。
對于初始化Mat,還有其他的一些方法:
比如Matlab風格的 zeros(), ones(), eye():
M += Mat::eye(M.rows, M.cols, CV_64F);
Mat M = (Mat_<double>(3,3) << 1, 0, 0, 0, 1, 0, 0, 0, 1);
如果是處理“外來”的數據,那么則在構造函數中加上data則會非常方便的將外來數據轉化為Mat結構:
[cpp]?view plaincopy
特別的,對于與opencv1.X中的IplImage結構的交互:
[cpp]?view plaincopy
說完了,構造、初始化,應該討論元素訪問的方法,這個在之前的博客中也有提過《我的OpenCV學習筆記(二):操作每個像素》這里就不再重復了。
總結
以上是生活随笔為你收集整理的OPENCV中的数据结构总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 从GBIP到PXI 的发展简史
- 下一篇: MAT类如何存储数据