Windows7+VS2012下64位OpenCV3.0+CUDA7.5的编译和部署

         http://johnhany.net/2015/10/windows7-compile-opencv3-with-cuda/

        从OpenCV 3.0 Beta开始,加入了大量的GPU加速计算的功能。6月份OpenCV 3.0 Gold发布,修复了大量的BUG。与2.4.x版本相比,3.0仍然采用CUDA作为GPU计算库,但废除了cv::gpu,转而使用cv::cuda命名空间。官网提供的预编译库并不包含完整的CUDA功能,所以要想体验GPU加速技术带给OpenCV的变化,只能自己重新编译整个库。

        在CUDA Toolkit 7.5中,虽然给出了适用Win32和x64两种目标架构的库,但像cufftnppsnvblas等OpenCV所需的库只有x64版本。于是这也限制了我们只能编译64位的OpenCV库,而且在今后的编程中也要编写针对x64架构的程序。另外,在GUI组件中,CUDA也调用了部分OpenGL功能,所以编译过程也需要OpenGL库的支持。下图中左边是CUDA为Win32提供的库,右边是为x64提供的库。

cuda-win32-64

        之前在编译OpenCV 2.4.x版本时,为了尽可能地提高计算速度,我用了Intel TBB来优化OpenCV库函数的多核计算性能,并用Eigen头文件库优化矩阵的计算,而且事实证明是可行并有效的。但在编译OpenCV 3.0 Gold的过程中,发现即使我引用了x64版本的TBB库文件,最后编译产生的OpenCV库在编程时还是会产生“应用程序无法正常启动0xc000007b”的错误。用Dependency Walk查看.lib文件也会发现几乎全部的组件都是“x64”,只有TBB一项是个突兀的“x86”。至于Eigen库,在编译过程中就产生了大量的错误。也许是我配置的方法不正确,也许目前的OpenCV库还不完善,总之我没有办法成功地将TBB包整合到OpenCV库中。

        事实证明,OpenCV 3.1可以成功整合TBB,IPPICV和Eigen。配置和编译过程的变化在文中以黄色做出了标记。

        由于需要调用显卡的部分功能,首先还要确认自己的显卡是否支持CUDA和OpenGL。可用的工具有GPU-Z和GPU Caps Viewer。右图中的“5.2”指的是最低兼容的CUDA版本。

GPU-Caps-Viewer

        关于CUDA 5.x和CUDA 7.5:首先,CUDA 5只支持到vs2010,而CUDA 7.5是支持vs2012的。其次,从OpenCV部分头文件看来除了CUDA Toolkit外还调用了其他比较特殊的库,虽然对CUDA 7.5大部分功能没有太大影响,但这也导致部分CUDA功能是无法整合到OpenCV库中的。在这里有更详细的说明。最新版本的NVIDIA Nsight声称已经支持vs2015了,不过我还没有试验过,无从知晓CUDA 7.5对vs2015的支持程度。

        当然,不使用CUDA而直接配置预编译OpenCV 3.0库的方法本文也有介绍,在这里。在Visual Studio中把Win32项目转换为x64项目的过程在这里。配置OpenCV 2.4.x的过程可以参考《Windows7+VS2010下OpenCV环境配置》


        先给出我的系统环境和会用到的所有库和工具:

        Windows 7 x64,Visual Studio Ultimate 2012,CPU是Intel Core i5 4590,显卡是NVIDIA GeForce GTX 960。

        OpenCV 3.0 Gold 下载地址:http://sourceforge.net/projects/opencvlibrary/files/opencv-win/3.0.0/opencv-3.0.0.exe/download

        OpenCV 3.1 下载地址:http://sourceforge.net/projects/opencvlibrary/files/opencv-win/3.1.0/opencv-3.1.0.exe/download

        CMAKE 3.4.0 rc1 下载地址:https://cmake.org/files/v3.4/cmake-3.4.0-rc1-win32-x86.exe

        CMAKE 3.5.0 rc3 下载地址:https://cmake.org/files/v3.5/cmake-3.5.0-win32-x86.msi

        CUDA Toolkit 7.5.18 下载地址:http://developer.download.nvidia.com/compute/cuda/7.5/Prod/local_installers/cuda_7.5.18_windows.exe

        TBB 4.4 Update 3 下载地址:https://www.threadingbuildingblocks.org/sites/default/files/software_releases/windows/tbb44_20160128oss_win_0.zip

        Eigen 3.2.8 下载地址:http://bitbucket.org/eigen/eigen/get/3.2.8.zip

        OpenGL 4.5 关于OpenGL 4编译和配置的详细过程,可以参考《Windows7+VS2012下OpenGL 4的环境配置》,只是在CMAKE中第一次点击Configure后要选择“Visual Studio 11 2012 Win64”作为Generator;编译好之后在配置环境时选择x64路径下的lib目录。


        1.下载CMAKE和CUDA Toolkit并安装。

        安装过程这里就不赘述了。需要注意的是,CMAKE的安装路径可以随意指定,CUDA Toolkit库本身的路径推荐用默认的C:\Program Files\NVIDIA GPU Computing Toolkit,不要修改;不过CUDA Samples的路径最好设为C盘以外的分区,比如F:\_Projects\CUDA Samples。因为在编译CUDA样例的过程中,可能会由于管理权限的原因编译器不能在样例目录内修改和写入文件,造成编译的失败。

        CUDA Toolkit安装过程中会自动在Visual Studio安装NSIGHT插件。如果之前安装过较老版本的CUDA Toolkit,则会被自动卸载掉,并用7.5版本将其代替。安装程序也会自动在系统环境变量内修改“PATH”,添加“CUDA_INC_PATH”、“CUDA_LIB_PATH”、“CUDA_PATH”等值,所以我们不必过多担心CUDA的环境配置。

        如果想验证CUDA是否配置正确,可以尝试编译任意一个CUDA自带的样例程序。这里以deviceQuery为例。

        在CUDA Samples\1_Utilities\deviceQuery路径下找到deviceQuery_vs2012.sln项目文件,并用VS2012打开。我的路径是F:\_Projects\CUDA Samples\1_Utilities\deviceQuery。

cuda-device-query        打开之后,右击项目名称,点击Build。注意在DebugRelease两种模式下分别编译。

cuda-device-query-build        编译成功后,运行cmd.exe,切换到CUDA Samples\bin\win64\Debug目录,运行deviceQuery.exe,看能否通过测试。

cuda-device-query-debug

        再切换到CUDA Samples\bin\win64\Release目录,运行deviceQuery.exe,看能否通过测试。

cuda-device-query-release


        2.下载并解压OpenCV。

        在前面所给的链接下载OpenCV 3.0,双击打开,选择解压路径。比如E:\dev-lib。程序会自动在E:\dev-lib下建立名为opencv的文件夹,并把所有的文件解压到E:\dev-lib\opencv内。为了与OpenCV 2.4.x版本区分开,我把这个文件夹的名称改为了E:\dev-lib\opencv3

opencv-extraction        解压完成后,在E:\dev-lib\opencv3里有两个名为buildsources的文件夹,其中build是预编译库,sources包含OpenCV的源代码。我们就是利用sources文件夹里的源码进行编译。如果不打算使用CUDA组件而只需要常用的模块,可以直接使用预编译库来进行开发环境的配置。但OpenCV 3.0只提供了用于vs2012和vs2013的预编译库,如果你的Visual Studio是这两个版本以外的,仍然需要自己编译。如果决定继续使用CUDA,则可以跳过这一部分,直接看第3步。在使用的过程中也会发现预编译库把很多模块合并到了两个文件中,但如果是自己编译,仍然会产生像之前版本那样很多个文件。

        直接使用OpenCV 3.0预编译库配置开发环境的步骤如下:

        打开开始菜单,右击计算机,点击属性,在弹出的窗口里依次点击高级系统设置->高级->环境变量,双击名为path的用户环境变量,如果没有这一项,则点击新建建立一个名为path的变量。

pre-built-environment

        在变量值的末尾添加:

        点击确定保存环境变量。打开cmd.exe,输入

强制更新系统变量,以使刚刚的修改生效。

cmd-set-path        重新打开cmd.exe,输入

检查环境变量的修改是否生效。

cmd-echo-path

       注销并重新登录Windows,重启电脑等都可以更新环境变量。不过值得注意的是每次修改环境变量后,都需要重新打开Visual Studio才能对vs生效。

       打开vs2012,新建一个Visual C++的Win32 Console项目,我这里命名为“ocv-test-vc11”。

pre-built-new-project       点击OK,再点击Next,勾选Empty Project,点击Finish

pre-built-new-project-2       在左边Solution Explorer中右击项目名称,点击Properties。顶端的Configuration选择Debug,在属性窗口里选择Configuration Properties -> VC++ Directories,在右边的Include Directories里添加

       在Library Directories里添加

pre-built-new-project-5       在左边选择Linker -> Input,在右边的Additional Dependencies里添加

pre-built-new-project-6       点击应用,以保存更改。把顶端的Configuraion改为Release,在左边选择Configuration Properties -> VC++ Directories,在右边的Include Directories里添加

       在Library Directories里添加

pre-built-new-project-7       在左边选择Linker -> Input,在右边的Additional Dependencies里添加

pre-built-new-project-8

       点击确定,以保存修改并关闭窗口。

       在左边的Solution Explorer中右击Source Files -> Add -> New Item,新建一个cpp代码文件。

pre-built-new-project-3

       我这里命名为ocv-test-vc11.cpp。pre-built-new-project-4

       把下面的代码拷贝到ocv-test-vc11.cpp中。

       第10行是输入图片的路径,可以自己随意修改,但要注意路径中的分隔符“\”要换成“\\”。

       如果打算编写64位的程序,则需要把环境变量和库路径里的“x86”换成“x64”。然后如图打开Configuration Manager

pre-built-new-project-10       在弹出的窗口里,打开Active Solution Platform下的下拉菜单,点击<New…>,在Type or select the new platform里选择x64Copy settings from保持Win32不变,点击OK

pre-built-new-project-11

       编译项目之前如果需要切换到Release,还要在Configuration Manager中按下图更改Configuration

pre-built-new-project-12

       我使用的输入图像为skull.jpg

skull       程序运行结果为

pre-built-new-project-9


        3.使用CMAKE编译OpenCV。

        打开CMAKE。点击Browse source,选择OpenCV的源码路径,我的是E:/dev-lib/opencv3/sources。点击Browse Build,选择编译结果的保存位置,我的是F:/_Projects/opencv3。

        点击Configure,在弹出的窗口中选择“Visual Studio 11 2012 Win64”,然后点击Finish

cmake_generator        如果在下面输出区域里没有出现红色的错误信息,而且最后一行是“Configuring done”,就可以进行下一步了。

        勾选WITH_TBB,WITH_IPP,WITH_EIGEN。由于OpenCV源码没有附带FFMPEG和IPPICV的完整文件,需要在生成的过程中自动下载,有时速度会很慢。我提供了这两个库的完整文件,以节约时间:http://pan.baidu.com/s/1bcQoR8。解压后只需要将ffmpeg和ippicv两个文件夹覆盖opencv\sources\3rdparty中相应的文件夹即可。TBB解压的目录为E:\dev-lib\tbb,Eigen解压的目录为E:\dev-lib\Eigen。TBB和Eigen的路径设置如下:

        TBB_INCLUDE_DIRS    E:/dev-lib/tbb/include

        TBB_LIB_DIR    E:/dev-lib/tbb/lib/intel64/vc11

        EIGEN_INCLUDE_PATH    E:/dev-lib/Eigen

        可能需要单独设置TBB_STDDEF_PATH为E:/dev-lib/tbb/include/tbb/tbb_stddef.h。

        需要注意的是,E:\dev-lib\Eigen目录内还有一个单独的名为Eigen的文件夹,在这个E:\dev-lib\Eigen\Eigen文件夹内,包含所有的Eigen头文件。

        在上面的区域里选择编译所要包含的组件。由于之前提到的原因,WITH_TBB不能勾选。虽然默认勾选了WITH_EIGEN,但EIGEN_INCLUDE_PATH不需要指定,在编译过程中仍然会忽略Eigen。WITH_NVCUVID这一项也不能勾选,因为在OpenCV目录下的sources\modules\cudacodec\src\precomp.hpp文件有这样一行(第7行)

        除了NVCUVID库之外,这里调用了独立的NVENC SDK。NVCUVID与NVENC SDK共同构成了NVIDIA video codec SDK,其中NVCUVID库是包含在CUDA Toolkit中的,而NVENC SDK是一个独立的SDK,而且对显卡的架构要求比较严格,较常见的GeForce系列显卡即使支持但性能也是受限的。总之在我的机器上只有NVCUVID,却没有NVENC SDK。考虑到OpenCV是把NVCUVID和NVENC SDK一同调用的,所以只好全部抛弃。对我们的影响只在于不能用显卡进行视频的解码与编码,其实用OpenCV默认的在CPU端的ffmpeg库也可以满足大部分快速编码解码的需求。

        总之,我们需要勾选的是WITH_TBB、WITH_IPP、WITH_EIGEN、WITH_CUBLASWITH_CUDAWITH_CUFFTWITH_OPENGL,其中WITH_EIGEN、WITH_CUDAWITH_CUFFT是默认开启的。

cmake_configure

        再次点击Configure。如果没有红色错误信息产生,点击Generate,生成项目文件。如果下方输出区域最后两行是“Configuring done”和“Generating done”,就可以进行下一步的编译了。


        4.用Visual Studio编译OpenCV

        用Visual Studio 2012打开刚才生成的vs项目文件,比如我的是F:\_Projects\opencv3\OpenCV.sln。程序会花一些时间载入所有所需的文件。如果还安装了Visual Assist之类的插件,初始化时间还会延长更多。

        首先在Debug模式下,右击ZERO_CHECK项目,点击Build;再切换到Release模式下,右击ZERO_CHECK项目,点击Build。看两次编译是否产生错误。如果两次编译成功,则进行下一步。

build-opencv        在Debug模式下,右击INSTALL项目,点击Build,整个编译过程就开始了,这大概需要两个小时的时间。

build-opencv-2

        由于编译过程非常耗时,所以在编译之前检查所有的设置是否正确是很有必要的。我在这里列了一个表格,用来参考是否所有的步骤都正确完成了。

CUDA 系统环境变量PATH,CUDA_INC_PATH,CUDA_LIB_PATH
  C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.5\lib\x64中包含cublas cuda cufft nppc nppi npps
OpenGL 环境变量PATH指向bin\x64  glew32.dll文件拷贝到C:\Windows\SysWOW64目录下
CMAKE 勾选WITH_CUBLAS,WITH_CUDA,WITH_CUFFT,WITH_OPENGL,WITH_TBB,WITH_IPP,WITH_EIGEN
  没有勾选WITH_TBB,WITH_NVCUVID
  EIGEN_INCLUDE_PATH为空  EIGEN_INCLUDE_PATH为E:/dev-lib/Eigen
  TBB_INCLUDE_DIRS为E:/dev-lib/tbb/include,TBB_LIB_DIR为E:/dev-lib/tbb/lib/intel64/vc11
VS2012 目标平台为x64

        编译完成后,切换到Release模式,右击INSTALL项目,点击Build。这次编译同样也需要两个小时左右的时间。如果编译过程中产生了错误,可以把错误信息贴在在下面的评论区。如果两次都成功了,把install文件夹(我的是F:\_Projects\opencv3\install)里的内容复制到一个更方便的路径。比如我在E:\dev-lib\opencv3下新建了一个名为“with-cuda”的文件夹,并把install里的etc,include,x64三个文件夹拷贝了进去。接着就可以开始测试我们编译的OpenCV库了。

build-opencv-3


        5.测试程序

        按照第2步中的过程修改环境变量,只不过环境变量值要用

        按照第2步中的过程新建一个vs2012项目,并修改为x64架构。比如我的项目名称为“ocv3-test”。项目属性的VC++ Directories中的Include DirectoriesLibrary Directories要修改为

        Linker -> Input中的Additional Dependencies要修改为

(Debug)

(Release)

        测试代码如下

        我仍然使用第2步中的skull.jpg图像,程序运行的结果为

build-opencv-4        在代码第16行的注释其实是给出了另一种将数据从GpuMat传递到Mat的方式。很多OpenCV库函数既有CPU版又有CUDA版的,这段代码也反映了本地与GPU之间数据传递的最常用的方式。

        把数据从cv::Mat传递到cv::cuda::GpuMat

        把数据从cv::cuda::GpuMat传递到cv::Mat


        我编译的整合了CUDA和OpenGL的OpenCV库在这里可以下载,但是我不能保证在相似的环境下也能使用。

                http://pan.baidu.com/s/1qW3lF2G


2016.10.27更新:

        OpenCV 3.1.0版本所需的ffmpeg和ippicv库文件在这里下载:http://pan.baidu.com/s/1miFF5os

2016.01.05更新:

        OpenCV 3.1.0版本用本文方法也能够编译成功。不过在最后测试步骤中,除了要把所有*.lib文件名中的“300”改为“310”之外,还要注意OpenCV 3.1.0版本的lib比3.0.0版本少了一个“opencv_hal300”。

        整合了CUDA和OpenGL的OpenCV 3.1.0库在这里下载:http://pan.baidu.com/s/1kTVu8M7​

        如果发现在调试的时候弹出一个小黑框长时间没有反应,可以把Debug Type从默认的“Auto”改为“GPU Only”。

2016.03.15更新:

        更新了OpenCV 3.1整合TBB,IPPICV,Eigen的步骤。修改了OpenGL环境需求的错误。