本文根据浅墨大神文章学习加之实践后进行记录,代码经过本人运用并加之以注释和修改。博主准备以这种方式进行opencv的学习,顺便在学习大神之后记录自我的所学及收获,所以以后的文章大多会以这种形式记录。如果希望亲眼目睹大神的神韵,下面配上传送门----超时空传送门。
本篇对应着大神的篇目:【OpenCV入门教程之三】 图像的载入,显示和输出 一站式完全解析
本章较为简单,理清楚opencv中的Mat类型以及如何在opencv中进行图像的载入,显示和输出便可。
一、 Mat类型
cv::Mat类是用于保存图像以及其他矩阵数据的数据结构,默认情况下,其尺寸为0,我们也可以指定初始尺寸,比如,比如定义一个Mat类对象,就要写 cv::Mat pic(320,640,cv::Scalar(100)); 其次定义Mat类型的对象还有其他重载的构造函数,这里提几个比较常用的。
Mat::Mat(int rows, int cols, int type)创建行数为rows,列数为col,类型为type的图像; Mat::Mat(Size size, int type)创建大小为 size,类型为type的图像; Mat::Mat(const Mat& m)
将一个同类型Mat的对象去初始化对象,相当于复制了一个图像。
但需要注意的是,此时系统不会创建图像所需的空间,而是将新对象的地址指向m,新对象与m共用数据空间,这意为着对新对象的任何操作其实也是对m进行操作。同理在opencv中,如果你定义了两个Mat对象A,B.将B赋值给A即A=B;此时AB也共用内存空间,那么如何才能对一幅已用的图像Mat进行复制呢? Mat类中有这样两个函数:
Mat::zeros返回指定的大小和类型的零数组。Mat::ones返回一个指定的大小和类型的全为1的数组。
其实前面我们已经说了,Mat类型的对象其实是一个矩阵数据,它包含着一张图片的信息。一张图片在计算机看来,就是一堆亮度或是颜色各异的点。一副尺寸为M x N的图片可以用一个M x N的矩阵来表示,矩阵元素的值表示这个位置上的像素亮度、颜色。回到正题,计算机记录的图片信息其实就是像素点的值,Mat矩阵内的数据就是图片像素点的值。 zeros函数就是定义一张照片的表示数组,其上每个像素值都为零,也就是相当于定义一幅黑色的图片。之对应的还有一个ones函数,所有值都为1,理解为初始化了一个矩阵。
下面贴上zeros与ones的部分常用函数。
onesC++: static MatExpr Mat::ones(int rows, int cols, int type)
C++: static MatExpr Mat::ones(Size size, int type)
zeros
C++: static MatExpr Mat::zeros(int rows, int cols, int type)
C++: static MatExpr Mat::zeros(Size size, int type)
参数:
rows –行数。.
cols –列数。
size –替代矩阵大小规格Size(cols, rows)的方法。
sizes –指定数组的形状的整数数组。
type –创建的矩阵的类型。
好吧,最后说一个东西,type–创建的矩阵的类型,这个type在Mat的构造函数中作为参数出现过,在zeros和ones也出现过,这里详细说下。opencv中很多都涉及到类型type。type可以是CV_8UC1,CV_16SC1,…,CV_64FC4等。里面的8U表示8位无符号整数,16S表示16位有符号整数,64F表示64位浮点数(即double类型);C后面的数表示通道数,例如C1表示一个通道的图像,C4表示4个通道的图像,以此类推。
二、 图像的基本操作
1. 图像的打开 ----imread( )函数Mat::imread(const string& filename, intflags=1 );一般要打开一张图片可以通过以下函数进行操作:imread("图片文件名.后缀格式") 例如打开项目文件下的一张名为first jpg格式的图片即imread("first.jpg") 该函数的参数详细解释浅墨中已有述说,这里不进行赘述。
2.创建窗口----namedWindow()函数
void namedWindow(const string& winname,int flags=WINDOW_AUTOSIZE );一般使用为namedWindows(“你想要的名字”),例如要创建一个名字为“hello”的窗口:namedWindows(“hello”) 一般创建了一个窗口后会与显示图片函数Imshow连用,即将指定的图片在该窗口中显示。 该函数的参数详细解释浅墨中已有述说,这里不进行赘述。
3.图片的显示---imshow()函数
void imshow(const string& winname, InputArray mat);一般使用为imshow("图片所显示的窗口名称",要显示的图片的Mat类型),例如要在hello窗口显示frist图片。 Mat photo= imread("first.jpg"); namedWindow("hello"); imshow("hello",photo);
4.图片的保存---imwrite
<span style="white-space:pre"></span>bool imwrite(const string& filename,InputArray img, const vector<int>& params=vector<int> () );
该函数可以保存修改后的图片至项目文件夹中。 函数的一般应用:保存已经修改后的某张图片.imwrite("保存的名称.保存格式",保存的图片的Mat类型)
三、实例练习
最后是一个综合示例,载入图像,进行简单图像混合,显示图像,并且输出混合后的图像到jpg。
由于篇幅原因,这里的图像混合具体细节我们放到稍后的文章中再讲,现在先给大家看看混合的效果和源码。
注:实例来自浅墨大神,代码注释参考了另一位学习者超时空传送门;
Mat image= imread("dota.jpg");//载入图片,"dota.jpg"为工程目录下的文件图片
Mat logo= imread("dota_logo.jpg");
Mat imageROI;// 定义一个Mat类型,用于存放,图像的ROI,即图像的感兴趣区域
imageROI= image(Rect(800,350,logo.cols,logo.rows));//指定图像的感兴趣区域,imageROI的数据与源图像image共享存储区,所以此后在imageROI上的操作也会作用在源图像image上
//imageROI= image(Range(350,350+logo.rows),Range(800,800+logo.cols));//亦可这么写
// 将logo加到原图上
addWeighted(imageROI,0.8,logo,0.2,0,imageROI);//数组相加函数,imageROI为原数组,0.8为该数组权值,logo为另一个原数组,0.2为该数组权重,0为添加常数项,imageROI为输出目标数组,函数输出结果为:imageROI=imageROI*0.8+logo*0.2+0
namedWindow("原画+logo图");//显示结果
imshow("原画+logo图",image);
imwrite("我喜欢打dota2 by浅墨.jpg",image);//输出一张jpg图片到工程目录下
waitKey();//等待用户输入任意键,在win32环境下可防止程序运行后一闪就退出