opencv学习笔记(一)——图像加载、显示、输出

来源:互联网 发布:淘宝卖家被处罚要几天 编辑:程序博客网 时间:2024/05/16 17:45

想到opencv总有一些激动,觉得他的功能太强大了。学习opencv也有一段日子,但是回过头来想想总感觉有点不踏实,因为我总是在调用他的接口,好多东西没有深入去理解、去弄透。作为一个专业人士,这是不能容忍的,所以回过头来将自己学过的东西记录下来,从头整理一遍,也许只有写出来才是自己真正学到的,希望自己所写的东西能一步一步伴着自己一起成长。

我所写的opencv都是从opencv2.0版本开始的,对以前的1.0版本不是特别了解,往后我所写的东西基本上都是基于自己目前的电脑安装的环境(opencv2.4.9+vs2010)进行的,如后面有改变会另行提醒。我的学习习惯就是带着问题去学习,这样能给自己加深印象。下面我就给出图片加载显示的代码,大家可以在自己的平台上运行,从结果分析代码,一旦我们看到opencv的强大,就有了学习的冲动。好了,现在就让我们目睹一下opencv代码的芳容吧。

#include<iostream>  #include <opencv2/core/core.hpp>  #include <opencv2/highgui/highgui.hpp>  using namespace std;using namespace cv;  int main()  {      // 读入一张图片(游戏原画)      Mat img=imread("tank_1.jpg");    // 创建一个名为 "坦克世界"窗口      namedWindow("坦克世界");     // 在窗口中显示游戏原画    //imshow("游戏原画",img);    imshow("坦克世界",img);     //输出一张图片到工程目录下    imwrite("我喜欢坦克世界.jpg",img);    // 等待一个按键,窗口自动关闭      waitKey();     return 0;}  

运行后的结果如下图:

这里写图片描述

并且在自己的工程目录下生成一张名字为“我喜欢坦克世界.jpg”的图片。整个工程的运行结果就是如此,很简单吧。有没有惊奇的感觉?那我们就来分析这段代码吧。

NO.1、我是焦点一 || opencv头文件和命名空间

#include <opencv2/core/core.hpp>  #include <opencv2/highgui/highgui.hpp>  using namespace std;using namespace cv; 

我们在自己opencv的安装目录下,如我的安装目录下D:\win7 position\opencv\build\include下面,你会看到下面有opencv、opencv2两个文件。很明显include里面包含的是opencv是旧版本的头文件,opencv2则是当前版本的头文件。我们进入到opencv2文件夹下,可以看到已经分类好的各种头文件,下面我们就来讲讲在上述头文件下所出现的两个文件core和highgui。
【core】模块:
在这儿你将学习OpenCV中的基本数据结构。这一部分建议必读,这样你可以知道如何去读写图像的像素,以及相关的操作。比如说:Mat——基本图像容器,opencv如何扫描图像的以及对图像矩阵的操作等等。

【highgui】模块:
本节包含的有价值的教程,如何读取/保存您的图像/视频文件和如何使用内置的图形用户界面库。

【命名空间】:
opencv1.0里没有cv命名空间,这是2.x版本后C++接口里才有的东西。所有OpenCV用到的东西都被放入名字空间 cv 中以避免与其他库的数据结构和函数名称的命名冲突。因此,在使用OpenCV库中的任何定义和函数时,你必须在名称之前冠以 cv:: ,或者在包含头文件后,加上以下指令:

using namespace cv;// 新的C++接口API都在此名字空间中,需要导入

NO.2 我是焦点二 || 图像基本容器Mat

刚开始的时候,OpenCV基于 C 语言接口而建。为了在内存(memory)中存放图像,当时采用名为 IplImage 的C语言结构体,但这种方法必须接受C语言所有的不足,这其中最大的不足要数手动内存管理,其依据是用户要为开辟和销毁内存负责。虽然对于小型的程序来说手动管理内存不是问题,但一旦代码开始变得越来越庞大,你需要越来越多地纠缠于这个问题,而不是着力解决你的开发目标。后来C++的出现,并且带来类的概念,这给用户带来另外一个选择:自动的内存管理(不严谨地说)。这是一个好消息,如果C++完全兼容C的话,这个变化不会带来兼容性问题。为此,OpenCV在2.0版本中引入了一个新的C++接口,利用自动内存管理给出了解决问题的新方法。使用这个方法,你不需要纠结在管理内存上,而且你的代码会变得简洁(少写多得)。

首先Mat是一个类,他是用来保存图像以及其他矩阵的数据结构,Mat是由两部分组成的:矩阵头(包含矩阵尺寸,存储方法,存储地址等信息)和一个指向存储所有像素值的矩阵(根据所选存储方法的不同矩阵可以是不同的维数)的指针。
上述代码用到的Mat语句如所示:

    // 读入一张图片(游戏原画)      Mat img=imread("tank_1.jpg");

这是读入一张图片的存入Mat 对象img中,图片的读入函数见下面。

NO.3、我是焦点三 ||图像读入imread

函数imread用于读取图片文件中的数据,所谓图片文件的数据,简单地说,就是一个二维数组,这个二维数组存储着一张图片各个像素点的颜色索引值或颜色值,当然真正的图片文件还需要一些附加信息。
关于imread标准声明如下:

Mat imread(const string& filename, int flags);
其中第一个参数const string& filename表示图片的路径,可以是绝对路径,也可以是相对路径,但是必须用双引号括起来。
第二个参数int flags,标志,表示读取什么样(灰度,彩色)图像。我在代码中采用了默认参数,意味着我读入的是三通道彩色图。一般情况下当flags取值有如下规则:

  • flags >0返回一个3通道的彩色图像
  • flags =0返回灰度图像
  • flags <0返回包含Alpha通道的加载的图像

NO.4、我是焦点四 ||创建窗口 nameWindow

在vs2010中选中该函数,右键——>转到定义,可以查看函数函数原型:

void namedWindow(const string& winname,int flags=WINDOW_AUTOSIZE );

第一个参数const string& winname是定义窗体的名字。
第二个参数int flags,有如下定义:

  • WINDOW_NORMAL设置了这个值,用户便可以改变窗口的大小(没有限制)
  • WINDOW_AUTOSIZE如果设置了这个值,窗口大小会自动调整以适应所显示的图像,并且不能手动改变窗口大小
  • WINDOW_OPENGL 如果设置了这个值的话,窗口创建的时候便会支持OpenGL

正常情况下我们直接使用默认值即可。

NO.5、我是焦点五 || 图像显示imshow

查看函数原型:

void imshow(const string& winname, InputArray mat);

第一个参数const string& winname填需要显示的窗口标识名称。在这需要注意一下,当你的nameWindow函数定义的窗口名字和这里的winname不一致时候,也是可以显示的,只不过nameWindow所显示的东西是空的,其实是这样的,namedWindow函数的作用是,通过指定的名字,创建一个可以作为图像的容器窗口。如果具有相同名称的窗口已经存在,则函数不做任何事情。我们示范代码如下:

namedWindow("坦克世界"); imshow("游戏原画",img); 

显示结果是两个窗口,如下:
这里写图片描述这里写图片描述

第二个参数InputArray mat,即输入图像的矩阵。

NO.6、我是焦点六 || 图像输出imwrite

函数原型:

bool imwrite(const string& filename,InputArray img, const vector<int>& params=vector<int>() );

第一个参数const string& filename,即输出图像的名字,注意要加上后缀名,免得报错哦。
第二个参数InputArray img很容易理解,即输入图像的矩阵Mat
第三个参数const vector& params=vector()表示为特定格式保存的参数编码,默认值vector(),一般情况下不需要填写。这个函数相当于输入一张图片保存为名字不同的另一张图片而已。

本文过程很简单,弄清楚几个函数是干什么用的就OK啦。

1 0