OPENCV中的数据结构总结
生活随笔
收集整理的這篇文章主要介紹了
OPENCV中的数据结构总结
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
最近在寫(xiě)自己的算法,其實(shí)就是對(duì)一些傳統(tǒng)算法的改進(jìn)。傳統(tǒng)算法可以參考o(jì)pecv的源代碼。在閱讀源代碼的過(guò)程中,我慢慢領(lǐng)會(huì)到了opencv的強(qiáng)大之處,并不是因?yàn)樗鼘?shí)現(xiàn)了各種算法,而是在于它對(duì)于基本數(shù)據(jù)結(jié)構(gòu)的設(shè)計(jì),是得其他人可以很方便的使用這些數(shù)據(jù)結(jié)構(gòu)來(lái)實(shí)現(xiàn)自己的算法。在幫助手冊(cè)中,已經(jīng)對(duì)于這些數(shù)據(jù)結(jié)構(gòu)有比較詳細(xì)的描述了。今天我就為英語(yǔ)不好的孩子們服務(wù)一下,簡(jiǎn)單的介紹一下它們。
首先介紹2維點(diǎn)對(duì)Point_,它的是一個(gè)模板類(lèi)。我們可以直接訪問(wèn)數(shù)據(jù)成員x,y。它不僅定了+、-、==、!=這4個(gè)基本的操作,還定義了點(diǎn)乘、叉乘等操作。特別的這個(gè)類(lèi)還提供了inside函數(shù)來(lái)判斷一個(gè)點(diǎn)是否在矩形區(qū)域內(nèi)。此外,還定義了一些其他的類(lèi)型轉(zhuǎn)化函數(shù),比如轉(zhuǎn)化為1.X版本的CvPoint。
為了方便使用,opencv又對(duì)常用的類(lèi)型進(jìn)行了定義:
typedef Point_<int> Point2i;
typedef Point2i Point;
typedef Point_<float> Point2f;
typedef Point_<double> Point2d;
同理還有Point3_,只不過(guò)它是一個(gè)3維點(diǎn)(x,y,z)而已。它的常用類(lèi)型是:
typedef Point3_<int> Point3i;
typedef Point3_<float> Point3f;
typedef Point3_<double> Point3d;
介紹完點(diǎn),就可以介紹Size_了。它也是模板類(lèi)。
typedef Size_<int> Size2i;
typedef Size2i Size;
typedef Size_<float> Size2f
Size能夠訪問(wèn)的成員變量是height和width。還定義了area函數(shù)來(lái)求面積。其他的操作基本都是類(lèi)型轉(zhuǎn)化函數(shù)。
下來(lái)介紹Rect_模版類(lèi)。它是由左上角點(diǎn)和長(zhǎng)度、寬度定義的。在opecv中,一般定義為左開(kāi)右閉區(qū)間。有意思的是,這個(gè)類(lèi)竟然也提供了一個(gè)Rect+Point的函數(shù),作用是對(duì)矩形的偏移,還有一個(gè)Rect + Size的函數(shù),在左上角不變的情況下,重新調(diào)整矩形的大小。其他的操作還有與&和|,是求兩個(gè)矩形的交集和并集。
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類(lèi),這也是一個(gè)模板類(lèi),用來(lái)記錄一些小的矩形。這些矩形在編譯前大小就固定了:
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類(lèi),它其實(shí)是元素較少的向量。
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;
它支持加、減、數(shù)乘、相等、不等、求范數(shù)等運(yùn)算。
Scalar_類(lèi)其實(shí)是用Vec<tp,4>派生下來(lái)的,也就是說(shuō),它是一個(gè)4元組:typedef Scalar_<double> Scalar;
他通常用來(lái)傳遞像素。
Range類(lèi)用來(lái)指定連續(xù)的子序列。比如矩陣的一部分,比較簡(jiǎn)單,我們直接看定義:
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;?? };??
講完這些簡(jiǎn)單的類(lèi)型之后,我們看一個(gè)非常重要的類(lèi)型;Mat。Mat是opencv中的一種非常重要的數(shù)據(jù)結(jié)構(gòu),當(dāng)剛開(kāi)始使用時(shí),我僅僅把它當(dāng)做一個(gè)儲(chǔ)存圖像的數(shù)據(jù)結(jié)構(gòu),后來(lái)才慢慢理解,它不僅可以?xún)?chǔ)存二維矩陣,也可以?xún)?chǔ)存高維矩陣,這在模式識(shí)別、機(jī)器學(xué)習(xí)中是非常常用的。對(duì)于這類(lèi)問(wèn)題,我們就沒(méi)有必要自己手動(dòng)分配內(nèi)存了,直接使用它們就可以了。這個(gè)類(lèi)的內(nèi)容很多,但opencv的幫助手冊(cè),很好的幫我們理清的其中的內(nèi)容。
其中的核心數(shù)據(jù)成員data的儲(chǔ)存方式在前一篇博客《我的OpenCV學(xué)習(xí)筆記(23):Mat中實(shí)際數(shù)據(jù)是如何保存的》中已經(jīng)討論過(guò)了,這里只做一個(gè)補(bǔ)充,就是多維情況:
int?main(void)?? {?? ????int?sz[]={4,5,6};?? ????Mat?img(3,sz,CV_8U);//3維數(shù)組?? ????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;?? ????//遍歷每個(gè)元素?? ????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;?? }?? 我們建立了一個(gè)3維數(shù)組,數(shù)組的每一維長(zhǎng)度分別為4,5,6。這可以通過(guò)size來(lái)獲得。由于每個(gè)第一維向量中包含5個(gè)第二維的數(shù)組,而每個(gè)第二維數(shù)組中又包含了6個(gè)第三維數(shù)組,所以第一維每增加一步,相當(dāng)于整個(gè)地址移動(dòng)了5*6.所以step[0],等于30.
下面我們主要是看看Mat提供的函數(shù)。
首先是構(gòu)造函數(shù),光構(gòu)造函數(shù)就有很多種,這里介紹幾種常用的方式:
1.使用(nrows, ncols, type),初始化2維矩陣
// 創(chuàng)建一個(gè)7*7的2通道浮點(diǎn)矩陣,通常這樣的矩陣用來(lái)表示復(fù)矩陣
Mat M(7,7,CV_32FC2,Scalar(1,3));
//改變?yōu)?00*60的15通道uchar矩陣,原先的數(shù)據(jù)將會(huì)被釋放
M.create(100,60,CV_8UC(15));
創(chuàng)建高維矩陣
//創(chuàng)建100*100*100的3維矩陣
int sz[] = {100, 100, 100};
Mat bigCube(3, sz, CV_8U, Scalar::all(0));
下面是一些簡(jiǎn)單的對(duì)整行、整列的操作
// 第5行*3 + 第3行,這樣的操作在線(xiàn)性代數(shù)中很常見(jiàn)
M.row(3) = M.row(3) + M.row(5)*3;
// 把第7列拷貝到第1列
// M.col(1) = M.col(7); // 不能這樣寫(xiě)
Mat M1 = M.col(1);
M.col(7).copyTo(M1);
用源圖像的一部分創(chuàng)建新圖像
// 創(chuàng)建一個(gè)320*240的圖像
Mat img(Size(320,240),CV_8UC3);
// 選擇感興趣區(qū)域
Mat roi(img, Rect(10,10,100,100));
// 將區(qū)域改為綠色,原圖像也會(huì)發(fā)生修改
roi = Scalar(0,255,0);
B是A的[1,3)列,對(duì)B的修改會(huì)影響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方法。
對(duì)于初始化Mat,還有其他的一些方法:
比如Matlab風(fēng)格的 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);
如果是處理“外來(lái)”的數(shù)據(jù),那么則在構(gòu)造函數(shù)中加上data則會(huì)非常方便的將外來(lái)數(shù)據(jù)轉(zhuǎn)化為Mat結(jié)構(gòu): 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();??
特別的,對(duì)于與opencv1.X中的IplImage結(jié)構(gòu)的交互: IplImage*?img?=?cvLoadImage("greatwave.jpg",?1);?? Mat?mtx(img);?//?convert?IplImage*?->?Mat?? CvMat?oldmat?=?mtx;?//?convert?Mat?->?CvMat??
說(shuō)完了,構(gòu)造、初始化,應(yīng)該討論元素訪問(wèn)的方法,這個(gè)在之前的博客中也有提過(guò)《我的OpenCV學(xué)習(xí)筆記(二):操作每個(gè)像素》這里就不再重復(fù)了。
首先介紹2維點(diǎn)對(duì)Point_,它的是一個(gè)模板類(lèi)。我們可以直接訪問(wèn)數(shù)據(jù)成員x,y。它不僅定了+、-、==、!=這4個(gè)基本的操作,還定義了點(diǎn)乘、叉乘等操作。特別的這個(gè)類(lèi)還提供了inside函數(shù)來(lái)判斷一個(gè)點(diǎn)是否在矩形區(qū)域內(nèi)。此外,還定義了一些其他的類(lèi)型轉(zhuǎn)化函數(shù),比如轉(zhuǎn)化為1.X版本的CvPoint。
為了方便使用,opencv又對(duì)常用的類(lèi)型進(jìn)行了定義:
typedef Point_<int> Point2i;
typedef Point2i Point;
typedef Point_<float> Point2f;
typedef Point_<double> Point2d;
同理還有Point3_,只不過(guò)它是一個(gè)3維點(diǎn)(x,y,z)而已。它的常用類(lèi)型是:
typedef Point3_<int> Point3i;
typedef Point3_<float> Point3f;
typedef Point3_<double> Point3d;
介紹完點(diǎn),就可以介紹Size_了。它也是模板類(lèi)。
typedef Size_<int> Size2i;
typedef Size2i Size;
typedef Size_<float> Size2f
Size能夠訪問(wèn)的成員變量是height和width。還定義了area函數(shù)來(lái)求面積。其他的操作基本都是類(lèi)型轉(zhuǎn)化函數(shù)。
下來(lái)介紹Rect_模版類(lèi)。它是由左上角點(diǎn)和長(zhǎng)度、寬度定義的。在opecv中,一般定義為左開(kāi)右閉區(qū)間。有意思的是,這個(gè)類(lèi)竟然也提供了一個(gè)Rect+Point的函數(shù),作用是對(duì)矩形的偏移,還有一個(gè)Rect + Size的函數(shù),在左上角不變的情況下,重新調(diào)整矩形的大小。其他的操作還有與&和|,是求兩個(gè)矩形的交集和并集。
除了基本的矩形之外,opecv還提供了一個(gè)可以旋轉(zhuǎn)的矩形RotatedRect,它是由中心、變長(zhǎng)、旋轉(zhuǎn)角度決定的。你可以訪問(wèn)它的這三個(gè)成員,也可以使用points函數(shù)返回它的4個(gè)頂點(diǎn),使用boundingRect求出它的外接矩形(非旋轉(zhuǎn)),下面是一個(gè)例子:
[cpp]?view plaincopy
下面介紹Matx類(lèi),這也是一個(gè)模板類(lèi),用來(lái)記錄一些小的矩形。這些矩形在編譯前大小就固定了:
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類(lèi),它其實(shí)是元素較少的向量。
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;
它支持加、減、數(shù)乘、相等、不等、求范數(shù)等運(yùn)算。
Scalar_類(lèi)其實(shí)是用Vec<tp,4>派生下來(lái)的,也就是說(shuō),它是一個(gè)4元組:typedef Scalar_<double> Scalar;
他通常用來(lái)傳遞像素。
Range類(lèi)用來(lái)指定連續(xù)的子序列。比如矩陣的一部分,比較簡(jiǎn)單,我們直接看定義:
[cpp]?view plaincopy
講完這些簡(jiǎn)單的類(lèi)型之后,我們看一個(gè)非常重要的類(lèi)型;Mat。Mat是opencv中的一種非常重要的數(shù)據(jù)結(jié)構(gòu),當(dāng)剛開(kāi)始使用時(shí),我僅僅把它當(dāng)做一個(gè)儲(chǔ)存圖像的數(shù)據(jù)結(jié)構(gòu),后來(lái)才慢慢理解,它不僅可以?xún)?chǔ)存二維矩陣,也可以?xún)?chǔ)存高維矩陣,這在模式識(shí)別、機(jī)器學(xué)習(xí)中是非常常用的。對(duì)于這類(lèi)問(wèn)題,我們就沒(méi)有必要自己手動(dòng)分配內(nèi)存了,直接使用它們就可以了。這個(gè)類(lèi)的內(nèi)容很多,但opencv的幫助手冊(cè),很好的幫我們理清的其中的內(nèi)容。
其中的核心數(shù)據(jù)成員data的儲(chǔ)存方式在前一篇博客《我的OpenCV學(xué)習(xí)筆記(23):Mat中實(shí)際數(shù)據(jù)是如何保存的》中已經(jīng)討論過(guò)了,這里只做一個(gè)補(bǔ)充,就是多維情況:
[cpp]?view plaincopy
下面我們主要是看看Mat提供的函數(shù)。
首先是構(gòu)造函數(shù),光構(gòu)造函數(shù)就有很多種,這里介紹幾種常用的方式:
1.使用(nrows, ncols, type),初始化2維矩陣
// 創(chuàng)建一個(gè)7*7的2通道浮點(diǎn)矩陣,通常這樣的矩陣用來(lái)表示復(fù)矩陣
Mat M(7,7,CV_32FC2,Scalar(1,3));
//改變?yōu)?00*60的15通道uchar矩陣,原先的數(shù)據(jù)將會(huì)被釋放
M.create(100,60,CV_8UC(15));
創(chuàng)建高維矩陣
//創(chuàng)建100*100*100的3維矩陣
int sz[] = {100, 100, 100};
Mat bigCube(3, sz, CV_8U, Scalar::all(0));
下面是一些簡(jiǎn)單的對(duì)整行、整列的操作
// 第5行*3 + 第3行,這樣的操作在線(xiàn)性代數(shù)中很常見(jiàn)
M.row(3) = M.row(3) + M.row(5)*3;
// 把第7列拷貝到第1列
// M.col(1) = M.col(7); // 不能這樣寫(xiě)
Mat M1 = M.col(1);
M.col(7).copyTo(M1);
用源圖像的一部分創(chuàng)建新圖像
// 創(chuàng)建一個(gè)320*240的圖像
Mat img(Size(320,240),CV_8UC3);
// 選擇感興趣區(qū)域
Mat roi(img, Rect(10,10,100,100));
// 將區(qū)域改為綠色,原圖像也會(huì)發(fā)生修改
roi = Scalar(0,255,0);
B是A的[1,3)列,對(duì)B的修改會(huì)影響A
[cpp]?view plaincopy
如果需要深拷貝,則使用clone方法。
對(duì)于初始化Mat,還有其他的一些方法:
比如Matlab風(fēng)格的 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);
如果是處理“外來(lái)”的數(shù)據(jù),那么則在構(gòu)造函數(shù)中加上data則會(huì)非常方便的將外來(lái)數(shù)據(jù)轉(zhuǎn)化為Mat結(jié)構(gòu):
[cpp]?view plaincopy
特別的,對(duì)于與opencv1.X中的IplImage結(jié)構(gòu)的交互:
[cpp]?view plaincopy
說(shuō)完了,構(gòu)造、初始化,應(yīng)該討論元素訪問(wèn)的方法,這個(gè)在之前的博客中也有提過(guò)《我的OpenCV學(xué)習(xí)筆記(二):操作每個(gè)像素》這里就不再重復(fù)了。
總結(jié)
以上是生活随笔為你收集整理的OPENCV中的数据结构总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 从GBIP到PXI 的发展简史
- 下一篇: MAT类如何存储数据