OpenCV数据结构与基本绘图(Mat 类、Point类、Scalar类等)
文章目录
- 1.基础图像容器 Mat
- 1.1Mat 结构的使用
- 1.2像素值的存储方法
- 1.3 显示创建 Mat 对象的七种方法
- 1.3.1 Mat 的常用构造函数
- 1.4 OpenCV 中的格式化输出方法
- 1.5 输出其他常用数据结构
- 1.6 取对角线元素
- 1.7 Mat 表达式
- 1.8 Mat 与 IplImage 和 CvMat 的转换
- 1.8.1 Mat 转换为 IplImage 和 CvMat
- 1.8.2 IplImage 和 CvMat 格式转为 Mat
- 2 常用的数据结构和函数
- 2.1 点的表示:Point 类
- 2.2 颜色的表示:Scalar 类
- 2.3 尺寸的表示:Size 类
- 2.4 矩形的表示:Rect 类
- 2.5 颜色空间转换:cvtColo()函数
- 2.6 其他常用知识
- 3.基本图形的绘制
- 3.1 DrawEclipse() 函数的写法
- 3.2 DrawFilledCircle() 函数的写法
- 3.3 DrawPolygon() 函数的写法
- 3.4 DrawLine() 函数的写法
- 3.5 main 函数的写法
1.基础图像容器 Mat
1.1Mat 结构的使用
Mat 是一个类,由两个数据部分组成:矩阵头(包含矩阵尺寸、存储方法,存储地址等信息)和一个指向所有像素值的矩阵(根据所选存储方法的不同,矩阵可以是不同的维数)的指针。矩阵头的尺寸是常数值,但矩阵本身的尺寸会依图像的不同而不同,通常比矩阵头的尺寸大数个数量级。因此在程序中传递图像并创建副本时,大的开销是由矩阵造成的,而不是信息头。
为了解决开销问题,OpenCV 使用了引用计数机制。其思路是让每个 Mat 对象都拥有自己的信息头,但共享同一个矩阵。这通过让矩阵指针指向同一个地址实现。而拷贝构造函数则只复制信息头和矩阵指针,而不复制矩阵。
Mat A,C; //仅创建信息头部分A = imread("1.jpg, CV_LOAD_IMAGE_COLOR); //为矩阵开辟内存Mat B(A); //使用拷贝构造函数C = A; //赋值运算
我们可以创建只引用部分数据的信息头。比如想要创建一个感兴趣区域(ROI,region of interest),只需要创建包含边界信息的信息头:
Mat D (A ,Rect(10, 10, 100)); //使用矩形界定Mat E = A(Range:all(), Range(1,3)); //用行和列界定
对于矩阵的清理:通过引用计数机制来实现,我们无论什么时候复制一个 Mat 对象的信息头,都会增加矩阵的引用次数,反之,当一个头被释放后,这个计数被减一,当计数为零时,矩阵就会被清理。但某些时候想复制矩阵本身时(不是信息头和矩阵指针)。这时可以使用函数 clone() 或者 copyTo()。
Mat F = A.clone();Mat G;A.copyTo(G);
现在改变 F 或者 G就不会影响 Mat 信息头所指向的矩阵。
可总结为以下四个要点:
● OpenCV 函数中输出图像的内存分配是自动完成的(如果不特别指定的话)。
● 使用 OpenCV 的 C++ 接口时不需要考虑内存释放的问题。
● 赋值运算符和拷贝构造函数(构造函数)只复制信息头。
● 使用函数 clone() 或者 copyTo() 来复制一幅图像的矩阵。
1.2像素值的存储方法
存储像素值需要指定颜色空间和数据类型。颜色空间是指对于一个给定的颜色,如何组合颜色元素以对其编码。
GRB 颜色空间是最常用的颜色空间,它的基色是红色、绿色和蓝色,有时为了表示透明颜色也会加入第四个元素 alpha(A)。
颜色系统有很多,它们各有优势:
● GRB 是最常见的,这是因为人眼采用相似的工作机制,它也被显示设备所采用。
● HSV 和 HLS 把颜色分解成色调、饱和度和亮度/明度。这是描述颜色更自然的方式,比如可以通过抛弃最后一个元素,使算法对输入图像的光照条件不敏感。
● YCrCb 在 JPEG 图像格式中广泛使用。
● CIE Lab* 是一种在感知上均匀的颜色空间,它适合用来度量两个颜色之间的距离。
每个组成元素都有自己的定义域,而定义域取决去其数据类型,如何存储一个元素决定了我们在其定义域上能控制的精度。最小的数据类型是 char ,占一个字节或者 8 位,可以是有符号型(0 ~ 255 之间)或是无符号型(-127 ~ +127)之间。尽管使用三个 char 类型元素已经可以表示 1600 万种颜色可能(使用 GBR 颜色空间),但若使用 float (4 字节,32 位)或 double 型(8 字节,64 位)则能给出更加精细的颜色分辨能力。
1.3 显示创建 Mat 对象的七种方法
Mat 的 " << " 运算符也能将图片写入文件中,但该运算符只对二维矩阵有效。
方法一:使用 Mat 的构造函数:
Mat M(2, 2, CV_8UC3, Scalar(0, 0, 255));cout << "M = " << endl << " " << M << endl << endl;
运行结果:
对于二维多通道图像,需要定义其尺寸,即行数和列数。然后,需要指定存储元素的数据类型以及每个矩阵的点通道数。为此,依以下规则有多种定义:
CV_[位数][带符号与否][类型前缀]C[通道数]
比如 CV_8UC3 表示使用 8 位的 unsigned char 型,每个像素由三个元素组成三通道。而预先定义的 通道数可以多达四个。另外,Scalar 是个 short 型的向量,能使用指定的定制化值来初始化矩阵,它还可以用于表示颜色。当然,若需要更多通道,可以使用大写的宏并把通道数放在小括号中,如方法二。
1.3.1 Mat 的常用构造函数
//1.无参构造函数
Mat::Mat()//2.创建行为 rows,列为 cols,类型为 type 的图像
Mat::Mat(int rows,int cols,int type)//3.创建大小为 size,类型为 type 的图像
Mat::Mat(Size size,int type)//4.创建行数为 rows,列数为 cols,类型为 type 的图像,并将所有元素初始化值为 s
Mat::Mat(int rows,int cols,int type,const Scalar& s)//5.创建大小为 size,类型为 type 的图像,并将所有元素初始化为值 s
Mat::Mat(Size size,int type,const Scalar& s)//6.将 m 赋值给新创建的对象,此处不会对图像数据进行复制,m 和新的图像共用图像数据
Mat::Mat(const Mat& m)/*7.创建行数为 rows,列数为 cols,类型为 type 的图像,此构造函数不创建图像数据所需内存,而是直接使
用 data 所指内存,图像的步长由 step 指定8*/
Mat::Mat(int rows,int cols,int type,void* data,size_t step = AUTO_STEP)//8.创建大小为 size,类型为 type 的图像,此构造函数不创建图像数据所需内存,而是直接使
//用 data 所指内存,图像的步长由 step 指定
Mat::Mat(int rows,int cols,int type,void* data,size_t step = AUTO_STEP)/*9.创建的新图像为 m 的一部分,具体范围由 rowRange 和 colRange 指定,此构造函数也不进行图像数据
的复制操作,新图像与 m 共用图像数据。*/
Mat::Mat(const Mat& m,const Range& rowRange,const Range& colRange)/*10.创建的图像为 m 的一部分,具体的范围 roi 指定,此函数也不进行图像的复制,新图像与原图像共享
图像数据 */
Mat::Mat(const Mat& m,const Rect& roi)
方法二:在 C\C++ 中通过构造函数进行初始化
Mat sz[3] = {2,2,2};Mat L(3, sz, CV_8UC, Scalar::all(0));
上面的例子演示了如何创建一个超过两维的矩阵:指定维数,然后传递一个指向一个数组的指针,这个数组包含两个维度的尺寸,后续两个参数与方法一中的相同。
方法三:为已存在的 IplIamge 指针创建信息头
IplImage 的头文件为: #include<highgui/highgui_c.h>
IplImage* img = cvLoadImage("1,jpg",1);Mat mtx(img); //转换 IplImage* -> Mat;
方法四:利用 Create() 函数
M.create(4, 4, CV_8UC(2));cout << "M = " << endl << " " << M << endl << endl;
运行结果:
需要注意的是,此创建方法不能为矩阵设初值,只是在改变尺寸重新为矩阵开辟内存而已。
方法五:采用 Matlab 式的初始化方法
Matlab 形式的初始化方法有:zeros() , ones() , eyes() 。使用以下方式指定尺寸和数据类型:
Mat E = Mat::eye(4, 4, CV_64F);cout << "E = " << endl << " " << E << endl << endl;Mat O = Mat::ones(2, 2, CV_32F);cout << "O = " << endl << " " << O << endl << endl;Mat Z = Mat::zeros(3, 3, CV_8UC1);cout << "Z = " << endl << " " << Z << endl << endl;
运行结果:
方法六:对小矩阵使用逗号分隔式初始化函数
Mat C = (Mat_<double>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);cout << "C = " << endl << " " << C << endl << endl;
运行结果:
方法七:为已存在的对象创建新信息头
使用成员函数 copyTo() 或 clone() 为一个已存在的 Mat 对象创建一个新的信息头。
Mat RowClone = C.row(1).clone();cout << "RowClone = " << endl << " " << RowClone << endl << endl;
运行结果:
1.4 OpenCV 中的格式化输出方法
先定义一个矩阵以供下列方法使用,可通过 randu() 函数产生的随机值来填充矩阵,需要给一个上限和下限来确保随机值在期望的范围内。
Mat r = Mat(10, 3, CV_8UC3);randu(r, Scalar::all(0), Scalar::all(255));
风格一:OpenCV 默认风格
cout << "r (OpenCV 默认风格) = " << endl << r << ";" << endl << endl;
结果图为:
风格二:Python 风格
cout << "r (Python风格) = " << endl << format(r, Formatter::FMT_PYTHON) << ";" << endl << endl;
结果图为:
风格三:逗号风格(CSV)
cout << "r (逗号分隔风格) = " << endl << format(r, Formatter::FMT_CSV) << ";" << endl << endl;
结果图为:
风格三:Numpy风格
cout << "r (Numpy风格) = " << endl << format(r, Formatter::FMT_NUMPY) << ";" << endl << endl;
结果图为:
风格三:C语言风格
cout << "r (C语言风格) = " << endl << format(r, Formatter::FMT_C) << ";" << endl << endl;
结果图为:
1.5 输出其他常用数据结构
1)定义和输出二维点
Point2f p(6, 2);cout << "二维点 p" << p << ";\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(4);v.push_back(5);cout << "基于 Mat 的 vector : shortvec = " << Mat(v) << ";\n" << endl;
运行结果:
4)定义和输出二维点
定义和输出存放着点的 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 << ";" ;
运行结果:
1.6 取对角线元素
矩阵的对角线元素可以使用Mat类的diag()函数获取,该函数的定义如下:
Mat Mat::diag(int d) const
参数d=0时,表示取主对角线;当参数d>0是,表示取主对角线下方的次对角线,如d=1时,表示取主对角线下方,且紧贴主多角线的元素;当参数d<0时,表示取主对角线上方的次对角线。
如同row()和col()函数,diag()函数也不进行内存复制操作,其复杂度也是O(1)。
1.7 Mat 表达式
如果矩阵 A 与 B 大小相同,则可以使用表达式:
C = A + B + 1
其执行结果是 A 的矩阵元素与 B 的矩阵元素对应相加然后再加 1 ,并将生产的矩阵赋值给 C 变量。
下面给出Mat表达式所支持的运算。下面的列表中使用A和B表示Mat类型的对象,使用s表示Scalar对象,alpha表示double值。
加法,减法,取负:A+B, A-B, A+s, A-s, s+A, s-A,-A缩放取值范围:A*alpha矩阵对应元素的乘法和除法:A.mul(B), A/B, alpha/A矩阵乘法:A*B(注意此处是矩阵乘法,而不是矩阵对应元素相乘)矩阵转置:A.t()矩阵求逆和求伪逆:A.inv()矩阵比较运算:A cmpop B, A cmpop alpha, alpha cmpop A。
此处cmpop 可以是>,>=,==,!=,<=,<。如果条件成立,则结果矩阵(8U类型矩阵)的对应元素被置为255;
否则置 0。矩阵位逻辑运算:A logicop B, A logicop s, s logicop A,~A,此处logicop可以是 &、| 和 ^ 。矩阵对应元素的最大值和最小值:min(A, B), min(A, alpha), max(A, B),max(A, alpha)。矩阵中元素的绝对值:abs(A)叉积和点积:A.cross(B), A.dot(B)
下面展示了 Mat 表达式的使用方法:
#include<opencv2/opencv.hpp>
#include<time.h>
#include<iostream>using namespace std;
using namespace cv;int main(int argc, char* argv[]) {system("color 2F");//eye 为构建单位矩阵Mat A = Mat::eye(4, 4, CV_32SC1);cout << "A = " << endl << A << endl << endl;Mat B = A * 3 + 1;cout << "B = " << endl << B << endl << endl;//diag(0) 为从第 1 列开始取对角线元素,col(1) 为取 B 的第 2 行元素//diag(1) 为从第 2 列开始取 (rows - 1) x (cols - 1) 对角线元素Mat C = B.diag(0) + B.col(1); cout << "C = " << endl << C << endl << endl;cout << "C .* diag(B) = " << C.dot(B.diag(0)) << endl;//waitKey(0);system("pause");return 0;
}
运行结果:
5x4 + 8x4 + 5x4 + 5x4 = 92。
1.8 Mat 与 IplImage 和 CvMat 的转换
1.8.1 Mat 转换为 IplImage 和 CvMat
假如你有一个以前写的函数,函数的定义为:
void mycvOldFunc(IplImage *p, …);
函数的参数需要Ipllmage类型的指针。Mat转为Ipllmage,可以用简单的等号赋值操作来进行类型转换,这样实现:
Mat img(Size(320, 240), CV 8UC3);
IplImage iplimg = img; //转为IplImage结构
mycvOldFunc(&iplimq, …);//对Iplimq取地址
如果要转为 CvMat 类型,操作类似:
CvMat cvimg = img; //转为 CvMat 结构
示例:
char path[100] = "E:\\OpenCV\\1.jpg";Mat ig = imread(path);IplImage img1 = ig;IplImage* img2 = &img1;cvShowImage("img1", img2);
需要特别注意的是,类型转换后,IplImage 和 CvMat 与 Mat 共用同一矩阵数据,Ipllmage 和 CvMat 没有引用计数功能,如果上例中的 img 中数据被释放,iplimg 和 cvimg 也就失去了数据。因此要牢记不可将 Mat 对象提前释放。
1.8.2 IplImage 和 CvMat 格式转为 Mat
Mat 类有两个构造函数,可以实现 Ipllmage 和 CvMat 到 Mat 的转换。这两个函数都有一个参数 copyData。如果 copyData 的值是 false,那么 Mat 将与 Ipllmage 或 CvMat 共用同一矩阵数据;如果值是 true, Mat 会新申请内存,后将 Ipllmage 或 CvMat 的数据复制到 Mat 的数据区。
如果共用数据,Mat 也将不会使用引用计数来管理内存,需要开发者自己来管理。建议做此转换是将参数置为 true,这样内存管理变得简单。
Mat::Mat(const CvMat* m, bool copyData = false)
Mat::Mat(const IplImage* img, bool copyData = false)
例如:
IplImage* iplimg = cvLoadImage("1.jpg",1);
Mat im(iplimg, true);
2 常用的数据结构和函数
2.1 点的表示:Point 类
Point 类数据结构表示了二维坐标系下的点,即由其图像坐标 x 和 y 指定的 2D 点。用法如下:
Point point;point.x = 10;point.y = 8;//或者Point point = Point(10, 8);//另外,在 OpneCV 下有如下定义:typedef Point_<int> Point2i;typedef Point2i Point;typedef Point_<float> Point2f;
所以,Point_< int > 、Point2i、Point 互相等价,Point_< float > 、Point2f 互相等价。
2.2 颜色的表示:Scalar 类
Scalar() 表示有四个元素的数组,在 OpenCV 中被大量用于传递像素值,如果用不到第四个参数,则不必写出来。
如果给出以下颜色参数表达式:
Scalar(a, b, c);
那么定义的 RGB 颜色值:红色分量为 c ,绿色分量为 b,蓝色分量为 a 。
Scalar 类的源头为 Scalar_ 类,而 Scalar_ 类是 Vec4x 的一个变种,我们常用的 Scalar 其实就是 Scalar< double >。这就解释了为什么很多函数的参数输入可以是 Mat ,也可以是 Scalar。
2.3 尺寸的表示:Size 类
Size 类的相关源码:
typedef Size_<int> Size2i;typedef Size2i Size;
其中,Size_ 是个模板类,Size_< int > 、Size2i、Size 这三个类型名等价。
对于 Size_ 模板类的定义中,我们使用最频繁的是下面这个构造函数:
Size_(_Tp _width, _Tp _heigth);//模板类的高度和宽度_Tp width, height;//于是可用 XXX.width 与 XXX.heigth 分别表示其宽度和高度。
2.4 矩形的表示:Rect 类
Rect 类的成员变量有 x、y、width、heigth,分别为左上角点的坐标和矩形的宽和高。常用的成员函数有: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;
2.5 颜色空间转换:cvtColo()函数
cvtColor() 函数是 OpenCV 中的颜色空间装换函数,可以实现 RGB 颜色空间想 HSV、HIS 等颜色空间转换,也可以转换为灰度图像。原型如下:
void cvtColor(InputArray src, OutputArray dst, int code, int dstCn = 0)
第一个参数为输入图像,第二个参数我输出图像,第三个参数为颜色空间转换的标识符(见下表),第四个参数为目标图像的通道数,若该参数是 0,则表示目标图像取源图像的通道数。
下面是一个调用示例:
cvtColor(srcImage, dstImage, COLOR_GRAY2BGR); //原始图转化为灰度图
需要注意的是:OpenCV 中默认的图片通道存储顺序是 BGR ,即蓝绿红,而不是 RGB。
下面给出颜色空间转换的简单代码:
#include<opencv2/opencv.hpp>using namespace std;
using namespace cv;int main(int argc, char** argv)
{//1.载入图片Mat srcImage = imread("8.jpg"),dstImage;//2.转换颜色空间cvtColor(srcImage, dstImage, COLOR_BGR2Lab);//3.显示原图和效果图imshow("原图", srcImage);imshow("效果图", dstImage);waitKey();//system("pause");return 0;
}
运行结果:
2.6 其他常用知识
● Matx 是个轻量级的 Mat ,必须在使用前规定好大小,比如一个 2 * 3 的 float 型的 Matx,可以声明为 Matx23f。
● Vec 是 Matx 的一个派生类,是一个一维的 Matx ,跟 vector 很相似。
● Range 类其实就是为了使 OpenCV 的使用更像 MATLAB 而产生的。
● OpenCV 中防止内存泄漏的函数有 alignPtr、alignSize、allocate、deallocate、fastMalloc、fastFree 等。
● <math.h> 里的一些函数使用起来很方便,有计算向量角度的函数 fastAtan2、计算立方根的函数 cubeRoot、向上取整函数 cvCeil、向下取整的函数 cvFloor、四舍五入的函数 cvRound 等。还有一些类似于 MATLAB 里的函数,比如 cvIsInf 判断自变量是否无穷大,cvIsNaN 判断自变量是否不是一个数。
● 显示文字相关的函数有 getTextSize、cvInitFont、putText。
● 作图相关的函数有 circle、clipLine、ellipse、ellipse2Poly、line、rectangle、polylines、类 LineIterator。
● 填充相关的函数有 fillConvexPoly、fillPoly。
● OpenCV 中 RNG() 函数的作用为初始化随机数状态的生成器。
3.基本图形的绘制
便于代码的编写,先在开头加上宏定义:
#define WINDOW_WIDTH 600 //定义窗口的大小
3.1 DrawEclipse() 函数的写法
描述:自定义的绘制函数,实现了绘制不同角度、相同尺寸的椭圆
void DrawEclipse(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, //拓展的弧度从 0 到 360360,Scalar(255,129,0), //图形颜色 ,该配置代表蓝色thickness, //线宽为 2lineType); //线型为 8 (8 联通线型)}
此函数的解析如下:
函数中调用了 OpenCV 的 ellipse 函数,将椭圆画到图像 img 上,椭圆中心点为 (WINDOW_WIDTH / 2, WINDOW_WIDTH / 2),并且大小位于矩形 (WINDOW_WIDTH / 4, WINDOW_WIDTH / 16) 内。椭圆旋转角度为 angle,拓展的弧度从 0 到 360 度。图形颜色为 Scalar(255,129,0) 代表的蓝色,线宽 thickness 为 2,线型 lineType 为 8(8 联通线型)。
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), //颜色 按 GBR 为红色thickness, //线粗lineType); }
函数调用了 OpenCV 中的 cirlce 函数,将圆画到图像 img 上,圆心由点 center 定义,圆的半径为 WINDOW_WIDTH / 32 , 圆的颜色为 Scalar(0,0,255),按 BGR 格式为红色,线粗定义为 thickness = -1 ,因此绘制的圆是实心的。
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 / 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 };fillPoly(img, //目标图像ppt, //多边形顶点集npt, //多边形顶点数目1, //要绘制的多边形数量Scalar(255, 255, 255), //多边形颜色--白色lineType);}
该函数调用了 OpenCV 中的 fillPoly 函数,用于将多边形画到图 img 上,其中多边形的顶点集为 ppt ,要绘制的多边形的顶点数目为 npt,要绘制的多边形数量为 1,多边形的颜色设置为白色 Scalar(255, 255, 255)。
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);}
该函数调用了 OpenCV 中的 line 函数,用于在图像 img 上画一条从点 start 到 end 的直线段,线的颜色为 Scalar(0, 0, 0) 代表的黑色,先的粗细为 thickness 为 2,且此线为 8 联通(lineType = 8)。
3.5 main 函数的写法
main 函数的写法非常简单,先创建空白的 Mat 图像,然后调用绘制化学中的原子示例图,接着绘制组合图,最后显示绘制出的图像。
int main(int argc, char** argv){//创建空白的 Mat 图像Mat atomImage = Mat::zeros(WINDOW_WIDTH, WINDOW_WIDTH, CV_8UC3);Mat rookImage = Mat::zeros(WINDOW_WIDTH, WINDOW_WIDTH, CV_8UC3);//-------------1.绘制化学中的原子示例图------------------------//1.1先绘制出椭圆DrawEclipse(atomImage, 90);DrawEclipse(atomImage, 0);DrawEclipse(atomImage, 45);DrawEclipse(atomImage, -45);//1.2再绘制圆心DrawFilledCircle(atomImage, Point(WINDOW_WIDTH / 2, WINDOW_WIDTH / 2));//-------------2.绘制组合图----------------------------//2.1先绘制出椭圆DrawPolygon(rookImage);//2.2绘制矩形rectangle(rookImage,Point(0, 7 * WINDOW_WIDTH / 8), //矩形的一个顶点Point(WINDOW_WIDTH, WINDOW_WIDTH), //对角线上的另一个顶点Scalar(0, 255, 255),-1,8);//2.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);moveWindow(WINDOW_NAME1, 0, 200);imshow(WINDOW_NAME2, rookImage);moveWindow(WINDOW_NAME2, WINDOW_WIDTH, 200);waitKey(0);//system("pause");return 0;}
运行结果:
OpenCV数据结构与基本绘图(Mat 类、Point类、Scalar类等)相关推荐
- 《OpenCV3编程入门》学习笔记4 OpenCV数据结构与基本绘图
第4章 OpenCV数据结构与基本绘图 4.1 基础图像容器Mat 4.1.1 数字图像存储概述 图像在数码设备中的表现形式:像素点矩阵 4.1.2 Mat结构的使用 1.OpenCV1.x时代: ...
- 【OpenCv】c++ 入门认识 Mat 类,单通道 Mat 的基本操作
文章目录 前言 Mat 类 Mat 类的构造方式 Mat 基本操作 单通道 Mat 的基本操作 使用成员变量 rows 和 cols 获取矩阵的行数和列数 使用成员函数 size() 来获取矩阵的尺寸 ...
- OpenCV 笔记(09)— 常用的数据结构和函数(Vec、Point、Scalar、Size、Rect、cvtColor)
1. Vec 对象类型 Vec 是一个主要用于数值向量的模板类.我们可以定义向量的类型和组件的数量: Vec<double, 19> myVector 我们还可以使用任何的预定义类型: t ...
- OPENCV数据结构体系和常用函数
opencv设计了一些基础的数据类型和一些帮助的数据类型 基础数据类型 : 图像类 IplImage: 矩阵类 CvMat; 可变集合类:CvSeq CvSet CvGraph; 多维柱状图混合类:C ...
- OpenCV(四)————认识Mat对象(C++)
内容: 1.什么是Mat 2.Mat的属性与操作 3.创建Mat 1.什么是Mat 图像文件的内存数据对象 对于人类来说,看到一个图像时,脑子里会想到这个图像内容,比如一张帅哥的照片,在我们看来就是帅 ...
- 绘图用的函数及矩形类CRect和矩形结构RECT
绘图一般在视图类的(屏幕/打印机)绘图消息响应函数OnDraw中进行,例如: void CTestView::OnDraw(CDC* /pDC/) { CTestDoc* pDoc = GetDocu ...
- OpenCV 中的 Scalar 类、Vec类
转 自 http://www.bubuko.com/infodetail-1533054.html 文章目录 Scalar 类 Vec 类 Scalar 类 typedef Scalar_<do ...
- OpenCV简单的几何绘图的实例(附完整代码)
OpenCV简单的几何绘图的实例 OpenCV简单的几何绘图的实例 OpenCV简单的几何绘图的实例 #include <opencv2/core.hpp> #include <op ...
- python @修饰符_数据结构与算法之8——抽象数据类型与python类
就算你是特别聪明,也要学习,从头学起!--(俄国)屠格涅夫 本篇文章要说的主要是数据结构与算法和python中关于类(Class)以及异常(Error)的一些基础,虽然很简单,但是必须非常重视.只有在 ...
最新文章
- 弹球游戏python代码含记分模式_python编写弹球游戏的实现代码
- VS2010 定位文件在solution中的位置
- Windows Azure 数据安全(清理和泄漏)
- SqueezeNet
- vue开发 - 将方法绑定到window对象,给app端调用
- 2699元起!格力首款5G手机悄然上架:骁龙765G处理器
- pb程序怎么发布到iis_怎么使用抖音小程序第三方平台系统开发制作发布抖音小程序+教程...
- 每一次结束只是一次新的起点,深有体会。
- 打开游戏要运行19.8亿次 if 语句?黑客嘲讽RockStar游戏代码太烂了
- 萤石云平台接入_前端接入萤石云视频
- visio2016上下标
- GAN网络-简单明了
- Katalon Recorder简介与使用
- 【COCI 2011】送票
- QCharts QValueAxis使用
- 分享2个优质牛肉干的挑选方法
- 必应每日壁纸API HTML 使用必应每日API为背景 css 背景图片 加模糊 遮罩
- OpenCV图像处理 空间域图像增强(图像锐化 1 基于拉普拉斯算子)
- GoPower运动功率计
- Mac OS terminal 查看内存使用情况的命令