• VS配置OpenCV开发环境(c++):How & Why


    前言

    不知不觉,正儿八经地写代码已经有三年多了。OpenCV是我这三年来用的最多的库,在Visual Studio中配置它的开发环境,算是家常便饭,已经相当熟稔。回想自己初学OpenCV时的经历,在网上看教程找资料,走了不少弯路。所以我写下这篇博文,把配置过程中的东西都讲清楚,让读到的人少走些弯路。在HOW部分,我将叙述如何配置,并尽量使配置过程简单明了;在WHY部分,我会尽量讲清楚为什么这样配置

    教程开始前,我希望你能清楚集成开发环境(Integrated Development Environment, IDE)和编译器是两码事儿,Visual Studio是IDE,而VC是编译器。VC是VS的子集。在不严谨的情况下,可以把它们当作一回事儿,但一定要清楚你的VS/VC的版本。各版本的VS和VC对应关系如下表(太古老的版本就不列出来了):

    IDE 编译器
    VS2017 VC15
    VS2015 VC14
    VS2013 VC12
    VS2012 VC11
    VS2010 VC10
    VS2008 VC9
    VS2005 VC8

    另外,本文将使用VS2013OpenCV-3.0为例。其他版本的配置差别不大,可以依葫芦画瓢。


    HOW

    (0) 准备工作

    首先在VS中新建一个空的c++工程:

    在项目中新增一个.cpp文件,然后写上一段简单的测试代码(读取一副图片然后将其显示出来):

    // 一段简单的测试代码
    #include <opencv2opencv.hpp>
    int main() {
    	cv::Mat img = cv::imread("E:\cap.png"); //改成你自己的图片路径
    	cv::imshow("test", img);
    	cv::waitKey(0);
    }
    
    (1) 配置附加包含目录

    对项目【右键】-【属性】

    弹出属性页,依次点击【配置属性】-【C/C++】-【常规】-【附加包含目录】,在弹出的窗口中把OpenCV的include路径填进去。本文填写的是【E:ENVopencv-3.0include】。
    注意上方【配置】和【平台】两个复选框里面的内容。后文将详细说明。

    (2) 配置附加库目录

    同样是在项目的属性页,依次点击【配置属性】-【链接器】-【常规】-【附加库目录】,在弹出的窗口中把OpenCV的lib路径填进去。
    本文填写的路径是【E:ENVopencv-3.0uildx86vc12lib】,其中【x86vc12】代表此库由VC12编译生成,32位。如果你需要其他版本的库,也可以改成对应的路径。后文将详细说明。

    (3) 配置附加依赖项

    依然是在项目的属性页,依次点击【配置属性】-【链接器】-【输入】-【附加依赖项】,在弹出的窗口中填入【opencv_ts300.lib】和【opencv_world300.lib】。其中300代表OpenCV-3.0,是版本号。后文将详细说明。

    (4) 配置dll

    这一部有两种做法,第一种方法(推荐)是把【E:ENVopencv-3.0uildx86vc12in】目录下的dll文件【opencv_world300.dll】拷贝一份,放到本项目生成的exe文件所在目录中,见下图。如果你没有Debug这个目录,那么先把项目生成/运行一遍就有了。

    第二种方法(不推荐)是把【E:ENVopencv-3.0uildx86vc12in】加到系统的环境变量,如下图,在右侧两个【Path】中选择一个编辑加入路径就行了。

    (5) 测试

    至此已完成全部配置工作!按下F5运行一开始准备好的测试代码,看看效果吧:

    成功运行!

    (*) 注意

    某些教程会教你在【配置属性】-【VC++目录】中修改【附加包含目录】和【附加库目录】,如下图。在这里修改虽然方便,但我不推荐。


    WHY

    为了弄清楚为什么要这样配置,我们来看看OpenCV文件夹里都有什么:

    • build
    • sources
    • LICENSE.txt
    • README.md.txt

    两个txt文件,分别是许可证和说明,不重要;两个文件夹,【sources】文件夹中是OpenCV的源代码,如果仅仅是调用OpenCV库,那么我们多半用不上这个文件夹里面的东西。【build】文件夹中包括头文件,和一些现成的库文件。这些库文件是由OpenCV官方生成的。(当然你也可以利用CMake自己生成这些库文件,CMake是一款跨平台的make软件,【sources】文件夹里面提供了CMake配置文件。我劝大家不要自己用去生成库,因为实在是太折腾了。)

    再来仔细看看【build】文件夹里面的东西:

    • etc
    • include
    • java
    • python
    • x64
    • x86
    • LICENSE
    • OpenCVConfig.cmake
    • OpenCVConfig-version.cmake

    【etc】文件夹中是OpenCV某些算法所依赖的数据集;

    【include】里面是一堆头文件,在 步骤(1) 中,我们将此目录加入了【附加包含目录】,就是为了使我们测试代码中的第一行#include <opencv2opencv.hpp>生效。#include是在【包含目录】中搜索头文件的,【附加包含目录】顾名思义,也属于【包含目录】;

    【java】和【python】文件夹与本文讨论的内容无关;

    【x86】和【x64】对应32位库和64位库。OpenCV-3.1官方没有提供32位的库,自然也就没有【x86】这个文件夹了。如果你需要32位的OpenCV-3.1库,可以自己去生成,但建议你先去网上找一找,看看第三方组织或个人生成的库文件中有没有你想要的。

    最后是许可证以及两个CMake相关的文件,不重要。

    步骤(2) 中,本文将【E:ENVopencv-3.0uildx86vc12lib】加入了【附加库目录】,这样做是在是调用“32位的、由vc12编译器生成的、动态链接库形式的、OpenCV库”,注意到引号里用了三个形容词,它们依次与路径中的【x86】、【vc12】、【lib】相对应。①【x86】:如果你想调用64位的库,那么在路径中写【x64】就行了(当然啦前提是这个库存在,前面也说过了,这里不赘述)。如果你不知道该调用32位还是64位的库,那么请和你自己的程序保持一致,这是最简单稳妥的做法。②【vc12】:与上一点一样,如果不知道该调用由哪个编译器生成的库,那么就与自己的程序保持一致。这是因为vcxx编译出来的库,依赖于一个叫做microsoft visual c++ 20xx redistributable package的东西(简称vcxx运行库),在安装VS20xx的时候会自动安装。本文调用vc12版的OpenCV库,VS版本为2013;如果使用VS2015编写程序,调用vc12版的OpenCV库,需安装vc12运行库。③【lib】:与该文件夹同级的,还有【bin】和【staticlib】文件夹。【lib】和【bin】提供动态链接库,【staticlib】提供静态库(关于静态库和动态库,可以看看这篇文章:C++静态库与动态库 吴秦)。如果你不知道该调用静态还是动态库,建议调用动态库。原因不多说,我自己也没有彻底弄清楚,就不误导别人了。

    步骤(3) 中,本文在【附加依赖项】中填入了【opencv_ts300.lib】和【opencv_world300.lib】。很多教程在这里,针对程序的debug版本和release版本,填入了不同的内容:debug版本会在".lib"前,加上一个字母"d"。这是为了让程序在debug模式下,调用debug版本的OpenCV库。我认为,只要你不需要在调试代码的时候,进入OpenCV库函数里面一探究竟,就没必要做这一步,毕竟debug库速度不及release库。所以按照本文的配置,无论VS用debug还是release模式,调用的都是release库。

    很多人不清楚debug模式和releas模式本的区别,简单按字面意思解释,debug版本用于调试,release版本用于发布。说一些它们的区别:前者会在编译阶段输出符号文件(.pdb文件),符号文件是调试的必需品;后者则会开启编译器的优化项,把一些中间变量优化掉——这就是为什么我们以release模式去调试的时候,很多变量的值都无法查看。

    步骤(3) 也能以显式的方法,写在代码里。将下面两行代码加在测试代码开头,就能代替 步骤(3) 了。

    #pragma comment(lib,"E:\ENV\opencv-3.0\build\x86\vc12\lib\opencv_ts300.lib")
    #pragma comment(lib,"E:\ENV\opencv-3.0\build\x86\vc12\lib\opencv_world300.lib")
    

    步骤(4) 中,本文这样配置,是为了让项目生成的exe文件在运行时,能够找到dll。exe在运行时,会在特定的目录下寻找自己依赖的库,它本身所在的目录肯定包含其中,故在第一种方法中,本文将OpenCV的dll拷贝到了exe的同级目录下;系统高级设置里面,环境变量【path】中的一连串目录也是exe搜索的范围,故在第二种方法中,本文将OpenCV的dll文件所在的目录,加入了环境变量【path】中。某些教程将OpenCV的dll拷贝到了system32这个系统目录下……虽然这方法行得通,但我觉得毫无优雅可言。

    最后,如果你有任何疑问与建议,或是我的文章存在纰漏,欢迎留言交流!

    知识共享许可协议
    本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可。

  • 相关阅读:
    8张图带你轻松温习 Java 知识.md
    关于 Java 序列化你不知道的 5 件事
    为什么 String 是不可变的?
    如何使用 Nginx 优雅地限流?
    JAVA泛型编程笔记
    java_接口的应用
    java_抽象类应用
    深入理解Java的接口和抽象类
    java_重写与重载的区别
    Java:按值传递还是按引用传递详细解说
  • 原文地址:https://www.cnblogs.com/fourseas/p/6294256.html
Copyright © 2020-2023  润新知