opencv学习笔记(十三)——数据结构

来源:互联网 发布:网络零售交易额指什么 编辑:程序博客网 时间:2024/05/22 03:35

一、基础图像容器Mat

1.1Mat介绍

Mat是用来储存数字图像的一个类。它是IplImage的升级。Mat相对于IplImage最大的优点就是:不用手动开辟和释放图像内存,Mat能够自动管理内存。
Mat是一个类。包含两个数据部分:(1)矩阵头(包含矩阵尺寸,储存方法、存储地址等信息);(2)一个指向储存所有像素值的矩阵(根据所储存方法的不同,矩阵可以是不同的维数)的指针。
为了提高Opencv的运行速度,采用了引用计数机制。其思路是让每个Mat对象有自己的信息头(矩阵头),共享同一个矩阵。在Opencv中,各个函数之间传递图像就是传递信息头,而不是传递矩阵数据,从而提高Opencv运行速度。
注意:一个矩阵被多个Mat类型的对象使用,这个矩阵清理由最后一个使用它的对象负责清理。


1.2Mat的复制:

1,Mat类的拷贝构造函数只复制信息头和矩阵指针,而不复制矩阵。
下面是两种只复制矩阵头的方法例程:

    Mat A, C;    A = imread("psb.jpg");    /*使用构造函数进行复制*/    Mat B(A);           /*使用赋值运算符进行复制*/    C = A;  

2,复制矩阵数据:
在一些情况下我们必须要复制Mat类的矩阵数据,就可以使用clone()或者是copyTo()。
例1:
Mat F =A.clone();
例2:

Mat G;A.copyTo(G);

1.3,Mat对象创建的七种办法:

(1)【方法一】使用构造函数(最常用):

Mat M(2, 2, CV_8UC3, Scalar(0, 0, 255));    //创建cout << "M = " << endl << " " << M << endl << endl; //显示

首先定义其行数和列数,然后指定存储元素的数据类型以及每个矩阵点的通道数,(CV_[位数][带符号与否][类型前缀]C[通道数],例:CV_8UC3,预先定义的通道数最多只能四通道,若需要更多通道数,可以使用大写宏,并把通道数放在括号中,如:CV_8UC(1))

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

(2)【方法二】使用已存在的IplImage指针创建信息头

    IplImage* img = cvLoadImage("G:\\Opencv\\素材\\楪析.jpg", 1);    Mat mtx(img);    //转换IplImage*->Mat

(3)【方法三】采用MATLAB式的初始化方式
采用MATLAB初始化矩阵的方式:zeros(),ones(),eyes().然后指定尺寸和数据类型:

    Mat O = Mat::ones(2, 2, CV_32F);    cout << "O = " << endl << O << endl << endl;
    Mat E = Mat::eye(4, 4, CV_64F);    cout << "E = " << endl << " " << E << endl << endl;
    Mat Z = Mat::zeros(3, 3, CV_8UC1);    cout << "Z = " << endl << " " << Z << endl << endl;

(4)【方法四】对小矩阵使用逗号直接初始化:

    Mat C = (Mat_<double>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);    cout << "C = " << endl << " " << C << endl << endl;

(5)【方法五】为已存在的对象创建新信息头
其实就是先创建一个信息头(Mat RowClone;),然后从一个带有矩阵数据的Mat对象中复制其数据给这个信息头,对其初始化。

Mat C = (Mat_<double>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);Mat RowClone = C.row(1).clone();    cout << "RowClone = " << endl << " " << RowClone << endl << endl;

1.4、Mat的格式化输出

主要介绍三种:
首先初始化一个Mat对象:

    /*初始化一个Mat对象*/    Mat r = Mat(10, 3, CV_8UC3);    randu(r, Scalar::all(0), Scalar::all(255));

(1)opencv默认风格输出:

/*opencv默认风格输出*/    cout << "r(opencv默认风格) = " << endl << r << ";" << endl << endl;

(2)C语言风格输出:

/*C语言风格*/    cout << "r(C语言风格)=" << endl << format(r, "C") << ";" << endl << endl;

(3)逗号分隔的风格:

/*逗号分隔的风格*/    cout << "r(逗号分隔) = " << endl << format(r, "csv") << ";" << endl << endl;

二、其他数据结构

2.1点的定义和输出:Point类

    //二维点的定义和输出    Point2f p(6, 2);    cout << "【二维点】 p = " << p << ";\n" << endl;

也可以这样表示:

    Point point;    point.x = 10;    point.y = 8;    cout << point << endl;

另外还有三维点:

    //三维点的定义和输出    Point3f p3f(8, 2, 0);    cout << "【三维点】p3f = " << p3f << ";\n" << endl;

然后我们查看Point的定义:

typedef Point_<int> Point2i;typedef Point2i Point;typedef Size_<int> Size2i;typedef Size_<double> Size2d;typedef Size2i Size;typedef Rect_<int> Rect;typedef Point_<float> Point2f;typedef Point_<double> Point2d;typedef Size_<float> Size2f;typedef Point3_<int> Point3i;typedef Point3_<float> Point3f;typedef Point3_<double> Point3d;

可以发现:Point_,Point2i,Point互相等价。

2.2基于Mat的std:vector定义和输出

//基于Mat的std:vector定义和输出    vector<float> v;    v.push_back(3);    v.push_back(5);    v.push_back(7);    cout << "【基于Mat的vector】shortvec = " << Mat(v) << ";\n" << endl;

2.3定义和输出std::vector点

    vector<Point2f> points(20);    for (size_t i = 0; i < points.size(); ++i)    {        points[i] = Point2f((float)(i * 5), (float)(i % 7));    }    cout << "【二维点向量】points =" << points << ";";

2.4颜色的表示:Scalar类

Scalar表示具有4个元素的数组,通常用来传递像素值。例如:RGB的颜色值。对于这个函数可以写三个函数,第四个可以不写。
如:
Scalar(a,b,c)
那么定义RGB颜色值:红色分量为c,绿色为b,蓝色为a;

2.5尺寸的表示:Size类

typedef Size_<int> Size2i;typedef Size2i Size;

其中Size_是个模板类,在这里Size_表示类体内部的模板所代表的类型为int,这两句代码意思是:首先给已知的数据类型Size_起个新名字,叫Size2i.然后又给已知数据类型Size起个新名字,叫Size。这里主要是typedef的用法。
对于Size_模板类的内部构造函数,我们使用频率最高的是:
Size_(_Tp _width,_Tp_height);
定义的是宽度和高度。
例:
Size(5,5),表示XXX的宽度和高度都是5。

2.6矩阵的表示:Rect类

Rect类的成员变量有x,y,width,hight,分别为左上角的坐标和矩阵的宽和高。常用的成员函数有:size()返回值为size,area()返回矩阵的面积contains(Point)判断点是否在矩形中,inside(Rect)函数判断矩形是否在矩形内。t1()返回左上角点坐标,br()放回右下角点坐标。

Scalar和Point综合运用实例:

Draw.cpp文件:

#include"Draw.h"/* *主要功能:实现绘制不同角度,相同尺寸的椭圆 *椭圆绘制函数ellipse()函数参数介绍: *将图像画到图像img上 *椭圆中心点Point(WINDOW_WIDTH / 2, WINDOW_WIDTH / 2) *椭圆旋转角度angle *扩展的弧度从0度到360度 *图形颜色Scalar(255,129,0) *线宽(thickness)为2 *线(lineType)为8(联通线型) */void DrawEllipse(Mat img,double angle){    int thickness = 2;    int lineType = 8;    ellipse(img,        Point(WINDOW_WIDTH / 2, WINDOW_WIDTH / 2),        Size(WINDOW_WIDTH / 4, WINDOW_WIDTH / 16),        angle,        0,        360,        Scalar(255, 129, 0),        thickness,        lineType);}/* *功能:实现实心圆的绘制 *圆形绘制circl函数参数介绍: *将图像画到图像img上 *圆的半径WINDOW_WIDTH/32 *圆的颜色Scalar(0,0,255),为红色 *线宽为 -1,即为实心 *线型(lineType)为8(联通线型) */void DrawFilledCircle(Mat img, Point center){    int thickness = -1;    int lineType = 8;    circle(img,        center,        WINDOW_WIDTH / 32,        Scalar(0, 0, 255),        thickness,        lineType        );}/* *功能:实现多边形的绘制 *函数fillPoly():用于将多边形画到图像img上 *多边形顶点集为ppt *要绘制的多边形顶点数目为npt *要绘制多边形数量仅为1 *多边形的颜色定义为白色Scalar(255,255,255) */void DrawPolygon(Mat img){    int lineType = 8;    //创建一些点    Point rookPoint[1][20];    rookPoint[0][0] = Point(WINDOW_WIDTH / 4, 7 * WINDOW_WIDTH / 8);    rookPoint[0][1] = Point(3 * WINDOW_WIDTH / 4, 7 * WINDOW_WIDTH / 8);    rookPoint[0][2] = Point(3 * WINDOW_WIDTH / 4, 13 * WINDOW_WIDTH / 16);    rookPoint[0][3] = Point(11 * WINDOW_WIDTH / 16, 13 * WINDOW_WIDTH / 16);    rookPoint[0][4] = Point(19 * WINDOW_WIDTH / 32, 3 * WINDOW_WIDTH / 8);    rookPoint[0][5] = Point(3 * WINDOW_WIDTH / 4, 3 * WINDOW_WIDTH / 8);    rookPoint[0][6] = Point(3 * WINDOW_WIDTH / 4, WINDOW_WIDTH / 8);    rookPoint[0][7] = Point(26 * WINDOW_WIDTH / 40, WINDOW_WIDTH / 8);    rookPoint[0][8] = Point(26 * WINDOW_WIDTH / 40, WINDOW_WIDTH / 4);    rookPoint[0][9] = Point(22 * WINDOW_WIDTH / 40, WINDOW_WIDTH / 4);    rookPoint[0][10] = Point(22 * WINDOW_WIDTH / 40, WINDOW_WIDTH / 8);    rookPoint[0][11] = Point(18 * WINDOW_WIDTH / 40, WINDOW_WIDTH / 8);    rookPoint[0][12] = Point(18 * WINDOW_WIDTH / 40, WINDOW_WIDTH / 4);    rookPoint[0][13] = Point(14 * WINDOW_WIDTH / 40, WINDOW_WIDTH / 4);    rookPoint[0][14] = Point(14 * WINDOW_WIDTH / 40, WINDOW_WIDTH / 4);    rookPoint[0][15] = Point(WINDOW_WIDTH / 4, WINDOW_WIDTH / 8);    rookPoint[0][16] = Point(WINDOW_WIDTH / 4, WINDOW_WIDTH / 8);    rookPoint[0][17] = Point(13 * WINDOW_WIDTH / 32, 3 * WINDOW_WIDTH / 8);    rookPoint[0][18] = Point(5 * WINDOW_WIDTH / 16, 13 * WINDOW_WIDTH / 16);    rookPoint[0][19] = Point(WINDOW_WIDTH / 4, 13 * WINDOW_WIDTH / 16);    const Point* ppt[1] = { rookPoint[0] };    int npt[] = { 20 };    fillPoly(img,        ppt,        npt,        1,        Scalar(255, 255, 255),        lineType);}/* *函数功能:实现线的绘制 * */void DrawLine(Mat img, Point start, Point end){    int thickness = 2;    int lineType = 8;    line(img,        start,        end,        Scalar(0, 0, 0),        thickness,        lineType);}

Draw.h文件:

#ifndef _DRAW_H#define _DRAW_H#include <opencv2/opencv.hpp>using namespace cv;using namespace std;#define WINDOW_WIDTH 600#define WINDOW_NAME1 "【绘制图1】"#define WINDOW_NAME2 "【绘制图2】"void DrawEllipse(Mat img, double angle);void DrawFilledCircle(Mat img, Point center);void DrawPolygon(Mat img);void DrawLine(Mat img,Point start,Point end);#endif

main函数:

int main(){    Mat atomImage = Mat::zeros(WINDOW_WIDTH, WINDOW_WIDTH, CV_8UC3);    Mat rookImage = Mat::zeros(WINDOW_WIDTH, WINDOW_WIDTH, CV_8UC3);    /*绘制原子示例图*/    //绘制椭圆    DrawEllipse(atomImage, 90);    DrawEllipse(atomImage, 0);    DrawEllipse(atomImage, 45);    DrawEllipse(atomImage, -45);    //绘制圆心    DrawFilledCircle(atomImage, Point(WINDOW_WIDTH / 2, WINDOW_WIDTH / 2));    /*制组合图*/    //绘制多边形    DrawPolygon(rookImage);    //绘制矩形    rectangle(rookImage,        Point(0, 7 * WINDOW_WIDTH / 8),        Point(WINDOW_WIDTH, WINDOW_WIDTH),        Scalar(0, 255, 255),        -1,        8);    DrawLine(rookImage, Point(0, 15 * WINDOW_WIDTH / 16), Point(WINDOW_WIDTH, 15 * WINDOW_WIDTH / 16));    imshow(WINDOW_NAME1, atomImage);    imshow(WINDOW_NAME2, rookImage);    waitKey(0);    return 0;}

效果:
这里写图片描述这里写图片描述

0 1
原创粉丝点击