版本使用说明:
目前网上已经发布的教程大多是基于OpenCV,CUDA,TBB等较古老版本搭建的,对于深度学习,人工智能飞速发展的今天,引入新的版本,使用最新的功能特性,充分利用电脑的性能,从而加速项目的开发是非常有必要的。本项目选用的版本均为2023年到2024年之间发布的版本,既考虑了最新版本的不稳定性,又兼顾了一些新的功能特性,理论上该版本在未来五年内都是一个比较好的选择,如有不当之处,恳请大家批评指正。本项目版本编译时与网上的一些古老版本有一些不同之处,笔者在编译时一次编译成功,并测试完全可用,具体效果见下图。同时本文也介绍了一些环境变量的简短配置方法,解决环境变量路径长度限制的报错以及构建C++工程项目文件时的相对路径的设置。
本项目的构建硬件平台如下:
电脑操作系统:WINDOWS 10 22H2 19045.4894
CPU:Intel® Core™ i7-10870H CPU @ 2.20GHz
GPU:NVIDlA GeForce RTX 2070 with Max-Q Design
文件下载及准备工作
操作步骤
首先通过Win+R,输入cmd,通过nvidia -smi查询电脑所支持的CUDA最高版本
本电脑支持版本如下:
如果电脑显卡驱动过低,可以通过电脑中的NIVDIA GeForce Experience程序来更新驱动程序,在下图位置点击安装即可。
OpenCV版本链接:
https://opencv.org/releases/#:~:text=Google%20Summer%20of%20Code.%20Google%20Summer
OpenCV4.9.0版本链接
opencv_contrib-4.9.0
CUDA 12.3.2版本链接:
CUDA的历史版本下载
笔者这里选择的是CUDA Toolkit 12.3
cuDNN版本链接:
cuDNN历史版本
笔者这里选择的是Download cuDNN v8.9.7 (December 5th, 2023), for CUDA 12.x
Cmake版本下载
cmake-3.28.6-windows-x86_64.msi
Cmake版本发行说明
TBB版本下载
说明:TBB本身是一个函数库,因此不需要安装,只需要将下载好的文件解压到一个文件夹中,之后回到计算机的“环境变量”中配置环境变量路径,但请注意所有路径不能包含中文。 正常在使用OpenCV和CUDA的时候可以不添加TBB库,但是部分函数在加添TBB库时才能正常使用,所以建议在混合编译的过程中将TBB库一同编译进去。当然,如果仅仅是使用一些基础函数还是可以不加入的。如下给出了TBB库的安装过程。
oneapi-tbb-2021.13.0-win.zip
截止发稿时,该版本为当前发布的TBB最新版本。
好了,准备工作做好了,下面就是安装过程了。
对于OpenCV来说,直接解压下载好的两个文件夹即可。
安装OpenCV时注意设置如下目录架构:
------1.opencv4.9_source
--------- 1.1 opencv_contrib-4.9.0
--------- 1.2 opencv-4.9.0
--------------- 1.2.1 3rdparty
----------------1.2.2 apps
----------------1.2.3 build(注意,该名称为新建名称,即后续Cmake编译结果的存放路径)
--------------- 1.2.4 …
接下是CUDA的安装过程,为方便以后出现问题时快速找到目录,可参考笔者在C盘以外的安装路径:
D:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.3.2
其中NVIDIA GPU Computing Toolkit\CUDA\v12.3.2均为笔者新建文件夹 !
下面安装选择自定义
下面安装选项时,注意观察版本信息。
后面的三个选项因为电脑的当前版本比老版本的版本号更新,所以笔者选择较新的版本,因此后面三项笔者并未勾选。
接着将下载好的cuDNN解压,将里面的将bin,include,lib文件夹复制到刚才NVIDIA CUDA 12.3的安装位置,如图所示:
此时,需要在电脑中添加系统的环境变量
具体步骤如下:
WINDOWS 10 系统下右键此电脑,选择属性,在设置中打开高级系统设置,在下图页面中选择环境变量选项,找到系统变量。
在系统变量中找到Path变量,将下面几个变量添加进去。
D:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.3.2\libnvvp
D:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.3.2\bin
D:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.3.2\extras\CUPTI\lib64
由于笔者这里电脑环境变量过多,若将地址完整地传递进去,在后续添加环境变量时WINDOWS系统会报变量值过长的错误信息,因此,笔者建议在系统变量这一栏,选择新建,变量名以简短清晰明了为佳,该变量名不做特殊要求,可根据个人喜好起名字。变量值需要填写文件的具体的地址,此处填写地址是为了尽可能缩短在Path路径下的地址。笔者的变量名和变量值如下所示:
变量名:CUDA_PATH_V12_3
变量值:D:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.3.2
这里提供一个添加地址的教程:(仅是帮助理解,可以直接跳过)
假设添加地址为:
D:\OpenCV\opencv4.0.1\opencv\build\bin
D:\OpenCV\opencv4.0.1\opencv\build\etc
D:\OpenCV\opencv4.0.1\opencv
此时变量名可以自定义(但最好不要有中文)
变量值是其最大的公共部分,如:D:\OpenCV\opencv4.0.1\opencv。适当短一些也无伤大雅。
好了,书归正传,接下来点击系统变量中的Path,新建下方几个变量
%CUDA_PATH_V12_3%\libnvvp
%CUDA_PATH_V12_3%\bin
%CUDA_PATH_V12_3%\extras\CUPTI\lib64
注意,若电脑存在其他CUDA版本的环境变量,请将上面的三个环境变量上移到其他CUDA版本环境变量上方。
如果Cmake是想编译较少的安装包,环境更加简洁,出错概率更加小一些的话,如果不使用java,python等环境,可以考虑在这里暂时移除
接着配置TBB,Cmake的系统环境变量,由于笔者这两个安装包均直接安装在D盘,路径相对较短,这里直接在变量Path里直接添加。笔者这里直接给出自己路径参考。
D:\TBB21.13.0\include
D:\TBB21.13.0\redist\intel64\vc14
D:\Cmake\bin
项目编译
到这里前期工作已经差不多做好了,接下来是愉快的编译过程。
启动Cmake
Where is the source code:填写OpenCV的源码路径
Where to build the binaries:填写生成Cmake的路径(这里一定要按照前文提到的目录架构来写)
笔者目录参考如下:
!
Where is the source code: D:/OpenCV/opencv4.9_source/opencv-4.9.0
Where to build the binaries:D:/OpenCV/opencv4.9_source/opencv-4.9.0/build
初次直接点击Configure时会出现一些参数设置,具体如下
完成后进行一次环境构建。观察是否出现Java,Python等环境,
如果不想要该环境的,可以在Search中搜索其关键词,取消勾选即可。这里可以直接跳过。
下面是重点
在Search中搜索下面几项,并分别勾选
WITH_CUDA
WITH_TBB(注意只勾选这一个)
OPENCV_ENABLE_NONFREE
OPENCV_EXTRA_MODULES_PATH
并在此处的Value填写D:/OpenCV/opencv4.9_source/opencv_contrib-4.9.0/modules
为了提升项目的生成速度,若不需要test和sample相关的内容,这些标签可以去掉
继续搜索world
将其勾选
接着点击Configure,再次完成一次项目构建。
接着搜索CUDA_FAST_MATH,将其勾选上。
在Search中查询TBB
手动添加以下路径
D:/TBB21.13.0/lib/cmake/tbb
D:/TBB21.13.0/include
D:/TBB21.13.0/lib/intel64/vc14/tbb.lib
D:/TBB21.13.0/lib/intel64/vc14/tbb_debug.lib
在编译时可能出现以下报错:
cudacodec::VideoReader requires Nvidia Video Codec SDK:
cudacodec::VideoWriter requires Nvidia Video Codec SDK:
这个错误是因为OpenCV 的cudacodec模块使用 Nvidia Video Codec SDK 来处理视频解码( VideoReader)。如果系统中没有安装这个 SDK,或者 CMake 就无法找到它,编译时会提示这个警告。类似地,cudacodec模块的VideoWriter功能也依赖于 Nvidia Video Codec SDK 来进行视频编码。如果缺少该 SDK,或者没有正确配置,CMake 会发出警告。
解决方案如下:
1.安装Nvidia视频编解码器SDK:Nvidia Video Codec SDK
2.禁用相关选项:在Search中搜索WITH_NVCUVID和WITH_NVCUVENC,将其取消勾选即可。
在编译时还有一个重要选项,即GPU算力架构设置。
在Search中搜索CUDA_ARCH_BIN,这里面默认有几个值,代表了GPU的架构
常见值:
5.0:Maxwell
6.0, 6.1:Pascal
7.0, 7.5:Volta, Turing
8.0, 8.6:Ampere
9.0:Ada Lovelace, Hopper
在Search中搜索CUDA_ARCH_PTX
PTX代码是一种虚拟架构的代码,不针对任何特定的GPU架构,可以视作一种“汇编代码”。
作用:生成PTX代码通常是为了确保未来的CUDA驱动可以针对未被当前CUDA版本直接支持的未来GPU架构,动态编译生成适配的二进制代码。PTX在执行时,CUDA驱动会根据当前运行的GPU架构重新编译这些PTX代码。
使用场景:如果需要兼容未来发布的GPU架构,生成PTX代码会让程序具备更好的向前兼容性,但运行时需要额外的开销(在运行时重新编译PTX代码)。
笔者只打算让程序在 RTX 2070 或其他 Turing架构 GPU 上运行,故只设置CUDA_ARCH_BIN=7.5。CUDA_ARCH_PTX 可以设置为空,或者设置为 7.5,这样只生成 Turing 架构的代码,不会为其他未来架构生成额外的 PTX代码。笔者这里将CUDA_ARCH_PTX设置为空
再次点击Configure,观察输出是否有红色警告,务必多次Configure,直至红色警告消失。此时TBB_VER_FILE的值会有系统自动填充。
在TBB模块中可能会出现TBB_DIR-NOTFOUND错误。
错误原因如下:
CMake 通过查找 TBBConfig.cmake 或者 FindTBB.cmake 文件来定位 TBB 库。如果这些文件缺失或路径不正确,就会导致 TBB_DIR-NOTFOUND。
个人解决方案:将TBBConfig.cmake文件复制后放到目标路径文件夹下即可解决。但是该方法可能出现_tbb_debug_lib-NOTFOUND以及_tbb_release_lib-NOTFOUND。需要多次尝试,或重启或重启后Configure解决。
笔者在编译时较为顺利,因此提供的错误解决方案较少,部分博主提到出现一些错误可以尝试通过多次Configure解决。
再确认上述配置没有问题后,输出全白,说明配置没有问题,点击Generate。
生成的文件在D:/OpenCV/opencv4.9_source/opencv-4.9.0/build 路径下,此时建议使用Cmake打开项目,点击Open Project启动。
在生成选项中选择批生成
在ALL_BUILD,以及INSTALL上面打上勾,最后点击生成。此过程较为缓慢,在去掉tset,sample的情况下预计生成67个项目,大概耗时4小时左右,全量生成预计为263个项目。笔者在这一过程中较为顺利,未出现报错。如果存在其他错误请自查前面步骤是否有遗漏,或参照其他解决方案。
完成编译后,其生成路径放在下面路径中
D:\OpenCV\opencv4.9_source\opencv-4.9.0\build\install
在D:\OpenCV\opencv4.9_source\opencv-4.9.0\build\install\x64\vc16\lib
路径下的文件如下:
在D:\OpenCV\opencv4.9_source\opencv-4.9.0\build\install\x64\vc16\bin
路径下的文件如下:
运行测试
最后笔者新建项目进行GPU加速测试,以验证安装是否成功。
启动Visual Stduio 2019,选择创建新项目
笔者这里使用Release x64平台,并采用相对路径配置环境。
将D:\OpenCV\opencv4.9_source\opencv-4.9.0\build
下的install文件夹复制到目标项目中,笔者这里将其重命名为OpencvCudainstall,具体位置参考如下:
为配置项目的相对路径,方便项目的可移植性,笔者在项目的属性管理器中新建Opencv490_Cuda12_3的相对路径属性表。具体如下:
在VC++目录中配置包含目录如下:
.\OpencvCudainstall\include\opencv2
.\OpencvCudainstall\include
库目录配置如下:
.\OpencvCudainstall\x64\vc16\lib
解释:
. 表示当前所在的目录,意味着路径是从当前工作目录开始的。
\ 是路径分隔符,用于连接不同目录或文件夹。
../ 表示上一级目录
接着在链接器中找到输入,添加附加依赖项opencv_world490.lib
最后点击应用。
此时点击生成,选择生成解决方案。会发现和OpencvCudainstall同级的目录下出现了x64文件夹。
将......OpencvCudainstall\x64\vc16\bin
路径中的opencv_videoio_ffmpeg490_64.dll以及
opencv_world490.dll(Debug版本使用opencv_world490d.dll)复制到上面提到的x64\Release文件夹内。
通过这样配置,其他项目可通过移动OpencvCudainstall库文件,以及Opencv490_Cuda12_3相对路径属性表快速实现项目配置。
接着使用GPU测试文件测试,具体代码如下:
在Visual Stduio 2019中的源文件中新建.cpp文件。在OpencvCudainstall同级的目录中放置两张图片,笔者这里命名分别为yuan.bmp和1.bmp。请复制下面代码测试。
#include <iostream> // Console I/O
#include <sstream> // String to number conversion
#include <opencv2/core.hpp> // Basic OpenCV structures
#include <opencv2/core/utility.hpp>
#include <opencv2/imgproc.hpp>// Image processing methods for the CPU
#include <opencv2/imgcodecs.hpp>// Read images
// CUDA structures and methods
#include <opencv2/cudaarithm.hpp>
#include <opencv2/cudafilters.hpp>
using namespace std;
using namespace cv;
double getPSNR(const Mat& I1, const Mat& I2); // CPU versions
Scalar getMSSIM( const Mat& I1, const Mat& I2);
double getPSNR_CUDA(const Mat& I1, const Mat& I2); // Basic CUDA versions
Scalar getMSSIM_CUDA( const Mat& I1, const Mat& I2);
//! [psnr]
struct BufferPSNR // Optimized CUDA versions
{
// Data allocations are very expensive on CUDA. Use a buffer to solve: allocate once reuse later.
cuda::GpuMat gI1, gI2, gs, t1,t2;
cuda::GpuMat buf;
};
//! [psnr]
double getPSNR_CUDA_optimized(const Mat& I1, const Mat& I2, BufferPSNR& b);
//! [ssim]
struct BufferMSSIM // Optimized CUDA versions
{
// Data allocations are very expensive on CUDA. Use a buffer to solve: allocate once reuse later.
cuda::GpuMat gI1, gI2, gs, t1,t2;
cuda::GpuMat I1_2, I2_2, I1_I2;
vector<cuda::GpuMat> vI1, vI2;
cuda::GpuMat mu1, mu2;
cuda::GpuMat mu1_2, mu2_2, mu1_mu2;
cuda::GpuMat sigma1_2, sigma2_2, sigma12;
cuda::GpuMat t3;
cuda::GpuMat ssim_map;
cuda::GpuMat buf;
};
//! [ssim]
Scalar getMSSIM_CUDA_optimized( const Mat& i1, const Mat& i2, BufferMSSIM& b);
static void help()
{
cout
<< "\n--------------------------------------------------------------------------" << endl
<< "This program shows how to port your CPU code to CUDA or write that from scratch." << endl
<< "You can see the performance improvement for the similarity check methods (PSNR and SSIM)." << endl
<< "Usage:" << endl
<< "./gpu-basics-similarity referenceImage comparedImage numberOfTimesToRunTest(like 10)." << endl
<< "--------------------------------------------------------------------------" << endl
<< endl;
}
int main(int, char *argv[])
{
help(