前言
博主从接触机器视觉开始,最主要的工具就是Opencv,期间由于重装系统、换电脑等等原因…可以说是无数次配置过opencv,也看过网上无数的教程,从一开始只知道跟着博客一步一步操作来,到久而久之也有了一些“心得体会”,前些日子决定开始写博客,于是决定第一篇文章就从最基本的配置Opencv开始。其实,大多时候一些问题本身是简单的,但是由于被我们从一开始就忽略,导致后期一头雾水。因此,本文偏重一些根本性的问题理解而不是具体的操作过程,希望可以帮助大家理解配置Opencv的过程中你到底干了什么。这是我的第一篇文章…欢迎大家拍砖
主要内容
- Opencv是个啥
- 编译Opencv
- CUDA支持
- 添加Contribute模块
- 生成VS属性表
- 配置Opencv时你在干啥
一、Opencv是个啥
由于博主是非CS专业学生,刚开是接触Opencv时并没有太多的编程经验,可以说是在学习Opencv的过程中渐渐熟悉C++和编程的一些相关知识,相信这种现象在非CS专业学生中是普遍存在的,因此我认为有必要先简要说明一下一些基本概念,方便大家开展Opencv学习之路。
首先由Opencv官网的介绍:
OpenCV (Open Source Computer Vision Library: http://opencv.org) is an open-source BSD-licensed library that includes several hundreds of computer vision algorithms.
我们可以看到Opencv是一个开源的包含很多视觉算法的库。
维基百科中对库的解释:
In computer science, a library is a collection of non-volatile resources used by computer programs, often for software development. These may include configuration data, documentation, help data, message templates, pre-written code and subroutines, classes, values or type specifications.
可以看到,库是一系列预先定义好的功能,他们具有特定的功能,被编译成链接库,根据链接方式的不同又分为:
- 动态链接库
在可执行文件执行过程中需要时被链接 - 静态链接库
在编译时被链接
这样可以使程序设计者可以方便的利用这些功能而无需关注其源代码(当然Opencv的源代码还是要看一看的)。
对于链接库的创建,我们可以自行百度,Opencv的源代码也是基于这种方式,只不过是比网上的例子复杂得多,看过之后你会知道:
静态库编译好后生成一个.LIB文件,动态库编译好后生成一个.DLL文件和一个.LIB文件
关于编译链接的相关概念,就不再这里具体讨论了,放一个图就好~但我们要知道的是,可执行文件并不是点一下“绿色三角”就从源代码生成了,IDE在大大简化我们编写软件的过程的同时,掩盖了软件从源代码到生成可执行文件的过程,感兴趣的话我们可以看看IDE中的Build Log或是Output等区域,就可以看到可执行文件是通过哪些编译器命令如何从源代码生成的了。
以上所说的均是针对于C++等编译型的语言而对于Python等解释型语言,Opencv亦是如此
综上所述,Opencv即是一个包含了大量机器视觉算法的库,我们在C++或是Python程序中,通过调用这些功能,进而完成更复杂的任务。
二、编译Opencv
根据上面的讨论,我们需要先将Opencv源码编译成相应的可链接文件才能共其他程序使用。其实如果我们不需要contribute模块和CUDA支持的话,我们可以直接由此下载预编译好的对应版本的Opencv,具体的VS配置过程会在后文提及。
但如果我们需要以上两个功能时,就不得不要自己编译了,编译之前需要准备好:
- Cmake-gui
- CUDA9.2
-
Contribute 模块
开始之前,我们简要叙述一下Cmake的功能:
由上文我们知道可执行文件需要通过编译链接等过程才能变为可执行文件,在实际的项目中,由于功能的复杂性,一句一句的执行特定的编译链接命令(比如GNU)是极为繁琐的,而这些命令是编译方式决定的,因此人们编写了一些软件来让用户明确编译方式然后自动生成编译命令,比如make:
In software development, Make is a build automation tool that automatically builds executable programs and libraries from source code by reading files called Makefiles which specify how to derive the target program. Though integrated development environments and language-specific compilerfeatures can also be used to manage a build process, Make remains widely used, especially in Unix and Unix-like operating systems.
定义编译方式即是编写makefile文件:
一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令
然而,对于庞大的工程人工编写Makefile依然让人们觉得很麻烦……并且针对不同的平台需要有不同的makefile,因此又编写了一个软件Cmake,来根据一些更高层次的配置来生成对应平台下的Makefile,或是说三遍:IDE工程 IDE工程 IDE工程(诸如VS,CodeBlocks,Xcode),明确这些参数的东西叫做Cmakelist,可以在Opencv源码文件夹下看到,这其中的东西够写好几篇文章的了,就暂且不详细讨论了。
而Cmake-gui只是一个具有图形化界面的Cmake,为了使参数的配置过程更加明了。下面我们开始具体的编译过程:
Step1. 导入源代码
分别指定源代码位置和最终生成的目标文件所存放的位置
Step2. 读取配置参数
在Windows下我们一般选用vs的编译器,而在Linux下我们可能更常选用GNU
点击Configure,指定编译器,之后Cmake会根据Cmakelist自动读取Opencv中的参数列表等待你来明确,并去读取系统的信息、寻找一些Opencv的依赖项,其实就是在寻找系统中特定的环境变量 环境变量 环境变量,这些环境变量明确了这些依赖库的位置,到这里是不是有一点体会…软件就是这样一点一点被组织起来的。
Step3. 配置相关参数
我们可以通过Search按关键字搜索一些参数,并且大多数参数我们可以根据名字了解它的含义,几个比较重要的参数是:
-
WITH_CUDA
开启对GPU的支持 -
OPENCV_EXTRA_MODULES_PATH
指定之前下载好的contribute模块源文件所在的位置 -
ENABLE_CXX11
开启对C++11的支持 -
BUILD_SHARED_LIBS
这个参数对应了前文所说的,这里是让你指定将opencv编译成动态库还是静态库,这里选择动态库 -
BUILD_opencv_world
把各OpenCV模块编译成一个世界模块,这样最后生成的只有一个.lib或者.dll(后者需要打开BUILD_SHARED_LIBS开关),但在发行版本中建议按需引入相应模块以减少体积。 -
BUILD_opencv_matlab
开启对Matlab的支持
Step3. VS编译
在最近一次配置Opencv时,我遇到了CUDA无法编译的问题,通过查看cuda官方手册,目前Cuda支持的VS工具集只有15.0和15.6,但是新下载的VS2017一般都是15.7,因此会出现无法编译的情况
书归正传…然后点击生成,选择批生成,勾选INSTALL debug和release后的生成选框,开始生成,过程会非常非常非常漫长…
Step4.配置Opencv工程
打开Visual Studio 2017, 新建项目,然后打开【属性管理器】(视图→其他窗口→属性管理器),然后在【Debug|x64】右键,选择【添加新项目属性表】,将属性表命名后单击【添加】,我们就会发现【Debug|x64】下就会出现我们添加的属性项目表,这里我命名为OPENCV。至此,Opencv的全部配置工作就结束了,保存这一属性表,在新建工程的时候加入进来,就免去了每次都要配置的痛苦了,由于之前选则了buildworld,因此所有的库都被放到了一起,并且opencv的包含目录与库目录不是那么多,所以可能并不觉得很复杂,但是有的一些库并不是这样的,配置起来就很麻烦,因此像Cuda这样自己提供的属性表的库,属实非常贴心了……
总结
这篇文章中大体介绍了Opencv+cuda9.2+vs2017的配置过程,在最后配置Opencv工程的时候,我们一共配置了三处属性:
- 包含目录
- 库目录
- 附加依赖项
回顾第一幅图,包含目录告诉编译器头文件所在的位置,库目录告诉编译器链接库的位置,附加依赖项告诉编译器需要链接的库,对于Opencv工程的配置实则是对于编译器的配置,如果利用cmake make进行工程编译同样需要明确这些参数。回顾我自己的学习过程,开始时仅仅是跟着别人的博客一步一步完成一些操作,而这些操作背后的目的其实当时是不求甚解的,一些开始时欠下的债也在之后的学习过程中逐渐体现,不得不再重头恶补。因此,衷心希望刚入门的同学不要重蹈我的覆辙…………
OK,就写到这里,希望这篇文章会对你有帮助。