日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

OpenCV中的数据结构

發(fā)布時(shí)間:2025/4/16 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OpenCV中的数据结构 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
首先介紹2維點(diǎn)對(duì)Point_,它的是一個(gè)模板類。我們可以直接訪問(wèn)數(shù)據(jù)成員x,y。它不僅定了+、-、==、!=這4個(gè)基本的操作,還定義了點(diǎn)乘、叉乘等操作。特別的這個(gè)類還提供了inside函數(shù)來(lái)判斷一個(gè)點(diǎn)是否在矩形區(qū)域內(nèi)。此外,還定義了一些其他的類型轉(zhuǎn)化函數(shù),比如轉(zhuǎn)化為1.X版本的CvPoint。
為了方便使用,opencv又對(duì)常用的類型進(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)而已。它的常用類型是:
typedef Point3_<int> Point3i;
typedef Point3_<float> Point3f;
typedef Point3_<double> Point3d;


介紹完點(diǎn),就可以介紹Size_了。它也是模板類。
typedef Size_<int> Size2i;
typedef Size2i Size;
typedef Size_<float> Size2f
Size能夠訪問(wèn)的成員變量是height和width。還定義了area函數(shù)來(lái)求面積。其他的操作基本都是類型轉(zhuǎn)化函數(shù)。


下來(lái)介紹Rect_模版類。它是由左上角點(diǎn)和長(zhǎng)度、寬度定義的。在opecv中,一般定義為左開右閉區(qū)間。有意思的是,這個(gè)類竟然也提供了一個(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
  • 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類,這也是一個(gè)模板類,用來(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類,它其實(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_類其實(shí)是用Vec<tp,4>派生下來(lái)的,也就是說(shuō),它是一個(gè)4元組:typedef Scalar_<double> Scalar;
    他通常用來(lái)傳遞像素。


    Range類用來(lái)指定連續(xù)的子序列。比如矩陣的一部分,比較簡(jiǎn)單,我們直接看定義:

    [cpp]?view plaincopy
  • 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)單的類型之后,我們看一個(gè)非常重要的類型;Mat。Mat是opencv中的一種非常重要的數(shù)據(jù)結(jié)構(gòu),當(dāng)剛開始使用時(shí),我僅僅把它當(dāng)做一個(gè)儲(chǔ)存圖像的數(shù)據(jù)結(jié)構(gòu),后來(lái)才慢慢理解,它不僅可以儲(chǔ)存二維矩陣,也可以儲(chǔ)存高維矩陣,這在模式識(shí)別、機(jī)器學(xué)習(xí)中是非常常用的。對(duì)于這類問(wèn)題,我們就沒(méi)有必要自己手動(dòng)分配內(nèi)存了,直接使用它們就可以了。這個(gè)類的內(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
  • 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行,這樣的操作在線性代數(shù)中很常見(jiàn)
    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);


    用源圖像的一部分創(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
  • 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):

    [cpp]?view plaincopy
  • 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)的交互:

    [cpp]?view plaincopy
  • 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ù)了。

    總結(jié)

    以上是生活随笔為你收集整理的OpenCV中的数据结构的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。