opencv学习笔记——数据结构与基本绘图
来源:互联网 发布:淘宝化妆品推广文章 编辑:程序博客网 时间:2024/06/04 17:46
1、基础图像容器Mat
1.1 Mat结构
早期OpenCV的函数库是基于C接口够贱的,使用名为IplImage的结构体存储图像。缺点是退出之前必须release,否则会造成内存泄漏。
OpenCV2.0引入了新的C++接口,使用Mat类数据结构,好处是不必手动为其开辟空间,不必在不需要是立即将空间释放。
Mat类由两个数据部分组成:矩阵头(矩阵尺寸、存储方法、存储地址等)和一个指向存储所有像素值的矩阵(可以是不同的维数)的指针。每个Mat对象有自己的信息头,但通过指针可以共享同一个矩阵。
//所有Mat对象最终都指向同一个数据矩阵,但信息头不同Mat A, C; //仅创建信息头部分A = imread("1.jpg", CV_LOAD_IMAGE_COLOR); //为矩阵开辟空间Mat B(A); //使用拷贝构造函数C = A; //赋值运算符
//只引用部分数据的信息头,创建感兴趣区域(ROI)Mat D(A, Rect(10, 10, 100, 100)); //使用矩形界定Mat E = A(Range:all(), Range(1, 3)); //用行和列来界定
复制/释放一个Mat对象的信息头,会增加/减少矩阵的引用次数,当计数值为零时,矩阵被清理。想要复制矩阵本身而不只是矩阵指针,使用函数clone()和copyTo()。
Mat F = A.clone();Mat G;A.copyTo(G);
1.2 像素值的存储方法
存储像素值需要制定颜色空间和数据类型。颜色空间是指针对一个给定的颜色,如何组合颜色元素以对其编码。例如RGB颜色空间的基色是红、绿、蓝,以及表示透明颜色的alpha(A)。
几种颜色空间:
- RGB最常用,采用人眼相似的工作机制。
- HSV和HLS把颜色分解成色调、饱和度和亮度/明度,是描述颜色更自然的方法。
- YCrCb在JPEG图像格式中广泛使用。
- CIE L*a*b*是一种在感知上均匀的颜色空间,适合用来度量两个颜色之间的距离。
每个组成元素都有自己的定义域,定义域取决于其数据类型,数据类型决定了在其定义域上能够控制的精度。
1.3 显式创建Mat对象
使用Mat()构造函数
Mat M(2, 2, CV_8UC3, Scalar(0, 0, 255));cout << "M = " << endl << " " << M << endl << endl;
首先定义其尺寸,即行数和列数。然后指定存储元素的数据类型以及每个矩阵点的通道数,定义规则:CV_[位数][带符号与否][类型前缀]C[通道数]。Scalar是short型的向量,使用指定的定制化值来初始化矩阵,可以用于表示颜色。
在C\C++中通过构造函数进行初始化
int sz[3] = {2, 2, 2};Mat L(3, sz, CV_8UC, Scalar:all(0));
创建超过二维的矩阵:指定维数,传递一个指向数组的指针,数组包含每个维度的尺寸。
使用IplImage指针创建信息头
IplImage* img = cvLoadImage("1.jpg", 1);Mat mtx(img); //转换IplImage*为Mat
使用Create()函数
M.Create(4, 4, CV_8UC(2));
此方法不能为矩阵设初值,改变尺寸是重新为矩阵开辟内存。
采用Matlab式初始化方式
Mat E = Mat::eye(4, 4, CV_64F);Mat O = Mat::ones(2, 2, CV_32F);Mat Z = Mat::zeros(3, 3, CV_8UC1);
采用Matlab形式初始化方式:zeros()、ones()、eye()。
小矩阵使用逗号分隔式初始化函数
Mat C = (Mat_<double>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
为已存在的对象创建新信息头
Mat RowClone = C.row(1).clone();
使用函数clone()或copyTo()为已存在的Mat对象创建一个新的信息头。
1.4 格式化输出方法
Mat r = Mat(10, 3, CV_8UC3);randu(r, Scalar::all(0), Scalar::all(255));
给定一个上限和下限,使用randu()函数产生的随机值来填充矩阵。
OpenCV默认风格
cout << "r (OpenCV默认风格) = " << r << ";" << endl << endl;
Python风格
//OpenCV2版cout << "r (Python风格) = " << format(r, "python") << ";" << endl << endl;//OpenCV3版cout << "r (Python风格) = " << format(r, Formatter::FMT_PYTHON) << ";" << endl << endl;
逗号分隔风格
//OpenCV2版cout << "r(逗号分隔风格) = " << format(r, "cvs") << ";" << endl << endl;//OpenCV3版cout << "r(逗号分隔风格) = " << format(r, Formatter::FMT_CVS) << ";" << endl << endl;
Numpy风格
//OpenCV2版cout << "r(Numpy风格) = " << format(r, "numpy") << ";" << endl << endl;//OpenCV3版cout << "r(Numpy风格) = " << format(r, Formatter::FMT_NUMPY) << ";" << endl << endl;
C语言风格
//OpenCV2版cout << "r(C语言风格) = " << format(r, "C") << ";" << endl << endl;//OpenCV3版cout << "r(C语言风格) = " << format(r, Formatter::FMT_C) << ";" << endl << endl;
1.5 输出其他常用数据结构
定义二维点
Point2f p(6, 2);
定义三维点
Point3f p3f(8, 2, 0);
定义基于Mat的std::vector
vector<float> v;v.push_back(3);v.push_back(5);v.push_back(7);
定义std::vector点
vector<Point2f> points(20);for (size_t i; i < points.size(); ++i) points[i] = Point2f((flaot)i * 5, float(i % 7));
2、示例程序
2.1 常用数据结构和函数
Point类:点的表示
//定义方式Point point;point.x = 10;point.y = 8;Point point = Point(10, 8);//OpenCV定义typedef Point_<int> Point2i;typedef Point2i Point;typedef Point_<float> Point2f;
Scalar类:颜色的表示
Scalar()表示4个元素的数组,被大量用于传递像素值。
Scalar(a, b, c);
定义RGB值,a表示蓝色,b表示绿色,c表示红色,只使用单个参数。
Scalar类基于Scalar_类,Scalar_类基于Vec4x类。很多函数的参数可以是Mat,也可以是Scalar。
Size类:尺寸的表示
//Size类的定义typedef Size_<int> Size2i;typedef Size2i Size;Size(5, 5);
构造出的Size的宽度和高度都为5,可以用XXX.height和XXX.width表示。
Rect类:矩形的表示
Rect类的成员变量有x、y、width、height,表示左上角点的坐标和矩形的宽和高。常用的成员函数:
Size()返回值为Size;
area()返回矩形的面积;
contains(Point)判断点是否在矩形内;
inside(Rect)判断矩形是否在该矩形内;
tl()返回左上角点的坐标;
br()返回右下角点的坐标。
//求两个矩形的交集和并集Rect rect = rect1 & rect2;Rect rect = rect1 | rect2;//矩形的平移操作和缩放操作Rect rectShift = rect + point;Rect rectScale = rect + size;
cvtColor()函数:颜色空间转换
//函数原型void cvtColor(InputArray src, OutputArray dst, int code, int dstCn = 0)
第一个参数为输入图像,第二个参数为输出图像,第三个参数为颜色空间转换的标识符,第四个参数为目标图像的通道数,0表示取源图像的通道数。
2.2 其他知识点
- Matx是轻量级的Mat,必须在使用前规定好大小,如2*3的float型Matx,声明为Matx23f;
- Vec是Matx的派生类,是一维的Matx;
- Range类类似MATLAB使用;
- 防止内存溢出函数:alignPtr、alignSize、allocate、deallocate、fastMalloc、fastFree;
- math.h中函数fastAtan2计算向量角度、cubeRoot计算立方根、cvCeil向上取整、cvFloor向下取整、cvRound四舍五入、cvIsInf判断自变量是否无穷大、cvIsNaN判断自变量是否不是一个数。
- 显示文字的函数:getTextSize、cvInitFont、putText;
- 作图函数:circle、clipLine、ellipse、ellipse2Poly、line、rectangle、polylines、类LineIterator;
- 填充函数:fillConvexPoly、fillPoly;
- RNG()函数为初始化随机数状态的生成器。
2.3 示例程序
#include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>#include <opencv2/imgproc/imgproc.hpp>using namespace cv;/* 定义辅助宏 */#define WINDOW_NAME1 "【绘制图1】" //为窗口标题定义的宏#define WINDOW_NAME2 "【绘制图2】" //为窗口标题定义的宏#define WINDOW_WIDTH 600 //定义窗口大小的宏/* 绘制不同角度相同尺寸的椭圆 */void DrawEllipse(Mat img, double angle){ int thickness = 2; int lineType = 8; //将椭圆画到img上,中心为点Point,位于矩形Size内,椭圆角度为angle,扩展弧度0到360度 //图形颜色为Scalar,线宽为2,线型为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);}/* 绘制实心圆 */void DrawFilledCircle(Mat img, Point center){ int thickness = -1; int lineType = 8; //将圆画到img上,圆心为点center,半径为WINDOW_WIDTH/32,颜色为Scalar,线粗-1,线型为8 circle(img, center, WINDOW_WIDTH / 32, Scalar(0, 0, 255), thickness, lineType);}/* 绘制凹多边形 */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 / 40, WINDOW_WIDTH / 8); rookPoints[0][8] = Point(26 * WINDOW_WIDTH / 40, WINDOW_WIDTH / 4); rookPoints[0][9] = Point(22 * WINDOW_WIDTH / 40, WINDOW_WIDTH / 4); rookPoints[0][10] = Point(22 * WINDOW_WIDTH / 40, WINDOW_WIDTH / 8); rookPoints[0][11] = Point(18 * WINDOW_WIDTH / 40, WINDOW_WIDTH / 8); rookPoints[0][12] = Point(18 * WINDOW_WIDTH / 40, WINDOW_WIDTH / 4); rookPoints[0][13] = Point(14 * WINDOW_WIDTH / 40, WINDOW_WIDTH / 4); rookPoints[0][14] = Point(14 * WINDOW_WIDTH / 40, 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 / 32, 3 * WINDOW_WIDTH / 8); rookPoints[0][18] = Point(5 * WINDOW_WIDTH / 16, 13 * WINDOW_WIDTH / 16); rookPoints[0][19] = Point(WINDOW_WIDTH / 4, 13 * WINDOW_WIDTH / 16); const Point* ppt[1] = { rookPoints[0] }; int npt[] = { 20 }; //多边形的顶点集为ppt,顶点数为npt,绘制数量为1,颜色为Scalar,线型为8 fillPoly(img, ppt, npt, 1, Scalar(255, 255, 255), lineType);}/* 绘制线 */void DrawLine(Mat img, Point start, Point end){ int thickness = 2; int lineType = 8; //画一条从start到end的线 line(img, start, end, Scalar(0, 0, 0), thickness, lineType);}int main(void){ 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)); 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); moveWindow(WINDOW_NAME1, 0, 200); imshow(WINDOW_NAME2, rookImage); moveWindow(WINDOW_NAME2, WINDOW_WIDTH, 200); waitKey(0); return 0;}
- opencv学习笔记——数据结构与基本绘图
- OpenCV笔记(一)——数据结构与基本绘图
- OpenCv的数据结构与基本绘图
- openCV—基本绘图
- OpenCV3——数据结构与基本绘图
- 《学习opencv》笔记——基本数据结构,CvMat,矩阵访问
- 【OpenCV学习笔记】七、基本绘图函数
- OpenCV学习:基本绘图
- OpenCV学习笔记(17)OpenCV之基本绘图
- OpenCV学习笔记(18)OpenCV之基本绘图2
- OpenCV 学习记录3 数据结构和基本绘图
- OpenCV学习——基本数据结构
- OpenCV—基本数据结构与示例
- OpenCV—基本数据结构与示例
- 学习OpenCV范例(六)——基本绘图
- OpenCV 学习笔记 [1] 基本数据结构, CvMat
- Opencv学习笔记(二):Opencv中的基本数据类型与数据结构
- 《学习opencv》笔记——关于一些绘图的函数
- LightOJ 1348 Aladdin and the Return Journey(树链剖分)
- 纪念碑谷附录六(幻像城堡)
- 纪念碑谷附录七(密牢)
- Sed命令n,N,d,D,p,P,h,H,g,G,x解析
- Reactor3 响应式编程方式 spring5 已近支持
- opencv学习笔记——数据结构与基本绘图
- CodeForces 687B(剩余定理)
- 2017.11.6笔记
- npm怎么降级
- Error: recoverUnfinalizedSegments failed for required journal
- 2017题签
- 二叉排序数(创建,插入,删除,查找及前序、中序、后序遍历)
- Java中final变量为什么在使用前必须要进行初始化
- Android开发常用权限和依赖