opencv入门教程-----图像的输入,显示和输出

时间:2021-03-23 19:58:12

本文根据浅墨大神文章学习加之实践后进行记录,代码经过本人运用并加之以注释和修改。博主准备以这种方式进行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的部分常用函数。
ones

C++: 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_8UC1CV_16SC1CV_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环境下可防止程序运行后一闪就退出