Windows下编译OpenCV + CUDA + cudnn + Python

前置条件:

  1. 使用vcpkg安装必须的第三方库(由于Ubuntu这样的系统可以按照系统版本并由cmake直接使用,但Windows不行)
  2. 安装CUDA和cudnn库,并保证相应的系统变量存在
  3. 在系统中安装一个python3

1. 对于CUDA版本太新导致报错

Disclaimer:
I have very limited knowledge of the OpenCV source code, so if you follow my “solution”, do it at your own risk.

Solution:
I “solved” this by using static_cast.

You want to change line 114 in opencv/modules/dnn/src/cuda4dnn/primitives/normalize_bbox.hpp:
from:
if (weight != 1.0)
to:
if (weight != static_cast<T>(1.0))

As well as line 124 in opencv/modules/dnn/src/cuda4dnn/primitives/region.hpp (due to a similar error):
from:
if (nms_iou_threshold > 0) {
to:
if (nms_iou_threshold > static_cast<T>(0)) {

Explanation:
Since both variables, weight and nms_iou_threshold, are templated and finally boil down to a primitive type during compilation, it is meaningful to use a static_cast to convert the respective constant (1.0 (by default double) and 0 (by default int)) to the template type. Based on the operator candidates the required types should all be compatible, i.e., the constant values are safe to be casted to the target template type.

2. 修改cmake文件,调整windows下编译行为

OpenCVDetectPython.cmake文件中,将下述部分:

if(PYTHON_DEFAULT_EXECUTABLE)
	set(PYTHON_DEFAULT_AVAILABLE "TRUE")
elseif(PYTHON2_EXECUTABLE AND PYTHON2INTERP_FOUND)
	# Use Python 2 as default Python interpreter
	set(PYTHON_DEFAULT_AVAILABLE "TRUE")
	set(PYTHON_DEFAULT_EXECUTABLE "${PYTHON2_EXECUTABLE}")
elseif(PYTHON3_EXECUTABLE AND PYTHON3INTERP_FOUND)
	# Use Python 3 as fallback Python interpreter (if there is no Python 2)
	set(PYTHON_DEFAULT_AVAILABLE "TRUE")
	set(PYTHON_DEFAULT_EXECUTABLE "${PYTHON3_EXECUTABLE}")
endif()

修改为:

if(PYTHON_DEFAULT_EXECUTABLE)
	set(PYTHON_DEFAULT_AVAILABLE "TRUE")
elseif(PYTHON3INTERP_FOUND) # PYTHON3_EXECUTABLE AND
	# Use Python 3 as fallback Python interpreter (if there is no Python 2)
	set(PYTHON_DEFAULT_AVAILABLE "TRUE")
	set(PYTHON_DEFAULT_EXECUTABLE "${PYTHON3_EXECUTABLE}")
elseif(PYTHON2INTERP_FOUND) # PYTHON2_EXECUTABLE AND
	# Use Python 2 as default Python interpreter
	set(PYTHON_DEFAULT_AVAILABLE "TRUE")
	set(PYTHON_DEFAULT_EXECUTABLE "${PYTHON2_EXECUTABLE}")
endif()

OpenCVDownload.cmake中修改:

execute_process(COMMAND  "${CMAKE_COMMAND}" -E tar xzf "${CACHE_CANDIDATE}"
	WORKING_DIRECTORY "${DL_DESTINATION_DIR}"
	RESULT_VARIABLE res)

变成下述部分,我的windows系统中安装了7zip并将exe文件添加到了系统路径,这个用于保证解压文件可以正确运行:

execute_process(COMMAND 7z x "${CACHE_CANDIDATE}"
	WORKING_DIRECTORY "${DL_DESTINATION_DIR}"
	RESULT_VARIABLE res)

3. 如何运行python?

首先,需要保证cmake命令中有-DBUILD_opencv_python3=ON来编译opencv-python相关部分,编译完成后,可以将生成的cv2.xxxx.pyd放到python的site-packages的目录中,在运行python import cv2之前,插入下述代码来保证可以找到对应的dll文件:

import os

os.add_dll_directory('D:\\Library\\OpenCV\\opencv\\build\\bin\\Release')
os.add_dll_directory('C:\\dev\\vcpkg\\installed\\x64-windows\\bin')
os.add_dll_directory('C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v12.3\\bin')

import cv2

4. 参考链接

Opencv-Python built for Windows x64 Python 3.7, .pyd file not found, OpenCV modules unavailable
Build OpenCV (including Python) with CUDA on Windows
ImportError: DLL load failed while importing cv2: The specified module could not be found.
CUDA 12.2 fp16 dnn compilation error