Opencv Mat的三種常用類型簡介

本文主要介紹Opencv常用的三種Mat類型:MatMat_Matx

1. Mat

1.1 創建與初始化
int rows = 3, cols = 1;
cv::Size size(cols, rows);

/* first method */
cv::Mat myMat( rows, cols, CV_8UC1, cv::Scalar(0) );
cv::Mat myMat = cv::Mat( rows, cols, CV_8UC1, cv::Scalar(0) );

cv::Mat myMat( size, CV_8UC1, cv::Scalar(0) );
cv::Mat myMat( cv::Size(cols, rows), CV_8UC1, cv::Scalar(0) );

/* second method */
cv::Mat myMat2;
myMat = cv::Mat( rows, cols, CV_8UC1 );
// initial with other mat or data
myMat.copyTo(myMat2);         // initial with mat

cv::Point3i pts( 1, 2, 3 );   
myMat2 = cv::Mat(pts, true);  // initial with other data
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

注意:

  1. 使用Mat::Mat(int rows, int cols, int type, const Scalar& s)Mat::Mat(Size size, int type, const Scalar& s)函數進行Mat初始化的時候,一定要注意Size行列存放順序是(col, row)或者是(width, height)

  2. Mattype種類非常多,可以創建普通的CV_8UC1, ... , CV_64FC41-4通道的矩陣,也可以創建更高通道的矩陣CV_8UC(n), ... , CV_64FC(n),其中最大可以達到CV_CN_MAX通道,Opencv 2.4.11版本中#define CV_CN_MAX 512

  3. 創建多通道Mat時,例如CV_8UC3,使用cv::Scalar(0, 0,0)myMat.setTo(cv::Scalar(0)),其中後者通用於任意通道;

  4. 使用其他Mat拷貝初始化的時候,void Mat::copyTo(OutputArray m) const函數會首先調用m.create(this->size(), this->type())所以會對輸入的m進行重新創建(包括sizetype),然後進行數據拷貝。m.copyTo(m)也是允許的,沒有任何問題。

1.2 數據訪問

這裏只列舉出常用三種方法:

1.指針數組的方式

cv::Mat image = cv::imread( "E:\\test.JPG", CV_LOAD_IMAGE_GRAYSCALE );
const int rows = image.rows;
const int cols = image.cols; 

uchar* data = (uchar*)image.data;
for ( int i=0; i<rows; i++ )
{
    for ( int j=0; j<cols; j++ )
    {
        int index = i*cols + j;
        data[index] = 0;
        /*
            if color one: 
            data[index * 3 + 0] = 0;
            data[index * 3 + 1] = 0;
            data[index * 3 + 2] = 0;
        */ 
    }
}
/*
    // also can be used as follow:
    for ( int i=0; i<rows; i++ )
    {
        uchar* data = (uchar*)image.data + i*cols;
        for ( int j=0; j<cols; j++ )
        {
            *data++ = 0;
        }
    }
}
*/
// cv::imwrite( "E:\\test2.JPG", image );
  • 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
  • 28
  • 29
  • 30
  • 31
  • 32

2..ptr的方式

/* .ptr with [] */
for ( int i=0; i<rows; i++ )
{
    uchar *data = image.ptr<uchar>( i );
    for ( int j=0; j<cols; j++ )
    {
        data[j] = 0;
        /*
            if color one:
            data[j*3 + 0] = 0;
            data[j*3 + 1] = 0;
            data[j*3 + 2] = 0;
        */
    }
}

/* .ptr with pointer */
for ( int i=0; i<rows; i++ )
{
    uchar *data = image.ptr<uchar>( i );
    for ( int j=0; j<cols*image; j++ )
    {
        *data++ = 0;
    }
}
  • 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

3..at的方式

for ( int i=0; i<rows; i++ )
{
    for ( int j=0; j<cols; j++ )
    {
         image.at<uchar>(i, j)= 0; // also can be: image.at<uchar>( cv::Point(j, i) ) = 0;
         /*
             if color one:
             image.at<uchar>( i, j*3 + 0 ) = 0;
             image.at<uchar>( i, j*3 + 1 ) = 0;
             image.at<uchar>( i, j*3 + 2 ) = 0;
         */
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

三種方法速度上有一定差異,感興趣的可以自己測試一下~

2. Mat_

Mat_繼承於Mat,相比於Mat沒有增加任何數據段,但增加了一些更加便捷的功能,表達上也更加精簡。

2.1 創建與初始化
/* first method */
cv::Mat_<double> myMat_ = ( cv::Mat_<double>(3, 3) << 
    1.0, 2.0, 3.0,
    4.0, 5.0, 6.0,
    7.0, 8.0, 9.0);

cv::Mat_<double> myMat_ = cv::Mat_<double>::zeros(3, 3); // others: eyes, diag, ones

/* second method */
cv::Mat_<double> myMat_(3, 1, 0.0); 
// -> cv::Mat image(3, 1, CV_64FC1, cv::Scalar(0.0));

// create a 100x100 color image and fill it with green(in RGB space)
cv::Mat_<cv::Vec3b> image( 100, 100, cv::Vec3b(0, 255, 0) );

/* third method */
cv::Mat myMat( 100, 100, CV_64F1, cv::Scalar(0) );
cv::Mat_<double>& myMat_ = (cv::Mat_<double>&)myMat; 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

注意:

  1. 使用( cv::Mat_<double>(row, col) << ...) )形式創建並初始化的時候,最外面的( )不能省略;

  2. 使用第二種通過Mat指針或者引用的方式創建與初始化Mat_時,兩者的數據類型一定要一致,不然程序雖然編譯沒問題,但運行就會BUG~

2.2 數據訪問
/* 
    Note that Mat::at<_Tp>(int y, int x) and 
    Mat_<_Tp>::operator ()(int y, int x) do 
    absolutely the same and run at the same speed
*/ 
int rows = myMat_.rows;
int cols = myMat_.cols;

/* first method */ 
for ( int i=0; i<rows; i++ )
{
    for ( int j=0; j<cols; j++ )
    {
        std::cout << myMat_(i, j) << std::endl;
    }
}

// for multi-channel images/matrices:
for ( int i = 0; i < rows; i++ )
{
    for( int j = 0; j < cols; j++ )
    {
        // scramble the 2nd (red) channel of each pixel
        image(i, j)[2] ^= (uchar)(i ^ j); // ^: exclusive or operation
    }
}

/* second method */
int matCount = rows * cols;
for ( int idx=0; idx < matCount; idx++ )
{
    std::cout << myMat_(idx) <<std::endl;
}
  • 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
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

3. Matx

Matx主要用於大小、數據類型(浮點型)已知的小矩陣(最大不超過6x6),包括:Matx12f, ... , Matx66fMatx12d, ... , Matx66d

創建與初始化都很簡單,不做過多介紹:

cv::Matx31d myMatx( 1.0, 2.0, 3.0 );

cv::Matx33d myMatx2 = cv::Matx33d( 0.0, 0.0, 0.0 );
  • 1
  • 2
  • 3

最後,關於Mat的運算(加,減,乘,求逆,轉置,均值,標準差…)三種類型基本差異不大,在文檔中也容易找到~


轉自: http://blog.csdn.net/yhl_leo/article/details/47683127

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章