笔记系列
参考书籍:OpenCV3编程入门
作者:毛星云
版权方:电子工业出版社
出版日期:2015-02
笔记仅供本人参考使用,不具备共通性
笔记中代码均是OpenCV+Qt的代码,并非用vs开发,请勿混淆
本章核心函数/类清单
函数/类名称 | 说明 | 对应讲解章节 |
---|---|---|
Mat::mat() | Mat类的构造函数 | 4.1.4 |
Mat::Creat() | Mat类的成员函数,可用于Mat类的初始化操作 | 4.1.1 |
Point类 | 用于表示点的数据结构 | 4.2.1 |
Scalar类 | 用于表示颜色的数据结构 | 4.2.2 |
Size类 | 用于表示尺寸的数据结构 | 4.2.3 |
Rect类 | 用于表示矩形的数据结构 | 4.2.4 |
cvtColor | 用于颜色空间转换 | 4.2.5 |
Mat类的好处
Mat是一个类,由两个数据部分组成
矩阵头的尺寸是常数值,但存储像素值的矩阵本身会以图象的大小不同而不同(通常都比矩阵头大上数个数量级),因此,在程序中传递图像并创建副本时,大的内存开销是由矩阵造成的
OpenCV是一个图像处理库,囊括了大量的图像处理函数,为了解决问题通常要使用库中的多个函数,因此传递图像(并创建副本)是常有的事,但基于上一条的原因,所以不到万不得已,尽量不要进行大图像的复制,因为这会降低程序的运行速度
当然OpenCV也设法解决了上面的问题-----引用计数机制
来看下面这段代码
Mat A,C;//仅创建信息头部分
A = imread("1.jpg",CV_LOAD_IMAGE_COLOR);//为矩阵开辟内存,并将图片存入
Mat B(A);//使用拷贝构造函数
C = A;//使用赋值运算符
上面代码中的A、B、C三个对象最终都指向同一个数据矩阵
虽然A、B、C三个对象的信息头不一样,但是通过任何一个对象所作的改变也会影响到其他对象
矩阵指针指向同一个数据矩阵的不同Mat对象只是访问相同数据的不同途径而已
OpenCV还可以创建只引用一部分数据的信息头,如下
//创建一个感兴趣区域(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);
通过上面的操作,现在对F和G做出改变就不会影响到A,B,C三个对象所指向的矩阵了
总结:
颜色空间
RGB
是最常见的,因为其基色是人眼内部构成颜色的方式HSV
和HLS
把颜色分解成色调、饱和度和亮度/透明的
YCrCB
在JPEG图像格式中广泛使用CIE L*a*b*
是一种在感知上均匀的颜色空间,它适合用来度量两个颜色之间的距离数据类型
可以通过Mat的运算符"<<"来查看图像矩阵的实际值,但是该方法只对二维矩阵有效果
Mat不单是一个非常有用的图像类容器,同时也是一个通用的矩阵类,我们可以用它来创建和操作多为矩阵
创建Mat对象的方法有:
最简单的方法
Mat M(2,2,CV_8UC3,Scalar(0,0,255));
cout<<"M = "<<endl<<""<<M<<endl<<endl;
//Qt Creator中如果要使用cout,需要像VS里面那样,#includ ,同时using namespace std;
上述代码运行效果(Qt Creator中)
对于二维通道图像
首先要定义其尺寸,即行数和列数
然后需要指定存储元素的数据类型和每个矩阵点的通道数(CV_8UC3)
对此,可以依据下面的规则来定义
CV_[The number of bits per item][Signed or Unsigned][Type Prefix]C[The channel number]
即:
CV_[位数][带符号与否][类型前缀]C[通道数]
比如
CV_32FC3参数的含义
int sz[3] = {2,2,2};
Mat M(3,sz,CV_8UC(2),Scalar::all(0));
//cout<<"M = "<
上面的例子演示了如何创建一个超过两维的矩阵
首先指定位数3(Mat构造函数的第一个参数)
然后,传递一个指向一个数组的指针sz(Mat构造函数的第二个参数)
&sz
,因为在C语言中,数组名就是指向该数组的第一个数组元素的地址后面两个参数与方法一中的相同,不再赘叙
cout<<"M = "<
这句代码是不能写在此处的,因为用Mat的"<<"字符来查看矩阵元素只对二维矩阵有效果
如果写了这句代码,则系统会报错
OpenCV: terminate handler is called! The last OpenCV error is:
OpenCV(3.4.13) Error: Assertion failed (m.dims <= 2) in FormattedImpl, file D:\opencv\opencv-3.4.13\modules\core\src\out.cpp, line 86
上述错误信息中,有这么一句:(m.dims <= 2)
就是在提醒开发者,只有维度小于等于2的矩阵才可以cout出来
(1) IplImage 转 Mat:
IplImage* image = cvLoadImage( "1.jpg");
Mat mat=cvarrToMat(image);
(2)Mat转IplImage:
Mat img = imread("test.jpg");
IplImage* ipl_img = cvCreateImage(cvSize(img.cols, img.rows),IPL_DEPTH_8U,img.channels());
memcpy(ipl_img->imageData, img.data, ipl_img->height * ipl_img->widthStep);
书上写的方法如下,但因为我装的OpenCV版本过高(3.4.13),这些方法都失效了
IplImage* image = cvLoadImage( "1.jpg");
Mat mat(image);
OPENCV 3.4.*版本 mat转IplIMage报错问题的解决方案
Mat M(2,2,CV_32FC3,Scalar(0,0,255));
M.create(4,4,CV_8UC(2));
cout<<"M = "<<endl<<""<<M<<endl<<endl;
需要注意的是,此创建方法不能为矩阵设初值,只是在改变尺寸的时候重新为矩阵数据开辟内存而已
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;
结果如下:
E =
[1, 0, 0, 0;
0, 1, 0, 0;
0, 0, 1, 0;
0, 0, 0, 1]
O =
[1, 1;
1, 1]
Z =
[ 0, 0, 0;
0, 0, 0;
0, 0, 0]
Mat::ones() 和 Mat::zeros()
Mat C = (Mat_<double>(3,3)<<0,-1,0,-1,5,-1,0,-1,0);
cout<<"C = "<<endl<<""<<C<<endl<<endl;
结果如下:
C =
[0, -1, 0;
-1, 5, -1;
0, -1, 0]
如过输入的元素不够矩阵的总元素,则会如下
C =
[0, -1, 0;
-1, 5, -1;
2.143248128504563e-312, 1.958064995486337e-306, 0]
如上:未输入元素会变成不可预知的值
使用成员函数clone()或者copyTo()为一个已经存在的Mat对象创建一个新的信息头
Mat C = (Mat_<double>(3,3)<<0,-1,0,-1,5,-1,0,0,0);
cout<<"C = "<<endl<<""<<C<<endl<<endl;
Mat RowClone = C.row(1).clone();
cout<<"RowClone = "<<endl<<""<<RowClone<<endl<<endl;
结果如下:
C =
[0, -1, 0;
-1, 5, -1;
0, 0, 0]
RowClone =
[-1, 5, -1]
首先先定义一个R矩阵,使用Randu()函数产生的随机数来填充矩阵,当然需要给定一个上限和下限来确保随机值在期望的范围内
Mat r = Mat(10,3,CV_8UC3);
randu(r,Scalar::all(0),Scalar::all(255));
cout<<"r (OpenCV default style)="<<endl<<r<<";"<<endl<<endl;
效果如下
r (OpenCV default style)=
[ 91, 2, 79, 179, 52, 205, 236, 8, 181;
239, 26, 248, 207, 218, 45, 183, 158, 101;
102, 18, 118, 68, 210, 139, 198, 207, 211;
181, 162, 197, 191, 196, 40, 7, 243, 230;
45, 6, 48, 173, 242, 125, 175, 90, 63;
90, 22, 112, 221, 167, 224, 113, 208, 123;
214, 35, 229, 6, 143, 138, 98, 81, 118;
187, 167, 140, 218, 178, 23, 43, 133, 154;
150, 76, 101, 8, 38, 238, 84, 47, 7;
117, 246, 163, 237, 69, 129, 60, 101, 41];
cout<<"r (python style) ="<<endl<<format(r,Formatter::FMT_PYTHON)<<";"<<endl<<endl;
效果如下
r (python style) =
[[[ 91, 2, 79], [179, 52, 205], [236, 8, 181]],
[[239, 26, 248], [207, 218, 45], [183, 158, 101]],
[[102, 18, 118], [ 68, 210, 139], [198, 207, 211]],
[[181, 162, 197], [191, 196, 40], [ 7, 243, 230]],
[[ 45, 6, 48], [173, 242, 125], [175, 90, 63]],
[[ 90, 22, 112], [221, 167, 224], [113, 208, 123]],
[[214, 35, 229], [ 6, 143, 138], [ 98, 81, 118]],
[[187, 167, 140], [218, 178, 23], [ 43, 133, 154]],
[[150, 76, 101], [ 8, 38, 238], [ 84, 47, 7]],
[[117, 246, 163], [237, 69, 129], [ 60, 101, 41]]];
cout<<"r (CSV) ="<<endl<<format(r,Formatter::FMT_CSV)<<";"<<endl<<endl;
效果如下
r (CSV) =
91, 2, 79, 179, 52, 205, 236, 8, 181
239, 26, 248, 207, 218, 45, 183, 158, 101
102, 18, 118, 68, 210, 139, 198, 207, 211
181, 162, 197, 191, 196, 40, 7, 243, 230
45, 6, 48, 173, 242, 125, 175, 90, 63
90, 22, 112, 221, 167, 224, 113, 208, 123
214, 35, 229, 6, 143, 138, 98, 81, 118
187, 167, 140, 218, 178, 23, 43, 133, 154
150, 76, 101, 8, 38, 238, 84, 47, 7
117, 246, 163, 237, 69, 129, 60, 101, 41
;
cout<<"r (Numpy) ="<<endl<<format(r,Formatter::FMT_NUMPY)<<";"<<endl<<endl;
效果如下
r (Numpy) =
array([[[ 91, 2, 79], [179, 52, 205], [236, 8, 181]],
[[239, 26, 248], [207, 218, 45], [183, 158, 101]],
[[102, 18, 118], [ 68, 210, 139], [198, 207, 211]],
[[181, 162, 197], [191, 196, 40], [ 7, 243, 230]],
[[ 45, 6, 48], [173, 242, 125], [175, 90, 63]],
[[ 90, 22, 112], [221, 167, 224], [113, 208, 123]],
[[214, 35, 229], [ 6, 143, 138], [ 98, 81, 118]],
[[187, 167, 140], [218, 178, 23], [ 43, 133, 154]],
[[150, 76, 101], [ 8, 38, 238], [ 84, 47, 7]],
[[117, 246, 163], [237, 69, 129], [ 60, 101, 41]]], dtype=‘uint8’);
cout<<"r (C) ="<<endl<<format(r,Formatter::FMT_C)<<";"<<endl<<endl;
效果如下
r © =
{ 91, 2, 79, 179, 52, 205, 236, 8, 181,
239, 26, 248, 207, 218, 45, 183, 158, 101,
102, 18, 118, 68, 210, 139, 198, 207, 211,
181, 162, 197, 191, 196, 40, 7, 243, 230,
45, 6, 48, 173, 242, 125, 175, 90, 63,
90, 22, 112, 221, 167, 224, 113, 208, 123,
214, 35, 229, 6, 143, 138, 98, 81, 118,
187, 167, 140, 218, 178, 23, 43, 133, 154,
150, 76, 101, 8, 38, 238, 84, 47, 7,
117, 246, 163, 237, 69, 129, 60, 101, 41};
Point2f p(6,2);
cout << "[Two-dimensional point] p = "<<p<<";\n"<<endl;
效果如下:
[Two-dimensional point] p = [6, 2];
Point3f p(6,2,8);
cout << "[Three-dimensional point] p = "<<p<<";\n"<<endl;
效果如下:
[Three-dimensional point] p = [6, 2, 8];
vector<float> v;
v.push_back(3);
v.push_back(5);
v.push_back(7);
cout << "[Mat-based std::vector] shortvec = "<<endl<<Mat(v)<<";\n"<<endl;
效果如下:
[Mat-based std::vector] shortvec =
[3;
5;
7];
vector<Point2f> points(20);
for(size_t i = 0; i < points.size(); ++i)
{
points[i] = Point2f((float)(i*5),(float)(i%7));
}
cout << "[Two-dimensional point vector]"<<points<<";";
效果如下:
[Two-dimensional point vector][0, 0;
5, 1;
10, 2;
15, 3;
20, 4;
25, 5;
30, 6;
35, 0;
40, 1;
45, 2;
50, 3;
55, 4;
60, 5;
65, 6;
70, 0;
75, 1;
80, 2;
85, 3;
90, 4;
95, 5];
#include
//---------------------------------【头文件、命名空间包含部分】---------------------------
// 描述:包含程序所使用的头文件和命名空间
//-----------------------------------------------------------------------------------------------
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include
using namespace std;
using namespace cv;
//-----------------------------【ShowHelpText( )函数】--------------------------------------
// 描述:输出帮助信息
//-------------------------------------------------------------------------------------------------
static void ShowHelpText()
{
//输出欢迎信息和OpenCV版本
printf("\n\n\t\t\t非常感谢购买《OpenCV3编程入门》一书!\n");
printf("\n\n\t\t\t此为本书OpenCV3版的第19个配套示例程序\n");
printf("\n\n\t\t\t 当前使用的OpenCV版本为:" CV_VERSION );
printf("\n\n ----------------------------------------------------------------------------\n");
//输出一些帮助信息
printf("\n\n\n\t欢迎来到【基本图像容器-Mat类】示例程序~\n\n");
printf("\n\n\t程序说明:\n\n\t此示例程序用于演示Mat类的格式化输出功能,输出风格可为:");
printf("\n\n\n\t【1】OpenCV默认风格");
printf("\n\n\t【2】Python风格");
printf("\n\n\t【3】逗号分隔风格");
printf("\n\n\t【4】Numpy风格");
printf("\n\n\t【5】C语言风格\n\n");
printf("\n --------------------------------------------------------------------------\n");
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//改变控制台的前景色和背景色
system("color 8F");
//显示帮助文字
ShowHelpText();
Mat I = Mat::eye(4, 4, CV_64F);
I.at<double>(1,1) = CV_PI;
cout << "\nI = " << I << ";\n" << endl;
Mat r = Mat(10, 3, CV_8UC3);
randu(r, Scalar::all(0), Scalar::all(255));
//此段代码的OpenCV2版为:
//cout << "r (OpenCV默认风格) = " << r << ";" << endl << endl;
//cout << "r (Python风格) = " << format(r,"python") << ";" << endl << endl;
//cout << "r (Numpy风格) = " << format(r,"numpy") << ";" << endl << endl;
//cout << "r (逗号分隔风格) = " << format(r,"csv") << ";" << endl<< endl;
//cout << "r (C语言风格) = " << format(r,"C") << ";" << endl << endl;
//此段代码的OpenCV3版为:
cout << "r (OpenCV默认风格) = " << r << ";" << endl << endl;
cout << "r (Python风格) = " << format(r, Formatter::FMT_PYTHON) << ";" << endl << endl;
cout << "r (Numpy风格) = " << format(r, Formatter::FMT_NUMPY )<< ";" << endl << endl;
cout << "r (逗号分隔风格) = " << format(r, Formatter::FMT_CSV )<< ";" << endl<< endl;
cout << "r (C语言风格) = " << format(r, Formatter::FMT_C ) << ";" << endl << endl;
Point2f p(6, 2);
cout << "【2维点】p = " << p << ";\n" << endl;
Point3f p3f(8, 2, 0);
cout << "【3维点】p3f = " << p3f << ";\n" << endl;
vector<float> v;
v.push_back(3);
v.push_back(5);
v.push_back(7);
cout << "【基于Mat的vector】shortvec = " << Mat(v) << ";\n"<<endl;
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<<";";
getchar();//按任意键退出
return a.exec();
}
Point类数据结构表示了二维坐标系下的点,即由其图标x和y指定的2D点
用法如下
Point point;
point.x = 10;
point.y = 8;
//或者也可以这样使用
Point point2 = Point(10,8);
此外,在OpenCV中有如下定义
typedef Point_<int> Point2i;
typedef Point2i Point;
typedef Point_<float> Point2f
因此,point_、Point2i、Point互相等价,Point_、Point2f互相等价
Scalar()类表示具有四个元素的数组,它在OpenCV中被大量用于传递像素值,如RGB颜色值
RGB颜色值为三个参数,其实对于Scalar函数来说,如果用不到第四个参数,则不需要写出来
若只写三个参数,OpenCV会认为我们就想要表示三个参数
比如下面的例子
Scalar(a,b,c);
如此定义的话,那么定义的RGB颜色值:红色分量为c,绿色分量为b,蓝色分量为a
Scalar类的源头为Scalar_
类,而Scalar_
类是Vec4x的一个变种
我们常用的Scalar其实就是Scalar_
这就是为什么很多参数输入又可以是Mat,又可以是Scalar的原因
Size的源代码如下
typedef Size_<int> Size2i;
typedef Size2i Size;
其中Size_
是个模板类,在这里Size_表示其类体内部的模板所代表的类型为int
这里两句代码的意思,就是首先给已知的数据类型Size_
起个新名字----Size2i
接着又给已知的数据类型Size2i起个新名字----Size
综上,Size_、Size2i、Size这三个类型名等价
继续回溯,找到Size_
模板类的定义
template<typename _Tp> class Size_
{
public:
typedef _Tp value_type;
//! default constructor
//默认构造函数
Size_();
Size_(_Tp _width, _Tp _height);
Size_(const Size_& sz);
Size_(const Point_<_Tp>& pt);
Size_& operator = (const Size_& sz);
//! the area (width*height)
//区域(长*高)
_Tp area() const;
//! true if empty
bool empty() const;
//! conversion of another data type.
//转化为另外一种数据模型
template<typename _Tp2> operator Size_<_Tp2>() const;
_Tp width; //!< the width//宽度
_Tp height; //!< the height//高度
};
可以看到Size_
模板内部重载了一些构造函数,其中用的频率最高的是
Size_(_Tp _width, _Tp _height);
参数在代码的末尾也有模板
_Tp width; //!< the width//宽度
_Tp height; //!< the height//高度
也就是说,程序员可以用XXXX.width和XXXXX.height来分别表示矩形尺寸的宽和高
Rect类的成员变量有x、y、width、height,它们分别表示左上角点的坐标和矩形的宽和高
Rect常用的成员函数有
如果想求两个矩阵的交集和并集,可以用如下格式
Rect rect = rect1 & rect2;
Rect rect = rect2 | rect2;
如果想让矩形进行平移操作和缩放操作,可以这样写
Rect rectShift = rect + point;
Rect rectScale = rect + size;
cvtColor()函数是OpenCV里的颜色空间转换函数,可以实现RGB颜色向HSV、HSI等颜色空间的转换,也可以转换为灰度图像
函数原型如下
void cvtColor( InputArray _src, OutputArray _dst, int code, int dcn )
第一个参数:InputArray _src
第二个参数:OutputArray _dst
第三个参数:int code
颜色空间转换的标识符,详情见下表(OpenCV3版)
转换类型
|
标识符列表 |
---|---|
RGB<–>BGR | COLOR_BGR2BGRA、COLOR_RGB2BGRA、COLOR_BGRA2RGBA、COLOR_BGR2BGRA、COLOR_BGRA2BGR |
RGB<–>5X5 | COLOR_BGR5652RGBA、COLOR_BGR2RGBA等 |
RGB<–>Gray | COLOR_RGB2GRAY、COLOR_GRAY2RGB、COLOR_RGBA2GRAY、COLOR_GRAY2RGBA |
RGB<–>CIEXYZ | COLOR_BGR2XYZ、COLOR_RGB2XYZ、COLOR_XYZ2BGR、COLOR_XYZ2RGB |
RGB<–>YCrCb(YUY) JPEG | COLOR_RGB2YCrCb、COLOR_BGR2YCrCb、COLOR_YCrCb2BGR、COLOR_YCrCb2RGB、COLOR_RGB2YUV(可将YCrCb用YUV) |
RGB<–>HSV | COLOR_BGR2HSV、COLOR_RGB2HSV、COLOR_HSV2BGR、COLOR_HLS2RGB |
RGB<–>HLS | COLOR_BGR2HLS、COLOR_RGB2HLS、COLOR_HLS2BGR、COLOR_HLS2RGB |
RGB<–>CIE L*a*b | COLOR_BGR2Lab、COLOR_RGB2Lab、COLOR_Lab2BGR、COLOR_Lab2RGB |
RGB<–>CIE L*u*v | COLOR_BGR2Luv、COLOR_RGB2Luv、COLOR_Luv2BGR、COLOR_Luv2RGB |
RGB<–>Bayer | COLOR_BayerBG2BGR、COLOR_BayerGB2BGR、COLOR_BayerRG2BGR、COLOR_BayerGR2BGR、COLOR_BayerBG2RGB、COLOR_BayerGB2RGB、COLOR_BayerRG2RGB、COLOR_BayerGR2RGB(在CCD和CMOS上常用的Bayer模式) |
YUV420<–>RGB | COLOR_YUV420sp2BGR、COLOR_YUV420sp2RGB |
第四个参数:int dcn
调用示例
文件:main.cpp
#include "mainwindow.h"
#include
#include
#include
#include
using namespace cv;
using namespace std;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
Mat mat = imread("D:/Study/StudyDocuments/Study-Documents-2021/Year-2021/Study_Note/Study_Source/OpenCVsource/Final.jpg");
imshow("original image",mat);
Mat dstimage;
cvtColor(mat,dstimage,COLOR_BGR2GRAY);//转换为灰度图
Mat toimg;
cvtColor(dstimage,toimg,COLOR_GRAY2BGR);//转换为BGR彩图(其实转换出来还是灰图,只是它的编码方式改变了而已)
imshow("Effect picture",dstimage);
imshow("Effect picture2",toimg);
return a.exec();
}
运行效果如下:
Matx
Vec
Matx的一个派生类
是一个一维的Matx,跟vector很相似
OpenCV中的定义如下
template<typename _Tp, int cn> class Vec : public Matx<_Tp, cn, 1>{...}
typedef Vec<uchar, 2> Vec2b;
Range
OpenCV中防止内存溢出的函数有alignPtr,alignSize,allocate,deallocate,fastMalloc,fastFree等
显示文字相关的函数有:
作图相关的函数有:
填充相关的函数有
OpenCV中的RNG()函数的作用为初始化随机数状态的生成器
void DrawEllipse(Mat img,double angle)
{
int thickness = 2;//线宽(实心)
int lineType = 8;//线型(8为联通线型)
ellipse(img,//画布
Point(WINDOW_WIDTH/2,WINDOW_WIDTH/2),//椭圆中心点
Size(WINDOW_WIDTH/4,WINDOW_WIDTH/16),//椭圆大小(位于Size参数包含的那么大矩形中)
angle,//旋转角度
0,//扩展弧度,从0度开始
360,//到360度结束
Scalar(255,129,0),//蓝色
thickness,//线宽
lineType);//线型(8为联通线型)
}
该函数调用了OpenCV中的ellipse函数,从而将椭圆画到img画布上
线型的含义详见第八章8.1.2节的表8.3
void DrawFilledcircle(Mat img,Point center)
{
int thickness = -1;//线宽(实心)
int lineType = 8;//线型(8为联通线型)
circle(img,//画布
center,//圆心
WINDOW_WIDTH/32,//半径
Scalar(0,0,255),//红色
thickness,//线宽
lineType);//线型(8为联通线型)
}
函数DrawFilledCircle()调用了OpenCV中的circle函数,从而将圆画到img画布上
void DrawPolygon(Mat img)
{
int lineType = 8;//线型(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),//Scalar
lineType);//线型
}
函数DrawPolygon()调用了OpenCV中的fillPoly函数,从而将凹多边形画到img画布上
void DrawLine(Mat img,Point start,Point end)
{
int thickness = 2;//线宽
int lineType = 8;//线型
line( img,//画布
start,//开始处
end,//结束处
Scalar(0,0,0),//黑线
thickness,//线宽
lineType);//线型
}
//-----------------------------【预编译相关】----------------------------
#include
#include
#include
#include
using namespace cv;
#define WINDOW_WIDTH 600
#define WINDOW_NAME1 "Picture 01"
#define WINDOW_NAME2 "Picture 02"
//-----------------------------【调用函数声明】----------------------------
void DrawEllipse(Mat img,double angle);//画椭圆
void DrawFilledcircle(Mat img,Point center);//画实心圆
void DrawPolygon(Mat img);//画凹多边形
void DrawLine(Mat img,Point start,Point end);//划线
//------------------------------【main函数】------------------------------
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//创建空白的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>绘制组合图-------------------------------
//【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));
//-----------------------<3>显示绘制的图像-------------------------------
imshow(WINDOW_NAME1,atomImage);
moveWindow(WINDOW_NAME1,0,200);
imshow(WINDOW_NAME2,rookImage);
moveWindow(WINDOW_NAME2,WINDOW_WIDTH,200);
waitKey(0);
return a.exec();
}
//-----------------------------【预编译相关】----------------------------
#include
#include
#include
#include
using namespace cv;
#define WINDOW_WIDTH 600
#define WINDOW_NAME1 "Picture 01"
#define WINDOW_NAME2 "Picture 02"
//-----------------------------【调用函数声明】----------------------------
void DrawEllipse(Mat img,double angle);//画椭圆
void DrawFilledcircle(Mat img,Point center);//画实心圆
void DrawPolygon(Mat img);//画凹多边形
void DrawLine(Mat img,Point start,Point end);//划线
//------------------------------【main函数】------------------------------
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//创建空白的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>绘制组合图-------------------------------
//【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));
//-----------------------<3>显示绘制的图像-------------------------------
imshow(WINDOW_NAME1,atomImage);
moveWindow(WINDOW_NAME1,0,200);
imshow(WINDOW_NAME2,rookImage);
moveWindow(WINDOW_NAME2,WINDOW_WIDTH,200);
waitKey(0);
return a.exec();
}
//-----------------------------【DrawEllipse()函数】---------------------------------
// 描述:自定义的绘制函数,实现了绘制不同角度,相同尺寸的椭圆
//----------------------------------------------------------------------------------
void DrawEllipse(Mat img,double angle)
{
int thickness = 2;//线宽
int lineType = 8;//线型(8为联通线型)
ellipse(img,//画布
Point(WINDOW_WIDTH/2,WINDOW_WIDTH/2),//椭圆中心点
Size(WINDOW_WIDTH/4,WINDOW_WIDTH/16),//椭圆大小(位于Size参数包含的那么大矩形中)
angle,//旋转角度
0,//扩展弧度,从0度开始
360,//到360度结束
Scalar(255,129,0),//蓝色
thickness,//线宽
lineType);//线型(8为联通线型)
}
//-----------------------------【DrawFilledcircle()函数】---------------------------------
// 描述:自定义的绘制函数,实现了绘制实心圆
//----------------------------------------------------------------------------------
void DrawFilledcircle(Mat img,Point center)
{
int thickness = -1;//线宽(实心)
int lineType = 8;//线型(8为联通线型)
circle(img,//画布
center,//圆心
WINDOW_WIDTH/32,//半径
Scalar(0,0,255),//红色
thickness,//线宽
lineType);//线型(8为联通线型)
}
//-----------------------------【DrawPolygon()函数】---------------------------------
// 描述:自定义的绘制函数,实现了画凹多边形
//----------------------------------------------------------------------------------
void DrawPolygon(Mat img)
{
int lineType = 8;//线型(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),//Scalar
lineType);//线型
}
//-----------------------------【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);//线型
}
实现效果如下
本章核心函数/类清单
函数/类名称 | 说明 | 对应讲解章节 |
---|---|---|
Mat::mat() | Mat类的构造函数 | 4.1.4 |
Mat::Creat() | Mat类的成员函数,可用于Mat类的初始化操作 | 4.1.1 |
Point类 | 用于表示点的数据结构 | 4.2.1 |
Scalar类 | 用于表示颜色的数据结构 | 4.2.2 |
Size类 | 用于表示尺寸的数据结构 | 4.2.3 |
Rect类 | 用于表示矩形的数据结构 | 4.2.4 |
cvtColor | 用于颜色空间转换 | 4.2.5 |