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

一、基础图像容器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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值