OpenCV入门教程Word格式文档下载.docx
《OpenCV入门教程Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《OpenCV入门教程Word格式文档下载.docx(52页珍藏版)》请在冰点文库上搜索。
OpenCV是一个功能强大的计算机视觉库,要用好它,除了要具有相关的计算机视觉理论知识外,还需要具有一定的编程能力。
本书作者通过对OpenCV中文论坛中的大量问题观察,发现有很大比例的问题是因为用户对C/C++语言不熟练,导致出错,或出错后不知如何解决。
如果对C/C++语言不熟悉,那使用OpenCV时会满头雾水瞎摸索,费心费力。
在这一章中,将介绍一些编程的基本概念,让读者对编程的流程有一个基本了解。
这样在出现错误时,可以快速确定错误的类型,并知道该如何解决。
1.1编程的流程
一个编程的基本流程包括编辑、编译和连接三大步骤。
其流程图如图所
示。
编辑编辑
a.cppb.cpp
编译编译
opencv_core.lib
a.obj
b.obj
连接
main.exe
5
图1.1编程的基本流程
1.2什么叫编辑
编辑(edit)代码即编写代码,是编程的第一步。
你可以任意一个编辑器进行代码的编写。
你可以使用Windows自带的“记事本”来编写代码,也可以使用Notepad++,或者VisualStudio提供的编辑器。
图1.2使用Windows自带的记事本编辑代码
虽然可以使用记事本软件编辑代码,但是记事本软件的功能非常有限。
缺少常用的语法高亮,自动缩进等功能。
所以可以使用其他功能更丰富的编辑器,如
Notepad++)等。
图1.3使用Notepad++软件编辑代码
1.3什么叫编译
编译(compile)是将用某种编程语言(如C++语言)写成的源代码,转换成目标文件。
目标文件包含着机器代码(可直接被计算机中央处理器执行)以及代码在运行时使用的数据。
编译器(compiler)是实现这一目的的软件。
编译器有很多,如在Windows下有微软公司的cl.exe,在Linux下有gcc和g++。
在命令行
6
下使用cl.exe对hello.cpp源代码进行编译,如图所示。
编译后,将得到目标文件hello.obj,如图所示。
图1.4在命令行下使用cl.exe对hello.cpp进行编译
图1.5编译后,将新生成hello.obj目标文件
1.4什么叫连接
连接(link)是将多个目标文件,以及库文件生成可执行的文件(或静态库、或动态库)的过程。
连接器(linker)是实现这一目的的软件。
常用的连接器有
Windows下的link.exe,Linux下的ld等。
在Windows下可以使用link.exe将前面生成的hello.obj连接为可执行文件。
在命令行下效果如所图示。
连接后,将生成可执行文件,如图所示。
图1.6在命令行下使用link.exe对hello.obj进行连接
图1.7连接后,将新生成hello.exe可执行文件
1.5什么叫运行
运行(run)较容易理解,我们在Windows资源管理器里用鼠标双击exe可执行程序,可以使程序被载入CPU运行。
我们也可以在命令行窗口中输入可执
7
行程序的文件名运行,如图所示。
图1.8在命令行窗口中运行hello.exe,可以看到程序打印到标准输出的结果。
1.6VisualC++是什么
通过前面的介绍,可以看到一个编程的流程:
编辑->
编译->
连接->
运行。
更具体来说,完成这个流程需要你:
1.打开记事本软件,编辑代码,并保存;
2.在命令行下运行编译器,对代码进行编译,生成目标文件;
3.在命令行下运行连接器,将目标文件连接起来,生成可执行程序;
4.在命令行下,或Windows资源管理器中运行程序,验证程序的正确性。
如果你的项目只有一个源代码文件,完成上面四个步骤尚可接受。
但是如果你的项目包括几十个甚至几百个源文件,如无其他软件辅助,只用上面四个非常基本的步骤进行编程开发,会让人抓狂。
集成开发环境(IntegratedDevelopmentEnvironment,简称IDE)可以帮助你对项目进行管理。
常用的IDE有微软公司的VisualStudio,里面包含VisualC++,VisualC#等,其他的还有Eclipse、NetBeans、Delphi等。
因此我们平时所说的VC
不是一种编程语言,也不是编译器,它只是一个IDE。
IDE一般包含编辑器。
IDE自带的编辑器一般都针对编程语言进行了定制,实现语法高亮、自动缩进、自动补全等方便的功能。
IDE还提供丰富的菜单和按钮工具,如图、图所示。
如果你点击IDE中的“生成(build)”按钮(图),或者点击菜单“生成(build)”中的菜单项“生成项目(buildproject)”,那么IDE会去调用编译器cl.exe和连接器link.exe来生成可执行程序。
如果你在调试状态下,还会去调用调试器(debugger)。
IDE会提升程序开发的效率,特别是调试程序的效率。
8
图1.9微软VisualStdio集成开发环境
图1.10VisualStdio中的编辑按钮
图1.11VisualStdio中的生成程序按钮
1.7头文件
在编程过程中,程序代码往往被拆成很多部分,每部分放在一个独立的源文件中,而不是将所有的代码放在一个源文件中。
考虑一个简单的小例子:
程序中有两个函数main()和foo()。
main()函数位于main.cpp,foo()函数位于foo.cpp,
main()函数中调用foo()函数。
在编译阶段,由于编译是对单个文件进行编译,所以编译main.cpp时,编译器不知道是否存在foo()函数以及foo()调用是否正确,因此需要头文件辅助。
也就是说,在编译命令:
cl.exe/cmain.cpp
运行时,编译器不知道foo的用法是否正确(因为foo在另一个文件foo.cpp中),只有借助头文件中的函数声明来判断。
对main.cpp进行编译时,不会涉及
foo.cpp文件,只会涉及main.cpp和foo.h(因为foo.h被include)文件。
头文件的作用如图所示。
9
1.foo()函数这样用对
main.cpp
#include"
foo.h"
intmain()
{
inti=foo(3,4);
returni;
}
2.函数声明是intfoo(inti,intj),你的调用看上去是对的。
foo.h
intfoo(inti,intj);
foo.cpp
intfoo(inti,intj)
……
图1.12对main.cpp进行编译时,需要利用头文件中的foo()函数声明来确认main.cpp中
对foo()的调用是正确的
1.8库文件
库文件中包含一系列的子程序。
例如在上一节的例子中,foo.cpp源文件中实现了foo()函数,我们假设foo()函数是包含重要算法的函数,我们需要将foo()函数提供给客户使用,但是不希望客户看到算法源代码。
为了达到这一目的,我们可以将foo.cpp编译程库文件(图),库文件是二进制的,在库文件中是看不到原始的源代码的。
库和可执行文件的区别是,库不是独立程序,他们是向其他程序提供服务的代码。
当然使用库文件的好处不仅仅是对源代码进行保密,使用库文件还可以减少重复编译的时间,增强程序的模块化。
将库文件连接到程序中,有两种方式,一种是静态连接库,另一种是动态连接库。
如果希望了解更多关于库文件的知识,请查阅相关资料,再次不详细分析它们之间的异同。
10
用户
开发者
编辑
编译
main.obj
foo.lib
foo.obj
图1.13库是二进制的文件,里面包含一系列子程序(图有问题)
1.9OpenCV是什么
OpenCV其实就是一堆C和C++语言的源代码文件,这些源代码文件中实现了许多常用的计算机视觉算法。
例如C接口函数cvCanny()实现了Canny边缘提取算法。
可以直接将这些源代码添加到我们自己的软件项目中,而不需要自己再去写代码实现Canny算法,也就是不需要重复“造轮子”。
由于OpenCV中源代码文件巨多,根据算法的功能,将这些源文件分到多个模块中:
core、imgproc、highgui等。
将每个模块中的源文件编译成一个库文件(如opencv_core.lib、opencv_imgproc.lib、opencv_highgui.lib等),用户在使用时,仅将所需的库文件添加到自己的项目中,与自己的源文件一起连接成可执行程序则可。
11
1.10什么是命令行参数
C/C++语言中的main函数,经常带有参数argc,argv,如下:
intmain(intargc,char**argv)
或者
intmain(intargc,char*argv[])
在上面代码中,argc表示命令行输入参数的个数(以空白符分隔),argv中存储了所有的命令行参数。
假如你的程序是hello.exe,如果在命令行运行该程序(如图。
首先应该在命令行下用cd命令进入到hello.exe文件所在目录),运行命令为:
hello.exeShiqiYu
那么,argc的值是3,argv[0]是"
hello.exe"
,argv[1]是"
Shiqi"
,argv[2]是"
Yu"
。
图1.14使用命令行参数运行程序
下面的程序演示argc和argv的使用:
#include<
stdio.h>
intmain(intargc,char**argv)
inti;
for(i=0;
i<
argc;
i++)
printf("
Argument%dis%s.\n"
i,argv[i]);
return0;
假如上述代码编译为hello.exe,那么运行
hello.exeabcde
12
将得到
Argument0ishello.exe.
Argument1isa.
Argument2isb.
Argument3isc.
Argument4isd.
Argument5ise.
运行
hello.exelena.jpg
Argument1islena.jpg.
1.11常见编译错误
在编程中,经常会出现各种错误。
出现错误后,不要闭眼抱头作痛苦状。
出现错误后,需要做的第一件事情是阅读出错信息。
出错信息虽然看似凌乱,但是能够提供很多有价值的信息,帮你解决问题。
1.11.1找不到头文件
找不到头文件往往会提示如下错误:
hello.cpp
(2):
fatalerrorC1083:
Cannotopenincludefile:
'
opencv2/opencv.hppp'
:
Nosuchfileordirectory
找不到头文件一般有两个原因:
一个是头文件的文件名拼写错误;
或者未将头文件所在路径添加到开发环境中。
上例中的错误是文件名拼写错误,opencv2/opencv.hpp被错误地拼写为opencv2/opencv.hppp。
如果文件名拼写正确,编译器还是找不到头文件,则需要将头文件所在路径添加到相应的变量中。
如在VisualStudio2010中,需要在项目属性(ProjectProperty)对话框中设置头文件路径。
具体位置在对话框“VC++Directories”里面的“IncludeDirectories”
中,如图所示。
13
图1.15头文件所在路径设置
1.11.2拼写错误
在编程中,拼写错误也是一类常见错误。
如图所示代码中,将imread函数错误地拼成imreadd,编译器会提示错误:
hello.cpp(9):
errorC3861:
'
imreadd'
identifiernotfound
这句错误提示的意思是说无法找到imreadd标识符,因此我们需要仔细检查imreadd找不到的原因。
假如你真的有一个函数是imreadd,但是找不到,可能的原因是声明imreadd的头文件未使用include语句包含到源文件中。
14
图1.16拼写错误,将imread拼成了imreadd,会造成编译时错误。
如果源代码不符合语法规则,则会造成编译错误。
编译错误往往是由于编写代码不仔细造成,比如拼写错误、漏了半个括号、漏了分号等。
因此一旦遇到便宜错误,你需要按照错误提示,定位到出错的位置,仔细检查语法是否符合规范。
1.12常见链接错误
如果你的代码符合语法规则,则会通过编译过程。
编译完所有源代码之后,下一步是连接目标文件,以形成可执行文件。
连接过程中最常见的错误如下(图
):
1>
hello.obj:
errorLNK2019:
unresolvedexternalsymbol"
classcv:
Mat__cdeclcv:
imread(classstd:
basic_string<
char,structstd:
char_traits<
char>
classstd:
allocator<
>
const&
int)"
(?
imread@cv@@YA?
AVMat@1@ABV?
$basic_string@DU?
$char_traits@D@std@@V?
$allocator@D@2@@std@@H@Z)referencedinfunction_main
这个错误信息里最关键的词是“unresolvedexternalsymbol”,更具体的意思是在main函数中使用了imread函数,但是无法从外部找到imread。
imread函数是OpenCV的函数,不是用户自己实现的函数。
opencv.hpp头文件告诉编译器有个imread函数可以用,编译通过;
但是到了连接时,连接器却找不到imread的具体实现,故出错。
15
图1.17连接错误,无法找到imread等函数的实现
要解决这一问题,需要将依赖的库文件添加到项目设置中。
具体位置在对话框“Linker-Input”里面的“AdditionalDependencies”中,如图所示。
图1.18添加依赖的库文件
16
1.13运行时错误
经过编译和连接过程,生成了可执行的文件(如exe文件)之后,在运行这个可执行文件所产生的错误是运行时错误。
比较常见的运行时错误是内存错误。
比如下面这段代码:
opencv2/opencv.hpp>
usingnamespacecv;
Hello,OpenCV!
\n"
);
Matimg=imread("
lena.jpg"
Matgray;
cv:
cvtColor(img,gray,CV_BGR2GRAY);
return0;
编译和连接过程无任何问题,但在运行时弹出如图所示对话框,并在命令行窗口输出错误信息(图)。
图1.19运行时错误对话框
图1.20运行时错误的出错信息
17
错误信息中提示color.cpp文件的第2834行有错,错误原因是条件(scn==3||scn==4)不成立。
很多OpenCV用户看到此错误信息一头雾水,不知如何下手解决。
根据程序源代码的意思,是将三通道的BGR图像img转为单通道的图像gray。
但是程序说img既不是3通道,也不是4通道。
而根据imread函数的文档,imread将图像作为彩色图像读入,条件(scn==3||scn==4)肯定成立。
这个程序的问题出现在当前目录下无lena.jpg文件,这样程序无法读到图像,造成cvtColor函数出错。
因此对于读入图像时,需要检查图像读入是否成功,以免造成运行时错误。
在程序编写中,对于数组和指针等,要特别地小心。
因为对于空指针以及数组越界等问题,编译器无法在编译时给出错误提示。
这类错误一旦在运行时发生,排除起来非常困难。
18
第2章OpenCV介绍
OpenCV的全称是OpenSourceComputerVisionLibrary,是一个开放源代码的计算机视觉库。
OpenCV是最初由英特尔公司发起并开发,以BSD许可证授权发行,可以在商业和研究领域中免费使用,现在美国WillowGarage为OpenCV提供主要的支持。
OpenCV可用于开发实时的图像处理、计算机视觉以及模式识别程序,目前在工业界以及科研领域广泛采用。
2.1OpenCV的来源
OpenCV诞生于Intel。
Intel最初希望提供一个计算机视觉库,使之能充分发
掘CPU的计算能力,当然更希望以此促进Intel的产品的销售。
OpenCV最初的开发工作是由Intel在俄罗斯的团队实现。
这里面有两个关键人物,一个是Intel性
能团队(Intel’sPerformanceLibraryTeam)的李信弘(ShinnLee)先生,他是团队的经理,负责IPP等库,给予OpenCV很大的支持。
另一个关键人物是VadimPisarevsky,Vadim在Intel负责OpenCV的项目管理、代码集成、代码优化等工作。
在后期Intel支持渐少的时候,是VadimPisarevsky一直在维护着OpenCV。
2007年6月,受本书作者之邀,李信弘和VadimPisarevsky作为嘉宾参加了在北
京举行的“开放源代码计算机视觉库(OpenCV)研讨会”1,并做了非常有价值的报告。
在2008年,一家美国公司,WillowGarage2,开始大力支持OpenCV,VadimPisarevsky和GaryBradski都加入了WillowGarage。
GaryBradski也是OpenCV开
发者中的元老级人物,他曾出版《LeaningOpenCV》一书,广受欢迎。
WillowGarage是一家机器人公司,致力于为个人机器人开发开放的硬件平台和软件。
现在已经开发了PR2机器人,并支持ROS、OpenCV、PCL等软件。
ROS(RobotOperatingSystem)是用于机器人的操作系统,是一个开放源代码的软件,OpenCV作为ROS的视觉模块嵌入。
自从获得WillowGarage支持后,OpenCV的更新速度明显加快。
大量的新特性被被加入OpenCV中,很多算法都是最近一两年的新的科研成果。
OpenCV正日益成为算法研究和产品开发不可缺少的工具。
2.2OpenCV的协议
OpenCV采用BSD协议,这是一个非常宽松的协议。
简而言之,用户可以修
1研讨会网址:
2WillowGarage公司网站:
19
改OpenCV的源代码,可以将OpenCV嵌入到自己的软件中,可以将包含OpenCV的软件销售,可以用于商业产品,也可以用于科研领域。
BSD协议并不具有“传染性”,如果你的软件中使用了OpenCV,你不需要公开代码。
你可以对OpenCV做任何操作,协议对用户的唯一约束是要在软件的文档或者说明中注明使用了
OpenCV,并附上OpenCV的协议。
在这个宽松协议下,企业可以在OpenCV基础之上进行产品开发,而不需要担心版权问题(当然你要注明使用了OpenCV,并附上OpenCV的协议)。
科研领域的研究者,可以使用OpenC