Opencv 例程講解 4 ----圖片容器Mat

     在前面的幾個例程中,我們都有用到一個類 Mat,它作爲opencv中圖像數據,特徵點,查表數組,直方圖等數據的容器,可能是opencv中運用最普遍的一個類,幾乎大多數的API都爲這一數據類型留有接口。這次例程中,我們將看下opencv例程中是怎樣展示這樣一個強大的類的。對應的例程爲 (TUTORIAL) mat_the_basic_image_container。

源代碼如下:

/*  For description look into the help() function. */

#include "opencv2/core/core.hpp"
#include <iostream>

using namespace std;
using namespace cv;

static void help()
{
    cout
    << "\n--------------------------------------------------------------------------" << endl
    << "This program shows how to create matrices(cv::Mat) in OpenCV and its serial"
    << " out capabilities"                                                            << endl
    << "That is, cv::Mat M(...); M.create and cout << M. "                            << endl
    << "Shows how output can be formated to OpenCV, python, numpy, csv and C styles." << endl
    << "Usage:"                                                                       << endl
    << "./cvout_sample"                                                               << endl
    << "--------------------------------------------------------------------------"   << endl
    << endl;
}

int main(int,char**)
{
    help();
    // create by using the constructor
    Mat M(2,2, CV_8UC3, Scalar(0,0,255));
    cout << "M = " << endl << " " << M << endl << endl;

    // create by using the create function()
    M.create(4,4, CV_8UC(2));
    cout << "M = "<< endl << " "  << M << endl << endl;

    // create multidimensional matrices
    int sz[3] = {2,2,2};
    Mat L(3,sz, CV_8UC(1), Scalar::all(0));
    // Cannot print via operator <<

    // Create using MATLAB style eye, ones or zero matrix
    Mat E = Mat::eye(4, 4, CV_64F);
    cout << "E = " << endl << " " << E << endl << endl;

    Mat O = Mat::ones(2, 2, CV_32F);
    cout << "O = " << endl << " " << O << endl << endl;

    Mat Z = Mat::zeros(3,3, CV_8UC1);
    cout << "Z = " << endl << " " << Z << endl << endl;

    // create a 3x3 double-precision identity matrix
    Mat C = (Mat_<double>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
    cout << "C = " << endl << " " << C << endl << endl;

    Mat RowClone = C.row(1).clone();
    cout << "RowClone = " << endl << " " << RowClone << endl << endl;

    // Fill a matrix with random values
    Mat R = Mat(3, 2, CV_8UC3);
    randu(R, Scalar::all(0), Scalar::all(255));

    // Demonstrate the output formating options
    cout << "R (default) = " << endl <<        R           << endl << endl;
    cout << "R (python)  = " << endl << format(R,"python") << endl << endl;
    cout << "R (numpy)   = " << endl << format(R,"numpy" ) << endl << endl;
    cout << "R (csv)     = " << endl << format(R,"csv"   ) << endl << endl;
    cout << "R (c)       = " << endl << format(R,"C"     ) << endl << endl;

    Point2f P(5, 1);
    cout << "Point (2D) = " << P << endl << endl;

    Point3f P3f(2, 6, 7);
    cout << "Point (3D) = " << P3f << endl << endl;


    vector<float> v;
    v.push_back( (float)CV_PI);   v.push_back(2);    v.push_back(3.01f);

    cout << "Vector of floats via Mat = " << Mat(v) << endl << endl;

    vector<Point2f> vPoints(20);
    for (size_t i = 0; i < vPoints.size(); ++i)
        vPoints[i] = Point2f((float)(i * 5), (float)(i % 7));

    cout << "A vector of 2D Points = " << vPoints << endl << endl;
    return 0;
}

可以看出,這個例程首先介紹了Mat 的幾種基本的創建方法,包括利用構造函數創建,利用create函數創建;創建N-dimensional矩陣的方法等;接着展示了以不同風格輸出mat數據的方法,包括默認風格,python風格,numpy風格,csv風格和c風格;最後,展示了opencv中二位點,三維點,序列以及序列點的數據的創建和輸出。下面給出上述代碼各自對應的輸出結果。

1.利用構造函數創建,函數原型爲 Mat(int rows, int cols, int type, const Scalar& s);   Scalar 爲一個四通道的double序列。CV_8UC3表示通道數位3,數據類型爲CV_8U,還有其他幾種類似的構造函數,有Scalar 參數的以Scalar的值進行初始化,沒有設定初始化值的,初始化值不確定,但似乎有一定的規律,見下面create的結果。

    //! constructs 2D matrix of the specified size and type
    // (_type is CV_8UC1, CV_64FC3, CV_32SC(12) etc.)
    Mat(int rows, int cols, int type);
    Mat(Size size, int type);
    //! constucts 2D matrix and fills it with the specified value _s.
    Mat(int rows, int cols, int type, const Scalar& s);
    Mat(Size size, int type, const Scalar& s);

    // create by using the constructor
    Mat M(2,2, CV_8UC3, Scalar(0,0,255));
    cout << "M = " << endl << " " << M << endl << endl;

M =
 [0, 0, 255, 0, 0, 255;
  0, 0, 255, 0, 0, 255]

2.利用create 函數創建,函數原型爲void create(int rows, int cols, int type); 第一個參數爲列數,第二個參數爲函數,第三參數爲type,CV_8UC(2) 表示通道數位2,數據類型爲CV_8U的type

  // create by using the create function()
    M.create(4,4, CV_8UC(2));
    cout << "M = "<< endl << " "  << M << endl << endl;
M =
 [205, 205, 205, 205, 205, 205, 205, 205;
  205, 205, 205, 205, 205, 205, 205, 205;
  205, 205, 205, 205, 205, 205, 205, 205;
  205, 205, 205, 205, 205, 205, 205, 205]

3創建n-維的矩陣,注意這種Mat 不支持 cout<<輸出,函數原型爲Mat(int ndims, const int* sizes, int type, const Scalar& s); 同樣存在一個不帶初始化值的版本

Mat(int ndims, const int* sizes, int type);

    // create multidimensional matrices
    int sz[3] = {2,2,2};
    Mat L(3,sz, CV_8UC(1), Scalar::all(0));

4 創建matlab風格的矩陣,不詳細介紹了,一看就明白

    // Create using MATLAB style eye, ones or zero matrix
    Mat E = Mat::eye(4, 4, CV_64F);
    cout << "E = " << endl << " " << E << endl << endl;

    Mat O = Mat::ones(2, 2, CV_32F);
    cout << "O = " << endl << " " << O << endl << endl;

    Mat Z = Mat::zeros(3,3, CV_8UC1);
    cout << "Z = " << endl << " " << Z << endl << endl;
E =
 [1, 0, 0, 0;
  0, 1, 0, 0;
  0, 0, 1, 0;
  0, 0, 0, 1]

O =
 [1, 1;
  1, 1]

Z =
 [0, 0, 0;
  0, 0, 0;
  0, 0, 0]

5. 通過模板類Mat_創建,它是Mat 的派生模板類,兩者之間可以相互隱式轉換。Mat_主要實現對Mat 數據的迭代訪問,可以利用座標自己對像素進行操作,如果看過上一個例程的話,應該會對這個類型有影響。這裏是用這個類型讀入數據。

    // create a 3x3 double-precision identity matrix
    Mat C = (Mat_<double>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
    cout << "C = " << endl << " " << C << endl << endl;
C =
 [0, -1, 0;
  -1, 5, -1;
  0, -1, 0]

6. 展示了Mat 對列數據的操作

    Mat RowClone = C.row(1).clone();
    cout << "RowClone = " << endl << " " << RowClone << endl << endl;

RowClone =
 [-1, 5, -1]

7. 利用隨機數函數randu 初始化數據,函數原型爲 void randu(InputOutputArray dst, InputArray low, InputArray high); 值的範圍爲[low, high)

    // Fill a matrix with random values
    Mat R = Mat(3, 2, CV_8UC3);
    randu(R, Scalar::all(0), Scalar::all(255));
 

8 展示了幾種風格的輸出

    // Demonstrate the output formating options
    cout << "R (default) = " << endl <<        R           << endl << endl;
    cout << "R (python)  = " << endl << format(R,"python") << endl << endl;
    cout << "R (numpy)   = " << endl << format(R,"numpy" ) << endl << endl;
    cout << "R (csv)     = " << endl << format(R,"csv"   ) << endl << endl;
    cout << "R (c)       = " << endl << format(R,"C"     ) << endl << endl;
R (default) =
[91, 2, 79, 179, 52, 205;
  236, 8, 181, 239, 26, 248;
  207, 218, 45, 183, 158, 101]

R (python)  =
[[[91, 2, 79], [179, 52, 205]],
  [[236, 8, 181], [239, 26, 248]],
  [[207, 218, 45], [183, 158, 101]]]

R (numpy)   =
array([[[91, 2, 79], [179, 52, 205]],
  [[236, 8, 181], [239, 26, 248]],
  [[207, 218, 45], [183, 158, 101]]], type='uint8')

R (csv)     =
91, 2, 79, 179, 52, 205
  236, 8, 181, 239, 26, 248
  207, 218, 45, 183, 158, 101

R (c)       =
{91, 2, 79, 179, 52, 205,
  236, 8, 181, 239, 26, 248,
  207, 218, 45, 183, 158, 101}

9 2維點,3維點,序列,點序列,比較簡單,就不多加介紹了。注意序列不支持直接用cout<<輸出,但可以轉換成Mat進行輸出。

   Point2f P(5, 1);
    cout << "Point (2D) = " << P << endl << endl;

    Point3f P3f(2, 6, 7);
    cout << "Point (3D) = " << P3f << endl << endl;


    vector<float> v;
    v.push_back( (float)CV_PI);   v.push_back(2);    v.push_back(3.01f);

    cout << "Vector of floats via Mat = " << Mat(v) << endl << endl;

    vector<Point2f> vPoints(20);
    for (size_t i = 0; i < vPoints.size(); ++i)
        vPoints[i] = Point2f((float)(i * 5), (float)(i % 7));

    cout << "A vector of 2D Points = " << vPoints << endl << endl;

Point (2D) = [5, 1]

Point (3D) = [2, 6, 7]

Vector of floats via Mat = [3.1415927; 2; 3.01]

A vector of 2D Points = [0, 0; 5, 1; 10, 2; 15, 3; 20, 4; 25, 5; 30, 6; 35, 0; 40, 1; 45, 2; 50, 3; 55, 4; 60, 5; 65, 6; 70, 0; 75, 1; 80, 2; 85, 3; 90, 4; 95, 5]


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