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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

OpenCV系列(三):Mat详解

發布時間:2025/3/21 编程问答 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OpenCV系列(三):Mat详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Mat類是OpenCV最基本的一個數據類型,它可以表示一個多維的多通道的數組。Mat常用來存儲圖像,包括單通道二維數組——灰度圖,多通道二維數組——彩色圖。當然也可以用來存儲點云,直方圖等等,對于高維的數組可以考慮存儲在SparseMat中。對于一個Mat對象M,其數據布局是由M.step[]決定的,數據存放在M.data里面,假設M有d維,則數據的尋址方式為:

addr(Mi0,...,id?1)=M.data+i0?M.step[0]+...+id?1?M.step[d?1]addr(Mi0,...,id?1)=M.data+i0?M.step[0]+...+id?1?M.step[d?1]

例如ImgImg是一個二維三通道矩陣,則,

addr(Imgi0,i1)=M.data+i0?M.step[0]+i1?M.step[1]addr(Imgi0,i1)=M.data+i0?M.step[0]+i1?M.step[1]

這里需要說明的是各個維度的步長滿足如下關系:M.step[i] >= M.step[i+1]*M.size[i+1],也就是二維數組的數據的存放是一行一行的,三維數組數據存放是一面一面的。

下面給出OpenCV中Mat類的一個粗略定義如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class CV_EXPORTS Mat { public:// ... a lot of methods ....../*! includes several bit-fields:- the magic signature- continuity flag- depth- number of channels*/int flags;//! the array dimensionality, >= 2int dims;//! the number of rows and columns or (-1, -1) when the array has more than 2 dimensionsint rows, cols;//! pointer to the datauchar* data;//! pointer to the reference counter;// when array points to user-allocated data, the pointer is NULLint* refcount;// other members... };

構造Mat的方法

構造Mat的方式有很多種,下面把常用的方法一一列出:

  • 使用構造函數Mat(nrows, ncols, type[, fillValue]),例如,

    1 2 // 構建3×2的4通道8位矩陣,每個元素初始值為(1,2,3,4) Mat M(3,2,CV_8UC4,Scalar(1,2,3,4));

  • 使用M.create(nrows,ncols,type),例如,

    1 2 //構建100×100的10通道8位矩陣 M.create(100,100,CV_8UC(10))

  • 構建多維的矩陣,

    1 2 3 //構建一個100×100×100的8位三維矩陣 int sz[] = {100,100,100} Mat Cube(3, sz, CV_32F, Scalar::all(0))

  • 使用復制構造函數或者賦值操作符

    1 2 Mat A(B); Mat C = B;

  • 單獨對矩陣的某一行某一列進行操作

    1 2 3 4 5 6 //第4行加上第6行的3倍賦值給第4行 M.row(3) = M.row(3) + M.row(5)*3;// 把第8列拷貝到第2列,通過 M.col(1) = M.col(7)是不起作用的,應該: Mat M1 = M.col(1); M.col(7).copyTo(M1);

  • 構建矩陣的ROI區域,單獨操作ROI區域的值

    1 2 3 Mat img(Size(320,240),CV_8UC3); Mat roi(img, Rect(10,10,100,100)); roi = Scalar(0,255,0);

    確定矩陣在原矩陣中的相對位置,使用locateROI,

    1 2 3 4 5 6 Mat A = Mat::eye(10, 10, CV_32S); Mat B = A(Range::all(), Range(1, 3)); Mat C = B(Range(5, 9), Range::all()); Size size; Point ofs; //得出ofs為(1,5),size為(10,10),為什么是(10,10)?目前沒搞清楚 C.locateROI(size, ofs);

  • 對于外部數據輸入,進行初始化

    1 2 3 4 5 6 7 8 9 10 //外部輸入一個一維數組 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[2][3] = { {1, 2, 3}, {4, 5, 6} }; Mat M = Mat(2, 3, CV_64F, m);

  • IplImage,CvMat和Mat相互轉換
    1 2 3 4 5 IplImage* img = cvLoadImage("lena.jpg", 1); Mat mtx(img); // IplImage* -> Mat IplImage* img1 = mtx; //Mat -> IplImage* CvMat oldmat = mtx; // Mat -> CvMat Mat mtx1(oldmat); //CvMat -> Mat
  • 類似Matlab方式和<<賦值

    1 2 3 4 5 6 7 //類似Matlab中的單位矩陣等 M = Mat::ones(10, 10, CV_64F); M = Mat::eye(10, 10, CV_64F); M = Mat::zeros(10, 10, CV_64F);//使用`Mat_`和`<<`配合 Mat M = (Mat_<double>(3,3) << 1, 0, 0, 0, 1, 0, 0, 0, 1);

  • 獲取Mat元素的方法

    構造好矩陣后,剩下一個很重要的事情就是如何快速準確的獲取矩陣Mat中的元素,下面列出幾種常用的獲取Mat中的元素方法:

  • 使用M.at(i,j)

    1 M.at<double>(i,j)

  • 對于二維矩陣,可以采取逐行獲取的方式:

    1 2 3 4 5 6 7 double sum=0; for(int i = 0; i < M.rows; i++) {const double* Mi = M.ptr<double>(i);for(int j = 0; j < M.cols; j++)sum += std::max(Mi[j], 0.); }

    對于不在乎矩陣的形狀,只是簡單的遍歷矩陣的元素的,可以采用更快速的方法,首先檢查元素排列是否連續,如果是,可以看成一個一維數組訪問。

    1 2 3 4 5 6 7 8 9 10 11 12 13 double sum=0; int cols = M.cols, rows = M.rows; if(M.isContinuous()) {cols *= rows;rows = 1; } for(int i = 0; i < rows; i++) {const double* Mi = M.ptr<double>(i);for(int j = 0; j < cols; j++)sum += std::max(Mi[j], 0.); }

  • 仿照STL中,使用迭代器訪問:

    1 2 3 4 double sum=0;MatConstIterator_<double> it = M.begin<double>(), it_end = M.end<double>();for(; it != it_end; ++it)sum += std::max(*it, 0.);

  • 這個矩陣的迭代器可以傳給STL的算法,例如std::sort()。

    Mat提供的常用成員函數

  • 賦值操作符’=’
    除了普通的矩陣賦值外,如果一個Scalar賦值給一個Mat,則表示把Mat的所有元素賦值為這個Scalar值。

  • 矩陣的取行列及對角線操作
    A.row(i),A.col(j)這些操作返回矩陣A的第i行和第j列。A.rowRange(m,n)和A.colRange(m,n)分別取的是A的第m行到第n行(包括m行,不包括n行)和A的第m列到第n列(包括m列,不包括n列)。這里需要注意一個問題,對于

    1 A.row(i) = A.row(j)

    這一操作,并不能把第j行復制到第i行,因為A.row()返回的只是矩陣的頭,以上操作僅僅相當于兩個指針的操作,所指內存其實是沒有發生變化的。如果想把第j行復制到第i行,可以

    1 A.row(j).copyTo(A(i))

    當右邊的矩陣發生操作后,是可以賦值的,比如

    1 2 A.row(i) = A.row(j)*a A.row(i) = A.row(j) + Scalar(0,0,0);

    A.diag(i)取的是矩陣的對角線,這里i=0代表最中間的對角線,i=1是偏右上一行的對角線,i=-1是左下一行的對角線,例如:

    1 2 3 Mat A = (Mat_<float>(3,3)<< 1,9,3,7,5,0,7,3,9);

    A.diag(0)取得是{1,5,9},A.diag(1)取得是{9,0},A.diag(-1)取得是{7,3}。

  • 復制函數

    1 2 3 A.clone()//返回A的拷貝。 A.copyTo(B)//執行把A拷貝到B矩陣中。 A.copyTo(B,mask)//進拷貝mask對應的部分

  • 轉換矩陣元素的數據類型

    1 2 A.converTo(B,tpye,scale)//把A的類型轉換為type并且按照scale縮放A到B矩陣中 assignTo(A,type)//更改A的元素數據類型

  • 設定矩陣的值

    1 A.setTo(s)//把A中所有的值賦值為s

  • 更改矩陣的通道數和行數

    A.reshape()改變通道數,A.resize()改變行數。其中A.reshape()這個操作不改變roscolschannels的個數,僅僅相當于重構這些元素,例如:

    1 2 3 vector<Point> vec;//vec是N個Point Mat pointMat = Mat(vec); //pointMat是一個三通道的N×1的矩陣 pointMat.reshape(1)//pointMat變為一個單通道N×3的矩陣

    更改矩陣的行數如下

    1 A.resize(sz) //A變為sz行

  • locateROI和adjustROI

    這兩個函數主要是對submatrix的操作,即通過A.row(),A(Range(i,j),Range::all())等操作獲得的submatrix在原始矩陣中位置。例如:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 Mat A = (Mat_<float>(3,3)<< 1,9,3,7,5,0,7,3,9); Mat B = A(Range(0,2),Range(1,3));//B變為 {9,3,// 5,0} Size sz; Point p1; B.locateROI(sz, p1); cout<<sz<<" "<<p1<<endl; //sz是原矩陣的大小3×3,p1是B在A中位置(1,0) B.adjustROI(0,1,0,0); //四個參數分別是上下左右平移的像素數,這里是把B向下平移1行,//最后得出B為{9,3,// 5,0,// 3,9} cout<<B<<endl;

  • Mat的各項屬性

    1 2 3 4 5 6 7 8 9 10 11 12 A.total() //元素的個數 A.elemSize() //元素的大小,如果是8UC3的話,返回3*sizeof(uchar) A.elemSize1() //如果是8UC3的話,返回sizeof(uchar) A.type() //元素的數據類型 A.depth()//元素的位數 A.channels()//矩陣的通道數 A.step1() //矩陣的每一行元素的個數,A.step/A.elemSize1 A.size() //矩陣的尺寸 //注意以下是成員變量不是成員函數 A.step //矩陣的一行的字節數 A.rows //矩陣的行數,即高 A.cols //矩陣的列數,即寬

  • 總結

    Mat提供了關于矩陣的一些基本操作,這對圖像的操作打下了堅實的基礎,更多復雜的算法都是基于這些操作實現的。


    from:?http://blog.skyoung.org/2014/03/26/OpenCV(III)-How-to-use-Mat/#%E6%9E%84%E9%80%A0mat%E7%9A%84%E6%96%B9%E6%B3%95

    總結

    以上是生活随笔為你收集整理的OpenCV系列(三):Mat详解的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。