OpenCV DNN模块在linux中如何使用NVIDIA GPU
OpenCV DNN模块,它允许运行预先训练的神经网络。该模块的主要缺点之一是其仅支持cpu推理,因为它是唯一受支持的模式。从OpenCV 4.2
版本开始,DNN模块支持NVIDIA GPU
使用,这意味着在其上运行深度学习网络时,CUDA
和cuDNN
会加速。这篇文章将帮助我们学习在支持DNN GPU
的情况下编译OpenCV库,以加速神经网络推理。我们将学习使用NVIDIA gpu
优化OpenCV DNN
模块。
Ubuntu 18.04安装说明
为了在OpenCV中启用NVIDIA GPU支持,我们必须使用从头开始编译正确的配置。
步骤1: 准备条件
为了确保您拥有启动所需的一切,运行以下命令来安装您可能缺少的软件包:
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install build-essential cmake unzip pkg-config
sudo apt-get install libjpeg-dev libpng-dev libtiff-dev
sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev
sudo apt-get install libv4l-dev libxvidcore-dev libx264-dev
sudo apt-get install libgtk-3-dev
sudo apt-get install libblas-dev liblapack-dev gfortran
sudo apt-get install python3-dev
步骤2:获取OpenCV来源码
第一步是下载OpenCV库源代码。我们将使用最新的版本4.5.1
。
要下载到$HOME
文件夹,只需在终端中运行以下命令:
cd ~
wget -O opencv-4.5.1.zip https://github.com/opencv/opencv/archive/4.5.1.zip
unzip -q opencv-4.5.1.zip
mv opencv-4.5.1 opencv
rm -f opencv-4.5.1.zip
你也需要对opencv_contrib
模块做同样的事情:
注:和opencv_contrib版本号需一致
wget -O opencv_contrib-4.5.1.zip https://github.com/opencv/opencv_contrib/archive/4.5.1.zip
unzip -q opencv_contrib-4.5.1.zip
mv opencv_contrib-4.5.1 opencv_contrib
rm -f opencv_contrib-4.5.1.zip
步骤3:CUDA安装
从NVIDIA网站下载并安装适合您系统的CUDA版本。最好是遵循NVIDIA文档中的Ubuntu安装说明。
步骤4:cuDNN安装
从NVIDIA网站下载并安装适合您系统的cuDNN版本。您可以按照NVIDIA文档中的Ubuntu安装说明进行安装。
这篇文章已经用cuDNN v8.0.3测试过了,我们推荐你使用相同的版本。
步骤5:安装Python依赖
如果我们也想在我们的Python脚本中使用OpenCV
与DNN GPU
支持,我们将需要生成OpenCV-Python绑定。你可以把它们想象成一个桥梁,可以从python脚本内部调用c++ OpenCV函数。
首先,让我们创建一个新的虚拟环境。确保你有virtualenv包,否则执行以下命令安装它:
pip install virtualenv
创建新的虚拟环境env
python3 -m venv ~/env
```shell
激活虚拟环境
```shell
source env/bin/activate
安装numpy包
pip install numpy
步骤6: 编译OpenCV库
创建build目录并进入
cd ~/opencv
mkdir build
cd build
通过cmake进行编译
cmake \
-D CMAKE_BUILD_TYPE=RELEASE \
-D CMAKE_INSTALL_PREFIX=/usr/local \
-D INSTALL_PYTHON_EXAMPLES=OFF \
-D INSTALL_C_EXAMPLES=OFF \
-D OPENCV_ENABLE_NONFREE=ON \
-D OPENCV_EXTRA_MODULES_PATH=~/opencv_contrib/modules \
-D PYTHON_EXECUTABLE=~/env/bin/python3 \
-D BUILD_EXAMPLES=ON \
-D WITH_CUDA=ON \
-D WITH_CUDNN=ON \
-D OPENCV_DNN_CUDA=ON \
-D WITH_CUBLAS=ON \
-D CUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda-10.2 \
-D OpenCL_LIBRARY=/usr/local/cuda-10.2/lib64/libOpenCL.so \
-D OpenCL_INCLUDE_DIR=/usr/local/cuda-10.2/include/ \
..
注意后面的..
,不要忘记了。
参数说明,如下:
- 将
OPENCV_EXTRA_MODULES_PATH
设置为opencv_contrib文件夹的位置 - 将
PYTHON_EXECUTABLE
设置为创建的python虚拟环境 CUDA_TOOLKIT_ROOT_DIR
设置为已安装的CUDAOpenCL_LIBRARY
设置为共享的OpenCL库- 将
OpenCL_INCLUDE_DIR
设置为带有OpenCL头文件的目录 - 设置
WITH_CUDA=ON
,WITH_CUDNN=ON
,启用CUDA
和cuDNN
支持 - 设置
OPENCV_DNN_CUDA=ON
以构建具有CUDA
支持的DNN
模块。这是最重要的标识。没有它,将无法生成支持CUDA
的DNN
模块。 - 为优化目的启用了
WITH_CUBLAS
标志
此外,还有两个优化标志,ENABLE_FAST_MATH
和CUDA_FAST_MATH
,它们用于优化和加快数学操作。然而,当您启用这些标志时,浮点计算的结果并不能保证符合IEEE。如果您希望快速计算和精度不是问题的挂,您可以继续使用这些选项。这个链接详细解释了准确性方面的问题
如果一切正常,将会收到如下消息,说明配置成功:
仔细检查,NVIDIA是ON的,CUDA已经被发现:
现在,您可以运行make命令:
make -j12
编译问题解决
1. 编译OpenCV以及openc_contrib提示缺少boostdesc_bgm.i文件出错的解决
参考链接:https://www.cnblogs.com/penuel/p/13696252.html
由于网速等原因,以下文件需要在本地下载好,其中下载链接可以在build
文件夹下的日志文件CMakeDownloadLog.txt
,在日志文件CMakeDownloadLog.txt
中搜索 boostdesc_bgm.i
关键词 (不是在文件夹中搜索)
日志文件里就有它的下载地址,直接复制其下载地址到网页可以看该到文件的源码,直接拷贝源码并生存同名文件,放在 opencv_contrib/modules/xfeatures2d/src/
路径下即可。
总共缺了以下几个文件,都需要下载拷贝:
boostdesc_bgm.i
boostdesc_bgm_bi.i
boostdesc_bgm_hd.i
boostdesc_lbgm.i
boostdesc_binboost_064.i
boostdesc_binboost_128.i
boostdesc_binboost_256.i
vgg_generated_120.i
vgg_generated_64.i
vgg_generated_80.i
vgg_generated_48.i
如果不想自己下载,可以直接下载我下载好的文件,文件链接:ubantu 下安装C++ 版opencv的依赖文件
2 提示找不到feature2d/test/test_detectors_regression.impl.hpp
参考链接:https://blog.csdn.net/xiewenrui1996/article/details/108683866
编译过程中出现如下错误:
3 .①fatal error: features2d/test/test_detectors_regression.impl.hpp: No such file or directory
原因是没找到这个文件,解决方法如下:
将opencv4.4.0 / modules / 下的features2d文件复制,然后粘贴到build目录中来解决该问题
4. 编译过程提示opencv2/xfeatures2d/cuda.hpp: No such file or directory
解决方法
在opencv/modules/stitching/CMakeLists.txt
文件中加入一条语句使其include opencv_contrib/modules/xfeatures2d/include
,可以是绝对路径,如
INCLUDE_DIRECTORIES("/home/spring/Soft/opencv3.4.2/opencv_contrib/modules/xfeatures2d/include"
- 如果编译中断,根据下面的命令重新执行编译过程
make clean
make -j12
make需要一些时间。make完成后,运行:
sudo make install
sudo ldconfig
唯一剩下的事情就是向Python环境添加符号链接
。要做到这一点,请cd到您的虚拟环境site-packages
目录,并链接新构建的OpenCV库:
cd ~/env/lib/python3.x/site-packages/
ln -s /usr/local/lib/python3.x/site-packages/cv2/python-3.x/cv2.cpython-3xm-x86_64-linux-gnu.so cv2.so
不要忘记将“x”符号替换为您拥有的Python版本。由于我们使用Python 3.7,在本例中,x = 7。
就是这样!现在你可以使用带有DNN GPU
支持的OpenCV
库来实现代码。
测试示例代码
我们将测试OpenPose的代码,这可以在https://github.com/yuanxinshui/DeepLearnCV/tree/main/deep-learning-based-human-pose-estimation-using-opencv-cpp-python/中找到
读取模型
C++:
// Specify the paths for the 2 files
string protoFile = "pose/mpi/pose_deploy_linevec_faster_4_stages.prototxt";
string weightsFile = "pose/mpi/pose_iter_160000.caffemodel";
// Read the network into Memory
Net net = readNetFromCaffe(protoFile, weightsFile);
pose_iter_160000
和 pose_iter_400000
模型下载
Python:
# Specify the paths for the 2 files
protoFile = "pose/mpi/pose_deploy_linevec_faster_4_stages.prototxt"
weightsFile = "pose/mpi/pose_iter_160000.caffemodel"
# Read the network into Memory
net = cv2.dnn.readNetFromCaffe(protoFile, weightsFile)
读取图像并预处理
C++:
// Read Image
Mat frame = imread("single.jpg");
// Specify the input image dimensions
int inWidth = 368;
int inHeight = 368;
// Prepare the frame to be fed to the network
Mat inpBlob = blobFromImage(frame, 1.0 / 255, Size(inWidth, inHeight), Scalar(0, 0, 0), false, false);
// Set the prepared object as the input blob of the network
net.setInput(inpBlob);
Python:
# Read image
frame = cv2.imread("single.jpg")
# Specify the input image dimensions
inWidth = 368
inHeight = 368
# Prepare the frame to be fed to the network
inpBlob = cv2.dnn.blobFromImage(frame, 1.0 / 255, (inWidth, inHeight), (0, 0, 0), swapRB=False, crop=False)
# Set the prepared object as the input blob of the network
net.setInput(inpBlob)
预测并提取关键点
C++:
Mat output = net.forward()
int H = output.size[2];
int W = output.size[3];
// find the position of the body parts
vector<Point> points(nPoints);
for (int n=0; n < nPoints; n++)
{
// Probability map of corresponding body's part.
Mat probMap(H, W, CV_32F, output.ptr(0,n));
Point2f p(-1,-1);
Point maxLoc;
double prob;
minMaxLoc(probMap, 0, &prob, 0, &maxLoc);
if (prob > thresh)
{
p = maxLoc;
p.x *= (float)frameWidth / W ;
p.y *= (float)frameHeight / H ;
circle(frameCopy, cv::Point((int)p.x, (int)p.y), 8, Scalar(0,255,255), -1);
cv::putText(frameCopy, cv::format("%d", n), cv::Point((int)p.x, (int)p.y), cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(0, 0, 255), 2);
}
points[n] = p;
}
Python:
output = net.forward()
H = out.shape[2]
W = out.shape[3]
# Empty list to store the detected keypoints
points = []
for i in range(len()):
# confidence map of corresponding body's part.
probMap = output[0, i, :, :]
# Find global maxima of the probMap.
minVal, prob, minLoc, point = cv2.minMaxLoc(probMap)
# Scale the point to fit on the original image
x = (frameWidth * point[0]) / W
y = (frameHeight * point[1]) / H
if prob > threshold :
cv2.circle(frame, (int(x), int(y)), 15, (0, 255, 255), thickness=-1, lineType=cv.FILLED)
cv2.putText(frame, "{}".format(i), (int(x), int(y)), cv2.FONT_HERSHEY_SIMPLEX, 1.4, (0, 0, 255), 3, lineType=cv2.LINE_AA)
# Add the point to the list if the probability is greater than the threshold
points.append((int(x), int(y)))
else :
points.append(None)
cv2.imshow("Output-Keypoints",frame)
cv2.waitKey(0)
cv2.destroyAllWindows()
Draw Skeleton
C++:
for (int n = 0; n < nPairs; n++)
{
// lookup 2 connected body/hand parts
Point2f partA = points[POSE_PAIRS[n][0]];
Point2f partB = points[POSE_PAIRS[n][1]];
if (partA.x<=0 || partA.y<=0 || partB.x<=0 || partB.y<=0)
continue;
line(frame, partA, partB, Scalar(0,255,255), 8);
circle(frame, partA, 8, Scalar(0,0,255), -1);
circle(frame, partB, 8, Scalar(0,0,255), -1);
}
Python:
for pair in POSE_PAIRS:
partA = pair[0]
partB = pair[1]
if points[partA] and points[partB]:
cv2.line(frameCopy, points[partA], points[partB], (0, 255, 0), 3)
为了用CUDA运行代码,我们将对c++和Python代码需要添加如下代码:
net.setPreferableBackend(DNN_BACKEND_CUDA);
net.setPreferableTarget(DNN_TARGET_CUDA);
net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)
net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)
这就是使用CUDA加速运行代码所需要的所有代码更新。后端使用GPU和CPU的结果如下。
在这个例子中,GPU输出比CPU输出快10倍!
GPU执行一帧需要0.2秒,而CPU需要2.2秒。对于这个代码示例,CUDA后端减少了90%以上的执行时间。
总结
在这篇文章中,我们安装了支持CUDA的OpenCV。首先,我们通过安装所需的OS库来准备系统。然后在系统上安装CUDA和cuDNN。最后,我们从源代码构建OpenCV,并解释了我们使用的不同的CMake选项。OpenCV也是为Python虚拟环境而构建的。
更多推荐
所有评论(0)