第二章 环境搭建与配置:OpenCV编译与安装、DNN模块依赖库配置、CUDA与CUDNN加速配置

说实话,环境搭建这件事,看着简单,但坑是真不少。我见过太多人卡在这一步,代码写好了,结果编译不过去,或者跑起来慢得像蜗牛。今天我就把这些年踩过的坑、积累的经验,一次性给你讲清楚。

2.1 OpenCV源码编译——为什么我不建议你用pip install

很多人图省事,直接 pip install opencv-python。嗯,这样确实快,但你想过没有——这个预编译包,它不带CUDA支持,也不带DNN模块的完整功能。说白了,就是个阉割版。

我在项目里遇到过,用pip装的OpenCV跑YOLOv8,一张1080Ti显卡,推理速度只有30fps。后来换成源码编译,开启CUDA加速,直接飙到120fps。差距就这么大。

核心原则:做深度学习模型部署,一定要源码编译OpenCV,自己控制开启哪些模块。

2.2 编译前的准备工作——依赖库清单

编译OpenCV之前,你得先把依赖装好。不然编译到一半报错,那才叫崩溃。我个人习惯用这个脚本一次性搞定:

# Ubuntu 20.04 / 22.04
sudo apt-get update
sudo apt-get install -y \
    build-essential cmake git pkg-config \
    libjpeg-dev libtiff-dev libpng-dev \
    libavcodec-dev libavformat-dev libswscale-dev \
    libv4l-dev libxvidcore-dev libx264-dev \
    libgtk-3-dev libcanberra-gtk3-module \
    libatlas-base-dev gfortran \
    libprotobuf-dev protobuf-compiler \
    libgoogle-glog-dev libgflags-dev \
    libhdf5-dev libhdf5-serial-dev

这里我特别想提醒你——libgtk-3-dev 这个包很多人会漏掉。没有它,OpenCV的 imshow() 函数就用不了。我曾经调试一个项目,图像死活显示不出来,查了半天才发现是GTK没装。

2.3 DNN模块依赖库配置——让OpenCV读懂深度学习模型

OpenCV的DNN模块,说白了就是个模型解析器。它要读懂各种框架的模型文件,就得依赖对应的库。

模型格式 依赖库 说明
TensorFlow (.pb) protobuf, libtensorflow_cc 需要编译时开启 WITH_PROTOBUF
ONNX (.onnx) protobuf, onnxruntime 推荐使用ONNX Runtime作为后端
Darknet (.weights) 无特殊依赖 OpenCV原生支持YOLO系列
PyTorch (.pt/.pth) libtorch 需要编译时开启 WITH_LIBTORCH

你想想看,如果你的项目里既有TensorFlow模型,又有ONNX模型,那这些依赖一个都不能少。我建议你全部装上,省得后面来回折腾。

2.4 CUDA与CUDNN加速配置——让显卡真正跑起来

这才是重头戏。没有CUDA加速,你的GPU就是个摆设。我见过有人买了RTX 4090,结果推理速度还不如CPU——就是因为没配CUDA。

2.4.1 检查你的硬件和驱动

先确认你的显卡支持CUDA:

nvidia-smi

看到显卡型号和驱动版本了吗?嗯,这里要注意——驱动版本不能太老。CUDA 11.x 需要驱动版本 >= 450.80.02,CUDA 12.x 需要 >= 525.60.13。

避坑指南:我曾经在Ubuntu 18.04上装CUDA 12.0,结果驱动死活不兼容。后来才发现,老系统对新CUDA的支持有限。建议Ubuntu 20.04以上系统,搭配CUDA 11.8或12.0。

2.4.2 安装CUDA Toolkit

我个人习惯用runfile安装,因为可以自定义路径。但如果你怕麻烦,用deb包也行:

# 以CUDA 11.8为例
wget https://developer.download.nvidia.com/compute/cuda/11.8.0/local_installers/cuda_11.8.0_520.61.05_linux.run
sudo sh cuda_11.8.0_520.61.05_linux.run

# 配置环境变量
echo 'export PATH=/usr/local/cuda-11.8/bin:$PATH' >> ~/.bashrc
echo 'export LD_LIBRARY_PATH=/usr/local/cuda-11.8/lib64:$LD_LIBRARY_PATH' >> ~/.bashrc
source ~/.bashrc

装完之后,用 nvcc --version 验证一下。如果看到版本号,说明CUDA装好了。

2.4.3 安装CUDNN

CUDNN是NVIDIA的深度学习加速库。没有它,卷积运算会慢很多。下载需要NVIDIA开发者账号,这个没办法,你得注册一个。

# 解压并复制到CUDA目录
tar -xzvf cudnn-linux-x86_64-8.9.0.131_cuda11-archive.tar.xz
sudo cp cudnn-*-archive/include/cudnn*.h /usr/local/cuda-11.8/include/
sudo cp -P cudnn-*-archive/lib/libcudnn* /usr/local/cuda-11.8/lib64/
sudo chmod a+r /usr/local/cuda-11.8/include/cudnn*.h /usr/local/cuda-11.8/lib64/libcudnn*

小技巧:安装完CUDNN后,用 cat /usr/local/cuda-11.8/include/cudnn_version.h | grep CUDNN_MAJOR -A 2 查看版本。如果显示8.x或9.x,说明安装成功。

2.5 编译OpenCV——最关键的一步

好了,所有依赖都准备好了。现在开始编译OpenCV。这里我给出一个经过实战检验的CMake配置:

cd opencv-4.9.0
mkdir build && cd build

cmake -D CMAKE_BUILD_TYPE=RELEASE \
      -D CMAKE_INSTALL_PREFIX=/usr/local \
      -D WITH_CUDA=ON \
      -D WITH_CUDNN=ON \
      -D OPENCV_DNN_CUDA=ON \
      -D CUDA_ARCH_BIN=8.6 \  # 根据你的显卡计算能力修改
      -D WITH_TBB=ON \
      -D WITH_OPENMP=ON \
      -D WITH_OPENGL=ON \
      -D BUILD_opencv_python3=ON \
      -D BUILD_opencv_python2=OFF \
      -D BUILD_EXAMPLES=OFF \
      -D BUILD_TESTS=OFF \
      -D BUILD_PERF_TESTS=OFF \
      -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-4.9.0/modules \
      ..

make -j$(nproc)
sudo make install

这里有几个参数我要特别说明一下:

  • CUDA_ARCH_BIN:这个值对应你显卡的计算能力。RTX 3090是8.6,RTX 4090是8.9,A100是8.0。查不到的话,去NVIDIA官网查一下。
  • OPENCV_DNN_CUDA:这个必须开!不开的话,DNN模块还是用CPU推理。
  • OPENCV_EXTRA_MODULES_PATH:指向opencv_contrib模块。这里面有很多好用的算法,比如SIFT、SURF等。

注意:编译时间取决于你的机器配置。我见过有人用4核CPU编译,等了两个小时。建议至少8核以上,或者用 make -j$(nproc) 充分利用多核。

2.6 验证安装——跑个测试看看

编译安装完成后,别急着写代码。先验证一下:

python3 -c "import cv2; print(cv2.getBuildInformation())"

在输出信息里,找到这几行:

  • CUDA:YES
  • CUDNN:YES
  • DNN:YES

如果都是YES,恭喜你,环境搭建成功了!

再跑个简单的推理测试:

import cv2
import numpy as np

# 加载ONNX模型
net = cv2.dnn.readNetFromONNX('model.onnx')
net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)
net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)

# 创建输入
blob = cv2.dnn.blobFromImage(np.random.rand(224,224,3).astype(np.uint8))
net.setInput(blob)
output = net.forward()

print("推理成功!输出形状:", output.shape)

如果看到输出形状,说明你的OpenCV已经能调用GPU做推理了。

2.7 常见问题与解决方案

最后,我整理了一些我遇到过的问题,希望能帮你少走弯路:

问题 原因 解决方案
编译时报错 "CUDA not found" CUDA路径没配置对 检查 /usr/local/cuda 是否存在,或者手动指定 -D CUDA_TOOLKIT_ROOT_DIR
推理时报错 "CUDNN not found" CUDNN没复制到CUDA目录 重新执行CUDNN的复制命令,注意权限
推理速度没提升 没有设置DNN后端为CUDA 检查代码中是否调用了 setPreferableBackendsetPreferableTarget
Python导入cv2报错 Python路径不对 pip install opencv-python-headless 覆盖,或者重新编译时指定Python路径

环境搭建这件事,说白了就是耐心活。我第一次配的时候,折腾了整整两天。但只要你按照这个流程走,应该半天就能搞定。嗯,如果遇到问题,别慌,多半是路径或者版本的问题,仔细检查一下就好。

下一章,我们会真正开始用OpenCV的DNN模块加载模型做推理。到时候你会发现,环境搭好了,后面的路就顺了。