1.1.1 数字图像存储
显示场景中看到的物体是包含一个众多强度值的像素的矩阵,矩阵就是图像在数码设备中的表现形式。
1.1.2 Mat 结构的使用
Mat类:
(1)不必手动为其开辟空间;
(2)不需要时无需手动释放空间;
手动开辟空间并非必须,但它存在,多数OpenCV函数会手动的为输出数据开辟空间。当传递一个已经存在的Mat对象时,开辟好的空间会被重用。也就是我们使用大小正好的内存来完成任务。
Mat 是一个类,它由两部分组成:矩阵头(包含矩阵尺寸,存储方式,存储地址信息)和一个指向存储所有像素值的矩阵(根据所选存储方式的不同,矩阵可以是不同的维度)的指针。矩阵头的尺寸是常数值,但矩阵本身的尺寸会依图像的不同而不同,通常比矩阵头的尺寸大。
在做计算量很大的图像处理算法时,不该进行图像的复制,这会降低程序的运行速度。为了解决此类问题,OpenCV使用了引用记数机制,就是让每个Mat有自己的矩阵头,但共享同一矩阵。这通过让矩阵指针指向同一地址实现。拷贝构造函数则只是复制信息头和矩阵指针,而不复制矩阵。
Mat A,C; //仅创建矩阵头
A = imread("1.jpg", CV_LOAD_IMAGE_COLOR); //为矩阵开辟内存空间
Mat B(A); //拷贝构造
C = A; //幅值
上述例子,所有的Mat类对象(矩阵头不同)最终都指向同一个矩阵。
我们可以创建只引用部分数据的信息头,感兴趣区域(ROI),只需要创建包含边界的信息头:
Mat D(A, Rect(0, 0, 100, 100)); //使用矩阵定界
Mat E = A(Range:all(), Range(1,3)); //用行和列来定界
如果矩阵属于多个Mat对象,不需要时,谁来清除?
最后一个使用它的对象进行释放 通过引用记数机制来实现,复制一个Mat对象,对一次矩阵的引用。
如果想复制矩阵本身,可以使用clone(), copyTo()
函数
Mat T = A.clone();
Mat G;
A.copyTo(G);
上述改变T,G不会影响Mat信息头所指向的矩阵(A矩阵指针指向的矩阵).
总上所述:
1.1.3 像素值存储的方式
存储像素值需要指定颜色空间和数据类型。
颜色空间:是指针对一个给定的颜色,如何组合颜色元素以对其编码。最简单的颜色空间是灰度级空间,只处理黑色和白色,对他们组合就可产生不同程度的灰色。
颜色系统:
RGB
,被显示设备采用,红绿蓝为基色,有时为了表示透明也会加入alpha(A);HSV和HLS
把颜色分解为色调,饱和度,明亮。这个是描述颜色最自然的方式。YCrCb
在JPEG图像格式中使用CIE L*a*b
是一种在感知上均匀的颜色空间,它适合度量两个颜色之间的距离;1.1.4 创建Mat对象的方法
Mat不仅是一个图像容器类,同时也是一个通用的矩阵类。
创建一个Mat对象的多种方式:
使用Mat()构造函数
Mat M(2,2, CV_8UC3, Scalar(0,0,255));
cout << "M = " << endl << " " << M << endl << endl;
CV_8UC3:CV_[位数][带符号与否][类型前缀]C[通道数]
Scalar(0,0,255)
:能使用指定的定制化值来初始化矩阵,它还可以用于表示颜色。
利用create()函数
Mat M;
M.create(4,4,CV_8UC2);
cout << "M = " << endl << " " << M << endl << endl;
对小矩阵使用逗号分割式初始化函数
Mat M = (Mat_<double>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
1.2.1 点的表示:Point类
Point类数据表示了二维坐标系下的点,即由其图像坐标x和y指定的2D点。
Point point = Point(10,4);
OpenCV中有如下定义:
typedef Point_ Point2f;
typedef Point2i Point;
typedef Point_ point2f;
所以,Point_, Point2i, Point相互等价,Point_, Point2f相互等价。
1.2.2 颜色的表示:Scalar类
Scalar()表示具有4个元素的数组,在OpenCV中被用来大量传递像素值,如RGB颜色值。
例如:Scalar(a, b, c)
定义的RGB颜色值:红色分量为c, 绿色分量为b,蓝色分量为a;
Scalar类的源头时Scalar_类,而Scalar_类是Vec4x的一个变种,我们常用的Scalar就是Scalar_。这也解释了为什么很多函数的输入可以是Mat,也可以是Scalar;
1.2.3 矩形的表示:Rect类
Rect的类成员有x,y,width,height
,分别是左上角点的坐标和矩形的宽度和高度。常用的成员函数有:Size()返回值为Size;area()返回矩形的面积;contains(Point)判断点是否在矩形内;inside(Rect)函数判断矩形是否在该矩形内;tl()返回左上角点的坐标; br()返回右下角点的坐标。如果想要求两矩形的交集和并集,可以用如下格式:
Rect rect = rect1 & rect2;
Rect rect = rect | rect2;
如果想让矩形进行平移和缩放操作,可以:
Rect rectShift = rect + point;
Rect rectScale = rect + size;
1.2.4 颜色空间的转换:cvtColor()函数
cvtColor()是OpenCV里的函数颜色空间转换函数,可以实现RGB颜色向HSV,HSI等颜色空间的转换,也可以转换为灰度图像。
函数原型:
void cvColor(InputArray src, OutputArray dst, int code, int dstCn=0)
;
//OpenCV2版本:
cvtColor(srcImage, dstImage, CV_GRAY2BGR); //原图转灰度图
//OpenCV3版本:
cvtColor(srcImage, dstImage, COLOR_GRAY2BGR);
随着OpenCV版本的升级,cvtColor()函数对于颜色空间的种类的支持也增多。
对于颜色空间转换,OpenCV2的CV_前缀的宏命名规范,被OpenCV3中COLOR_式的宏命名前缀所取代。
#define WINDOW_WIDTH 600
void DrawEllipse(Mat image, double angle)
{
int thickness = 2;
int lineType = 8;
ellipse(imaege, Point(WINDOW_WIDTH/2, WINDOW_WIDTH/2), Size(WINDOW_WHDTH/4, WINDOW_WIDTH/16),angle, 0, 360, Scalar(255, 192, 0), thickness, lineType);
}
函数解析:DrawEllipse()调用OpenCV中的ellipse函数,将椭圆回到image图像上
ellipse()
函数的解析:
1.3.2 DrawFilledCirele()函数
————————————————————————————————————————————————
描述:绘制实心圆
————————————————————————————————————————————————
void DrawFilledCircle(Mat image, Point center)
{
int thickness = -1;
int lineType = 8;
circle(image, center, WINDOW_WIDTH/32, Scalar(250, 192,0), thickness, lineType);
}
函数解析:DrawFilledCircle()函数调用OpenCV中的circle函数,将实心圆绘制到image上
。
circle()
函数解析:
1.3.3 DrawPolygon()函数
————————————————————————————————————————————————
描述:绘制凹多边行
————————————————————————————————————————————————
void DrawPolygon(Mat imaege)
{
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(image, ppt, npt, 1, Scalar(255, 255, 255), lineType);
}
函数解析:DrawPolygon()调用了OpenCV中的fillPoly函数,用于将多边形画到image图像上
。
fillPoly()
函数解析:
1.3.4 DrawLine()函数
————————————————————————————————————————————————
描述:绘制线
————————————————————————————————————————————————
void DrawLine(Mat image, Point start, Point end)
{
int thickness = 1;
int lineType = 8;
line(image, start, end, thickness, lineType);
}
函数解析:DrawLine()调用OpenCV中的line()函数,用于将线段画到image图像上
。
line()
函数解析:
1.3.5 绘制图像
#include
#include
#include
#include
using namespace std;
using namespace cv;
//定义一些宏
#define WINDOW_NAME1 "[绘制图1]"
#define WINDOW_NAME2 "[绘制图2]"
#define WINDOW_WIDTH 600 //定义窗口大小;
void DrawEllipse(Mat image, double angle);
void DrawFilledCircle(Mat image, Point center);
void DrawPolygon(Mat image);
void DrawLine(Mat image, Point start, Point end);
int main()
{
//创建空白的Mat图像
Mat atcoImage = Mat::zeros(WINDOW_WIDTH, WINDOW_WIDTH, CV_8UC3);
Mat rookImage = Mat::zeros(WINDOW_WIDTH, WINDOW_WIDTH, CV_8UC3);
//[1]绘制出椭圆
DrawEllipse(atcoImage, 90);
DrawEllipse(atcoImage, -45);
DrawEllipse(atcoImage, 0);
DrawEllipse(atcoImage, 45);
//[2]画实心圆
DrawFilledCircle(atcoImage, Point(WINDOW_WIDTH/2, WINDOW_WIDTH/2));
//[3】绘制多边形
DrawPolygon(rookImage);
//[4]绘制矩形
rectangle(rookImage, Point(0, 7 * WINDOW_WIDTH/8), Point(WINDOW_WIDTH, WINDOW_WIDTH), Scalar(0,255,255), -1, 8);
//[5]绘制一些线段
DrawLine(rookImage, Point(0, 15 * WINDOW_WIDTH/16), Point(WINDOW_WIDTH, 15*WINDOW_WIDTH/16));
imshow(WINDOW_NAME1, atcoImage);
moveWindow(WINDOW_NAME1, 0, 200); //改变指定窗口的位置
imshow(WINDOW_NAME2, rookImage);
moveWindow(WINDOW_NAME2, WINDOW_WIDTH, 200);
// waitKey(0);
while(char (waitKey(1)) != 'q') {}
return 0;
}
void DrawEllipse(Mat image, double angle)
{
int thickness = 2;
int lineType = 8;
ellipse(image, Point(WINDOW_WIDTH/2, WINDOW_WIDTH/2), Size(WINDOW_WIDTH/4, WINDOW_WIDTH/16),angle, 0, 360, Scalar(255, 192, 0), thickness, lineType);
}
void DrawFilledCircle(Mat image, Point center)
{
int thickness = -1;
int lineType = 8;
circle(image, center, WINDOW_WIDTH/32, Scalar(250, 192,0), thickness, lineType);
}
void DrawPolygon(Mat image)
{
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(image, ppt, npt, 1, Scalar(255, 255, 255), lineType);
}
void DrawLine(Mat image, Point start, Point end)
{
int thickness = 1;
int lineType = 8;
line(image, start, end, thickness, lineType);
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.6)
find_package(OpenCV 3.4 REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
add_executable(open 1.cpp)
target_link_libraries(open ${OpenCV_LIBS})