OpenCV DNN模块,它允许运行预先训练的神经网络。该模块的主要缺点之一是其仅支持cpu推理,因为它是唯一受支持的模式。从OpenCV 4.2版本开始,DNN模块支持NVIDIA GPU使用,这意味着在其上运行深度学习网络时,CUDAcuDNN会加速。这篇文章将帮助我们学习在支持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脚本中使用OpenCVDNN 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设置为已安装的CUDA
  • OpenCL_LIBRARY设置为共享的OpenCL库
  • OpenCL_INCLUDE_DIR设置为带有OpenCL头文件的目录
  • 设置WITH_CUDA=ON, WITH_CUDNN=ON,启用CUDAcuDNN支持
  • 设置OPENCV_DNN_CUDA=ON以构建具有CUDA支持的DNN模块。这是最重要的标识。没有它,将无法生成支持CUDADNN模块。
  • 为优化目的启用了WITH_CUBLAS标志

此外,还有两个优化标志,ENABLE_FAST_MATHCUDA_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"
  1. 如果编译中断,根据下面的命令重新执行编译过程
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_160000pose_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虚拟环境而构建的。

源码地址:https://github.com/yuanxinshui/DeepLearnCV/tree/main/deep-learning-based-human-pose-estimation-using-opencv-cpp-python/

GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐