天天看点

【OpenCV3学习笔记二】 OpenCV中的Mat类   1、初识Mat2、构造单通道Mat对象3、获得单通道Mat的基本信息4、访问单通道Mat对象中的值(利用成员函数)5、向量类Vec      6、分离通道和合并通道

   1、初识Mat

    构造Mat对象相当于构造了一个矩阵(数组),需要四个基本要素:行数

    列数、通道数以及数据类型,所以Mat类的构造函数如下:

     Mat(int rows, int cols, int type)

    Mat(Size(int cols, int rows), int type)// Size 第一个元素是矩阵的列数(宽)

2、构造单通道Mat对象

int main()

{

    //构造2行3列的矩阵

    Mat m = Mat(2, 3, CV_32FC1);

    Mat o = Mat::ones(2, 3, CV_32FC1);             //2行3列全是1的float 类型单通道矩阵

    Mat m = Mat::zeros(Size(3, 2), CV_32FC1);  //2行3列全是0的float 类型单通道矩阵

    Mat m1 = Mat::zeros(Size(2, 3), CV_32FC1);     //3行2列全是0的float 类型单通道矩阵

    return 0;

}

3、获得单通道Mat的基本信息

int main()

{

    //构造2行3列的矩阵

    Mat m = Mat(2, 3, CV_32FC1);

    cout << "行数:" << m.rows << endl;

    cout << "列数:" << m.cols << endl;

    Mat m1 = (Mat_<int>(3, 2) << 11, 22, 33, 44, 55, 66); //3行2列

    Size size = m1.size();

    cout << "尺寸:" << size << endl;

    cout << "通道数:" << m1.channels() << endl;

    cout << "面积:" << m1.total() << endl;

    cout <<"维数:"<<m1.dims << endl;

    return 0;

}

    程序打印结果为:

行数:2

列数:3

尺寸:[3 x 2]

通道数:1

面积:6

维数:2

4、访问单通道Mat对象中的值(利用成员函数)

      1、利用at成员函数

int main()

{

    Mat m = (Mat_<int>(3, 2) << 11, 22, 33, 44, 55, 66); //3行2列

    for (int r = 0; r < m.rows; r++)

    {

        for (int c = 0; c < m.cols; c++)

        {

            cout << m.at<int>(r, c) << ","; //r行c列的值

        }

        cout << endl;

    }

}

    程序打印结果为:

11,22,

33,44,

55,66,

    2、利用ptr成员函数

int main()

{

    Mat m = (Mat_<int>(3, 2) << 11, 22, 33, 44, 55, 66); //3行2列

    for (int r = 0; r < m.rows; r++)

    {

        //得到矩阵m的第r行行首地址

        const int *ptr = m.ptr<int>(r);

        //打印第r行的所有值

        for (int c = 0; c < m.cols; c++)

        {

            cout << ptr[c] << ",";

        }

        cout << endl;

    }

}

    程序打印结果为:

11,22,

33,44,

55,66,

   3、利用isContinuous和ptr成员函数

int main()

{

    // 函数 isContinuous  实例

    Mat m = (Mat_<int>(3, 2) << 11, 22, 33, 44, 55, 66); //3行2列

    //isContinuous含义,每一行的所有值存储在连续的内存区域中,行与行之间可能有间隔

    //如果isContinuous返回值为true,则代表行与行之间也是连续存储,即所有的值是连续存储

    if (m.isContinuous())   

    {

        //得到矩阵m的第r行行首地址

        const int *ptr = m.ptr<int>(0);

        //打印第r行的所有值

        for (int c = 0; c < m.cols *m.rows; c++)

        {

            cout << ptr[c] << ",";

        }

        cout << endl;

    }

}

    程序打印结果为:

11,22,33,44,55,66,

  4、利用data和step成员变量

int main()

{

    //函数 data 和 step 实例

    Mat m = (Mat_<int>(3, 2) << 11, 22, 33, 44, 55, 66); //3行2列

    for (int r = 0; r < m.rows; r++)

    {

        for (int c = 0; c < m.cols; c++)

        {

            //step[0]代表每一行所占的字节数,如果有间隔,间隔也作为字节数的一部分计算在内

            //step[1]代表每一个数值所占的字节数,data是指向第一个数值的指针,类型为uchar

            //int类型的单通道矩阵的第r行第c列的指

            cout << *((int *)(m.data + m.step[0] * r + c * m.step[1])) << ",";

        }

    }

}

    程序打印结果为:

11,22,33,44,55,66,

5、向量类Vec

OpenCV为向量类的声明取了一个别名

typedef Vec<uchar, 3> Vec3b;

typedef Vec<int, 2> Vec2i;

typedef Vec<float, 4> Vec4f;

typedef Vec<double, 3> Vec3d;

int main()

{

    //向量类 Vec

    //格式如:Vec<Typename _Tp, int _cn> 数据类型为_Tp;

    //构造一个长度为3,数据类型为int 

    Vec<int, 3> vi(21, 32, 14);

    cout << "向量的行数:" << vi.rows << endl;

    cout << "向量的列数:" << vi.cols << endl;

    cout << "访问第0个元素:" << vi[0] << endl;

    cout << "访问第1个元素:" << vi(1) << endl;

}

    程序打印结果为:

向量的行数:3

向量的列数:1

访问第0个元素:21

访问第1个元素:32

int main()

{

    //向量类 Vec    

    Mat m = (Mat_<Vec3f>(2, 2) << Vec3f(1, 11, 21), Vec3f(2, 12, 32), 

                                   Vec3f(3, 13, 23), Vec3f(4, 14, 24));

    for (int r = 0; r < m.rows; r++)

    {

        for (int c = 0; c < m.cols; c++)

        {  //使用at函数

            cout << m.at<Vec3f>(r, c) << ",";

        }

        cout << endl;

    }

    for (int r = 0; r < m.rows; r++)

    {   //使用ptr函数

        //每行首元素地址    

        Vec3f *ptr = m.ptr<Vec3f>(r);

        for (int c = 0; c < m.cols; c++)

        {

            cout << ptr[c] << ",";

        }

        cout << endl;

    }

    for (int r = 0; r < m.rows; r++)

    {

        for (int c = 0; c < m.cols; c++)

        {

            Vec3f *ptr = (Vec3f *)(m.data + r * m.step[0] + c * m.step[1]);

            cout << *ptr<< ",";

        }

        cout << endl;

    }

}

    程序打印结果相同都为:

[1,11,21],[2,12,32],

[3,13,23],[4,24,34]

      6、分离通道和合并通道

  多通道矩阵分离为多个单通道矩阵的时候,这些单通道矩阵都存放在vector中

vector<Mat> planes;

split(m, planes);

 利用merge函数可以将多个单通道矩阵合并为一个三维矩阵

    Mat plane0 = (Mat_<int>(2, 2) << 1, 2, 3, 4);

    Mat plane1 = (Mat_<int>(2, 2) << 5, 6, 7, 8);

    Mat plane2 = (Mat_<int>(2, 2) << 9, 10, 11, 12);

    Mat plane[] = { plane0, plane1, plane2 };

    Mat mat;

    merge(plane, 3, mat);

    //利用merge重载函数

    vector<Mat> plane;

    plane.push_back(plane0);

    plane.push_back(plane1);

    plane.push_back(plane2);

    Mat mat;

    merge(plane, mat);

}

  7、获得Mat 中某一个区域的值

    //使用成员函数row和col得到矩阵的i行j列 对于单通道如下

    int r = 1;

    int c = 0;

    //矩阵的第r行

    Mat mr = m.row(r);

    //矩阵的第c列

    Mat mc = m.col(c);

    //获取到的返回值仍然是一个单通道的Mat类型

int main()

{

    //使用成员函数rowRange和colRange得到矩阵的连续行或者连续列

    //使用Mat构造函数构造matrix

    Mat matrix = (Mat_<int>(5, 5) << 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);

    Mat r_range = matrix.rowRange(Range(2, 4));

    for (int r = 0; r < r_range.rows; r++) 

    {

        for (int c = 0; c < r_range.cols; c++)

        {

            cout << r_range.at<int>(r, c) << ",";

        }

        cout << endl;

    }

}

程序打印结果为:

11,12,13,14,15,

16,17,18,19,20,

 colRange的使用方法类似。