第4章 OpenCV数据结构与基本绘图

4.1 基础图像容器Mat

4.1.1 数字图像存储概述

  图像在数码设备中的表现形式:像素点矩阵

4.1.2 Mat结构的使用

1.OpenCV1.x时代
  基于C语言接口而建的图像存储格式IplImage*
  缺点:退出时忘记relese掉的话,会造成内存泄漏,手动释放内存耗费时间
2.C++出现后
  自动的内存管理
  不足:许多嵌入式开发系统只支持C语言
3.OpenCV2.0时代
  Mat类数据结构
  优点:不必手动开辟空间、不必再在不需要时立即释放空间
4.Mat类数据部分组成
(1)矩阵头:矩阵尺寸、存储方法、存储地址等
(2)指向存储所有像素值的矩阵的指针
5.计数机制
  矩阵本身尺寸数量级很大,传递图像时造成比较大的开销,为解决此问题,引入计数机制。
  计数机制:让每个Mat对象有自己的信息头,但共享同一个矩阵。通过让矩阵指针指向同一个地址而实现,拷贝构造函数则只复制信息头和矩阵指针,而不复制矩阵。这时,通过任何一个对象所做的改变会影响其他图像。
(1)创建信息头:

Mat A,C; //仅创建信息头
Mat D(A,Rect(10,10,100,100)); //使用矩形界定信息头
Mat E=A(Range:all(),Range(1,3)); //用行和列界定信息头

(2)矩阵清理:复制一个信息头会增加矩阵的引用次数,反之,当一个头被释放后,计数会减一,当计数值为0,矩阵会被清理。
(3)复制矩阵本身函数:clone()或copyTo(),改变一个对象不会影响其他对象,例如:

Mat F=A.clone();
Mat G;
A.copyTo(G);

4.1.3 像素值的存储方法

1.存储像素值需要指定颜色空间和数据类型,颜色空间
(1)灰度级空间:黑白组合
(2)其他颜色空间:
  1)RGB颜色空间最常用;
  2)HSV和HLS把颜色分解成色调、饱和度和亮度/明度,抛弃最后一个元素算法对输入图像的光照条件不敏感
  3)YCrCb在JPEG图像格式中广泛使用
  4)CIE L*a*b*是一种在感知上均匀的颜色空间,它适合用来度量两个颜色之间的距离
2.每个组成元素都有自己的定义域,定义域取决于其数据类型
(1)char:最小数据类型,1字节(8位),RGB颜色空间使用三个char,可表示1600万种
(2)有符号型:0到255
(3)无符号型:-127到+127
(4)float或double:能给出更加精细的颜色分辨能力

4.1.4 显式创建Mat对象的7种方法

  (Mat不但是图像容器类,也是通用矩阵类,可以用来创建多维矩阵)

1.Mat()构造函数
  二维多通道图像定义:行数,列数,存储元素数据类型和矩阵点通道数(CV_[位数][带符号与否][类型前缀]C[通道数]),定制化值初始化矩阵,如:

Mat M(2,2,CV_8UC3,Scalar(0,0,255));//CV_8UC3:8位的unsigned char,每个像素由3个元素组成三通道
cout<<”M=”<<endl<<” “<<M<<endl<<endl;

2.C\C++中通过构造函数进行初始化

 int sz[3] = { 2,2,2 };Mat L(3, sz, CV_8UC3, Scalar::all(0));//创建超过2维的矩阵,指定维度,传递一个指向一个数组的指针,数组包含每个维度的尺寸

3.唯一存在的IplImage指针创建信息头,转换IplImage*->Mat

 //IplImage* img = cvLoadImage("1.jpg", 1);//Mat mtx(img); //报错,"Mat没有匹配IplImage*参数的构造函数"

4.利用Create()函数,此方法不能为矩阵设初值,只是在改变尺寸时重新为矩阵数据开辟内存

    M.create(4, 4, CV_8UC(2));cout << "M= " << endl << " " << M << endl << endl;

5.采用Matlab式的初始化方式

 Mat E = Mat::eye(4, 4, CV_64F);//单位矩阵cout << "E= " << endl << " " << E << endl << endl;Mat O = Mat::ones(2, 2, CV_32F);//全1矩阵cout << "O= " << endl << " " << O << endl << endl;Mat Z = Mat::zeros(3, 3, CV_8UC1);//全0矩阵cout << "Z= " << endl << " " << Z << endl << endl;

6.对小矩阵使用逗号分隔式初始化函数

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

7.为已存在的对象创建新信息头

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

4.1.5 OpenCV中格式化输出方法

  r矩阵定义:通过randu()函数产生的随机值来填充矩阵,需要给定一个上限和下限确保随机值在期望的范围内。

Mat r=Mat(10,3,CV_8UC3);
randu(r,Scalar::all(0),Scalar::all(255));
//1.OpenCV默认风格cout << "r (OpenCV默认风格)= " << r << ";" << endl << endl;
//2.Python风格cout << "r (Python风格)= " << format(r, Formatter::FMT_PYTHON) << ";" << endl << endl;
//3.逗号分隔风格cout << "r (逗号分隔风格)= " << format(r, Formatter::FMT_CSV) << ";" << endl << endl;
//4.Numpy风格cout << "r (Numpy风格)= " << format(r, Formatter::FMT_NUMPY) << ";" << endl << endl;
//5.C语言风格cout << "r (C语言风格)= " << format(r, Formatter::FMT_C) << ";" << endl << endl;

4.1.6 输出其他常用数据结构

1.二维点

 Point2f p2f(6, 2);cout << "[二维点]p2f = " << p2f << ";\n" << endl;

2.三维点

 Point3f p3f(8, 2, 0);cout << "[二维点]p3f = " << p3f << ";\n" << endl;

3.基于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;

4.std::vector点,定义和输出存放点的vector容器,以存放二维点Point2f为例

 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 << ";";

4.2 常用数据结构和函数

4.2.1 点的表示:Point类(OpenCV中Point_<int>、Point2i、Point等价,Point_<float>、Point2f等价)

 Point point;point.x = 10;point.y = 8;//Point point = Point(10, 8);

4.2.2 颜色的表示:Scalar类

  Scalar(a, b, c); 红c,绿b,蓝a

4.2.3 尺寸的表示:Size类(OpenCV中Size_、Size2i、Size等价)

 Size(5, 5);

4.2.4 矩形的表示:Rect类
(1)成员变量:x,y,width,height
(2)成员函数:Size(),area(),contains(Point),inside(Rect),tl()返回左上角点坐标,br()返回右下角点坐标
(3)求两矩形交并集 Rect rect = rect1 & rect2; Rect rext = rext1 | rext2;
(4)矩形平移和缩放 Rect rextShift = rect + point; Rect rectScale = rect + size;

4.2.5 颜色空间转换:cvtColor()函数
(1)函数原型:void cvtColor(InputArray src,OutputArray dst,int code,int dstCn=0)
(2)参数说明:输入图像,输出图像,颜色空间转换标识符,目标图像通道数
(3)示例: cvtColor(srcImage, dstImage, COLOR_GRAY2BGR);
        
4.2.6 Core模块中的常用函数
1.<math.h>中,计算向量角度fastAtan2、计算立方根cubeRoot、向上取整cvCeil、向下取整cvFloor、四舍五入cvRound、判断自变量是否无穷大cvIsInf、判断自变量是否不是一个数cvIsNaN
2.显示文字相关:getTextSize、cvInitFont、putText
3.作图相关:circle、clipLine、ellipse、ellipse2Poly、line、rectangle、polylines、LineIterator
4.填充相关:fillConvexPoly、fillPoly

4.3 基本图形绘制

  涉及绘制函数:line:直线;ellipse:椭圆;rectangle:矩形;circle:圆形;fillPoly:填充的多边形

#include<opencv2/opencv.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#define WINDOW_NAME1 "[绘制图1]"
#define WINDOW_NAME2 "[绘制图2]"
#define WINDOW_WIDTH 600      //定义窗口大小的宏
using namespace cv;
//4.3.1 DrawEllipse()函数
//自定义的绘制函数,实现绘制不同角度、相同尺寸的椭圆
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);
}//4.3.2 DrawFilledCircle()函数
//自定义的绘制函数,实现实心圆的绘制
void DrawFilledCircle(Mat img, Point center)
{int thickness = -1;int lineType = 8;circle(img, center, WINDOW_WIDTH / 32, Scalar(0, 0, 255), thickness, lineType);//图像,圆心,半径,颜色,线粗,线形
}
//4.3.3 DrawPolygon()函数
//自定义的绘制函数,实现凹多边形的绘制
void DrawPolygon(Mat img)
{int lineType = 8;Point rookPoints[1][20];rookPoints[0][0] = Point(WINDOW_WIDTH / 4, 7 * WINDOW_WIDTH / 8);rookPoints[0][1] = Point(3 * WINDOW_WIDTH / 4, 7 * WINDOW_WIDTH / 8);rookPoints[0][2] = Point(3 * WINDOW_WIDTH / 4, 13 * WINDOW_WIDTH / 16);rookPoints[0][3] = Point(11 * WINDOW_WIDTH / 16, 13 * WINDOW_WIDTH / 16);rookPoints[0][4] = Point(19 * WINDOW_WIDTH / 32, 3 * WINDOW_WIDTH / 8);rookPoints[0][5] = Point(3 * WINDOW_WIDTH / 4, 3 * WINDOW_WIDTH / 8);rookPoints[0][6] = Point(3 * WINDOW_WIDTH / 4, WINDOW_WIDTH / 8);rookPoints[0][7] = Point(26 * WINDOW_WIDTH / 4, WINDOW_WIDTH / 8);rookPoints[0][8] = Point(26 * WINDOW_WIDTH / 4, WINDOW_WIDTH / 4);rookPoints[0][9] = Point(22 * WINDOW_WIDTH / 4, WINDOW_WIDTH / 4);rookPoints[0][10] = Point(22 * WINDOW_WIDTH / 4, WINDOW_WIDTH / 8);rookPoints[0][11] = Point(18 * WINDOW_WIDTH / 4, WINDOW_WIDTH / 8);rookPoints[0][12] = Point(18 * WINDOW_WIDTH / 4, WINDOW_WIDTH / 4);rookPoints[0][13] = Point(14 * WINDOW_WIDTH / 4, WINDOW_WIDTH / 4);rookPoints[0][14] = Point(14 * WINDOW_WIDTH / 4, WINDOW_WIDTH / 8);rookPoints[0][15] = Point(WINDOW_WIDTH / 4, WINDOW_WIDTH / 8);rookPoints[0][16] = Point(WINDOW_WIDTH / 4, 3 * WINDOW_WIDTH / 8);rookPoints[0][17] = Point(13 * WINDOW_WIDTH / 4, 3 * WINDOW_WIDTH / 8);rookPoints[0][18] = Point(5 * WINDOW_WIDTH / 4, 13 * WINDOW_WIDTH / 16);rookPoints[0][19] = Point(WINDOW_WIDTH / 4, 13 * WINDOW_WIDTH / 16);const Point* ppt[1] = { rookPoints[0] };//多边形顶点集int npt[] = { 20 }; //多边形顶点数目fillPoly(img, ppt, npt, 1, Scalar(255, 255, 255), lineType);//图像,顶点集,顶点数目,要绘制的多边形数量,颜色,线形
}
//4.3.4 DrawLine()函数
//自定义绘制函数,实现线的绘制
void DrawLine(Mat img, Point start, Point end)
{int thickness = 2;int lineType = 8;line(img, start, end, Scalar(0, 0, 0), thickness, lineType);
}
int main()
{//创建空白的Mat图像Mat atomImage = Mat::zeros(WINDOW_WIDTH, WINDOW_WIDTH, CV_8UC3);Mat rookImage = Mat::zeros(WINDOW_WIDTH, WINDOW_WIDTH, CV_8UC3);//-------------------<1>绘制化学中的原子示例图--------------------------//1.绘制椭圆DrawEllipse(atomImage, 90);DrawEllipse(atomImage, 0);DrawEllipse(atomImage, 45);DrawEllipse(atomImage, -45);//2.绘制圆心DrawFilledCircle(atomImage, Point(WINDOW_WIDTH / 2, WINDOW_WIDTH / 2));//-------------------------<2>绘制组合图---------------------------//1.绘制椭圆DrawPolygon(rookImage);//2.绘制矩形rectangle(rookImage, Point(0, 7 * WINDOW_WIDTH / 8), Point(WINDOW_WIDTH, WINDOW_WIDTH), Scalar(0, 255, 255), -1, 8);//3.绘制一些线段DrawLine(rookImage, Point(0, 15 * WINDOW_WIDTH / 16), Point(WINDOW_WIDTH, 15 * WINDOW_WIDTH / 16));DrawLine(rookImage, Point(WINDOW_WIDTH/4, 7 * WINDOW_WIDTH / 8), Point(WINDOW_WIDTH/4, WINDOW_WIDTH));DrawLine(rookImage, Point(WINDOW_WIDTH / 2,7 * WINDOW_WIDTH/8), Point(WINDOW_WIDTH/2, WINDOW_WIDTH));DrawLine(rookImage, Point(3 * WINDOW_WIDTH/4, 7 * WINDOW_WIDTH / 8), Point(3 * WINDOW_WIDTH/4, WINDOW_WIDTH));//显示绘制图像imshow(WINDOW_NAME1, atomImage);cvMoveWindow(WINDOW_NAME1, 0, 200);imshow(WINDOW_NAME2, rookImage);cvMoveWindow(WINDOW_NAME2, WINDOW_WIDTH, 200);waitKey(0);return 0;
}

4.4 颜色空间拓展

  图像彩色模型包括RGB模型、CMY模型、HSI模型、YIQ模型、YUV模型、YCbCr模型等

4.4.1 RGB彩色模型

  RGB彩色模型基于笛卡尔坐标系统,红、绿、蓝、青、深红、黄、黑和白分别位于立方体各个顶点,灰度级沿黑和白两点的连线分布。不同的颜色可以用从原点分布的向量来定义。归一化彩色子空间立方体如图所示:
                

4.4.2 HSI彩色模型

  用色调、饱和度和强度描述彩色图像。饱和度是纯彩色被白光冲淡程度的度量,色调是用来描述纯色的属性,强度(灰度)是单色图像的描述算子。该模型可从彩色信息中消除强度分量的影响,更符合人类的视觉特性,是一种理想的彩色图像处理工具。

4.4.3 RGB与HSI彩色模型之间的转换

(1)RGB转换为HSI

  色调分量转换公式:
                  
  其中,
              
  饱和度分量转换公式:
                  
  亮度分量转换公式:
                    

(2)HSI转换为RGB

  RG区():若H在这个区域内,RGB分量公式为:
                   
  GB区():若H在这个区域内,RGB分量公式为:
                   
  BR区():若H在这个区域内,RGB分量公式为:
                   

《OpenCV3编程入门》学习笔记4 OpenCV数据结构与基本绘图相关推荐

  1. 原创 OpenCV3编程入门 学习笔记(总)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/qq_36163358/article/ ...

  2. OpenCV3编程入门 学习笔记(总)

    OpenCV3编程入门 学习笔记 2018.12.12-2018.12.29 此博客为在看过毛星云版<OpenCV3编程入门>后所总结的一本笔记,可供复习使用. 文章目录 OpenCV3编 ...

  3. Opencv3编程入门学习笔记(五)之通道分离(split)与合并(merge)

    若要对Opencv中(BGR)颜色通道进行单一处理,那必然会涉及到通道分离(split)与合并(merge).那么本篇博客笔者记录了两个方法的使用方法和案例.案例来源于<Opencv3编程入门学 ...

  4. 【OpenCV3编程入门学习笔记】——第1章 邂逅OpenCV

    邂逅OpenCV 文章目录 邂逅OpenCV 前言 1.1 OpenCV周边概念认知 1.1.1 图像处理.计算机视觉与OpenCV 1.1.2 OpenCV概述 1.1.3 起源及发展 1.1.4 ...

  5. Opencv3编程入门学习笔记(三)之访问图像像素的三种方法

    访问图像像素的三种方法:指针访问,迭代器访问,动态地址访问.访问最快的为指针访问,以下算法在几毫秒,但指针访问容易造成内存泄漏:其次为迭代器访问:最后为动态地址访问. 以下程序是根据<OpenC ...

  6. 【OpenCV3编程入门学习笔记】——第3章 HighGUI图形用户界面初步

    文章目录 前言 3.1 图形的载入.显示和输出到文件 3.1.1 OpenCV的命名空间 3.1.2 Mat类简析 3.1.3 图像的载入与显示概述 3.1.4 图像的载入:imread()函数 3. ...

  7. Opencv3编程入门学习笔记(四)之split通道分离Debug过程中0xC0000005内存访问冲突问题

    这是笔者学习<Opencv3编程入门>的第四篇博客,这篇博客主要是解决在Windows系统下VS 2013中Debug含有split分离通道色彩函数时报出的0xC0000005内存访问冲突 ...

  8. Opencv3编程入门学习笔记(二)之显式创建Mat对象

    以下总结是基于<Opencv3编程入门>一书4.1节总结的内容进行验证与总结,验证环境均为Windows10 ---VS2013 C++环境,验证Opencv3.0提供的开发包. 1. 方 ...

  9. 01.Java 编程入门学习笔记20210307

    Java 编程入门学习笔记-day01 第0章:编程入门 1.计算机的概述 计算机 = 硬件 + 软件 1.1硬件:冯诺依曼体系 CPU: CPU的衡量标准:速度的计量单位是赫兹(Hz),1Hz相当于 ...

最新文章

  1. SecutrCRTt 连接VirtualBox 中的Ubuntu -端口转发
  2. Java中的IO整理完整版
  3. C#——LINQ技术DEMO
  4. 概率分布之间的距离度量以及python实现(三)
  5. 在github上搭建hexo博客
  6. 随便讲讲自己了解的ajax在JQ中的应用
  7. linux下dns服务器部署,linux系统下部署DNS服务器
  8. 盘点那些跨界玩到飞起的程序员们!
  9. 简述线程,程序、进程的基本概念。以及他们之间关系是什么?
  10. java学习日记-基础-列出2~100内的素数
  11. 用于小儿肺炎检测的无代码AI
  12. ArcGIS+Fragstats软件进行景观格局指数分析(附练习数据下载)
  13. 怎么用java打开pkg文件怎么打开,pkg文件怎么打开 【处置方式】
  14. JavaAwtSwing笔记之 Frame和JFrame的区别
  15. “我是技术总监,我确实答不出那么多技术细节”
  16. 网站服务器在本地是指,本地域名是什么意思?本地域名服务器在哪?
  17. Matplotlib-Python-绘制基础饼形图,分裂饼形图,环形饼形图
  18. 中医学专业学c语言吗,考研专业课中医学题型分析
  19. 1 CRM需求分析,数据库表,录入数据
  20. 2018 WAIC |最强阵容!各界大咖齐聚,推动视觉智能全领域发展

热门文章

  1. VS Code 配置调试参数、launch.json 配置文件属性、task.json 变量替换、自动保存并格式化、空格和制表符、函数调用关系、文件搜索和全局搜索、
  2. Linux shell 学习笔记(1)— 文件和目录(查看、创建、复制、软硬链接、重命名及删除操作)
  3. LeetCode简单题之学生分数的最小差值
  4. NVIDIA DPU架构
  5. GAAFET与FinFET架构
  6. MindSpore静态图语法支持
  7. 固件安全性—防止内存损坏和注入攻击
  8. 每秒能捕捉万亿帧的相机
  9. 基于TensorRT车辆实时推理优化
  10. 构建深度学习框架运行平台