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

	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;

运行结果:
OpenCV数据结构与基本绘图(Mat 类、Point类、Scalar类等)_第1张图片
  需要注意的是,此创建方法不能为矩阵设初值,只是在改变尺寸重新为矩阵开辟内存而已。

方法五:采用 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;

运行结果:
OpenCV数据结构与基本绘图(Mat 类、Point类、Scalar类等)_第2张图片
方法六:对小矩阵使用逗号分隔式初始化函数

	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;

结果图为:
OpenCV数据结构与基本绘图(Mat 类、Point类、Scalar类等)_第3张图片

风格二:Python 风格

cout << "r (Python风格) = " << endl << format(r, Formatter::FMT_PYTHON) << ";" << endl << endl;

结果图为:
OpenCV数据结构与基本绘图(Mat 类、Point类、Scalar类等)_第4张图片

风格三:逗号风格(CSV)

cout << "r (逗号分隔风格) = " << endl << format(r, Formatter::FMT_CSV) << ";" << endl << endl;

结果图为:
OpenCV数据结构与基本绘图(Mat 类、Point类、Scalar类等)_第5张图片

风格三:Numpy风格

cout << "r (Numpy风格) = " << endl << format(r, Formatter::FMT_NUMPY) << ";" << endl << endl;

结果图为:
OpenCV数据结构与基本绘图(Mat 类、Point类、Scalar类等)_第6张图片

风格三:C语言风格

cout << "r (C语言风格) = " << endl << format(r, Formatter::FMT_C) << ";" << endl << endl;

结果图为:
OpenCV数据结构与基本绘图(Mat 类、Point类、Scalar类等)_第7张图片

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

运行结果:
OpenCV数据结构与基本绘图(Mat 类、Point类、Scalar类等)_第8张图片

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
#include
#include

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

运行结果:
OpenCV数据结构与基本绘图(Mat 类、Point类、Scalar类等)_第9张图片
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数据结构与基本绘图(Mat 类、Point类、Scalar类等)_第10张图片

  需要注意的是:OpenCV 中默认的图片通道存储顺序是 BGR ,即蓝绿红,而不是 RGB。
  下面给出颜色空间转换的简单代码:

#include

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

运行结果:
OpenCV数据结构与基本绘图(Mat 类、Point类、Scalar类等)_第11张图片

2.6 其他常用知识

  ● Matx 是个轻量级的 Mat ,必须在使用前规定好大小,比如一个 2 * 3 的 float 型的 Matx,可以声明为 Matx23f。
  ● Vec 是 Matx 的一个派生类,是一个一维的 Matx ,跟 vector 很相似。
  ● Range 类其实就是为了使 OpenCV 的使用更像 MATLAB 而产生的。
  ● OpenCV 中防止内存泄漏的函数有 alignPtr、alignSize、allocate、deallocate、fastMalloc、fastFree 等。
  ● 里的一些函数使用起来很方便,有计算向量角度的函数 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 到 360
			360,
			Scalar(255,129,0),		//图形颜色 ,该配置代表蓝色
			thickness,		//线宽为 2
			lineType);		//线型为 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类等)_第12张图片

OpenCV数据结构与基本绘图(Mat 类、Point类、Scalar类等)_第13张图片

你可能感兴趣的:(#,OpenCV,#,OpenCV3编程入门读书笔记)