System designTroubleshooting

cv2.cuda modules missing in Python: check the installed build

Why a CUDA build exposes only cv2.cuda_GpuMat and core classes, how to verify the imported wheel, and the CMake settings that bring back the missing modules.

LumaSpec Vision10 min read Share on LinkedIn

On this page 10 sections
  1. 01The symptom: eight core classes and nothing else
  2. 02Test 1: which wheel did the interpreter actually load
  3. 03Read the report: four lines decide it
  4. 04Likely causes, ranked
  5. 05Worked example: the 4.6.0 wheel that exposed eight core names
  6. 06The rebuild that restores the algorithm bindings
  7. 07Prove the fix, then keep it proving itself
  8. 08When you should not build CUDA at all
  9. 09The box that runs the wheel
  10. 10Questions

You compiled OpenCV with CUDA, pip installed the wheel, and import cv2 works — yet cv2.cuda offers a short list of core classes and nothing else. Calling cv2.cuda.createFarnebackOpticalFlow raises AttributeError while the CMake log insists every cuda module was built. That gap wastes afternoons on driver reinstalls that cannot fix it. This guide walks the checks in the order that finds the real defect: which wheel the interpreter actually loaded, what that binary's own build report says, which cause explains the missing algorithm bindings, and the CMake settings that generate them. You finish with a three-line test that proves the fix inside the environment you deploy.

The symptom: eight core classes and nothing else

A healthy CUDA build lets you upload a frame to a cv2.cuda_GpuMat and run algorithms on it: cv2.cuda.cvtColor for colour conversion, cv2.cuda.createFarnebackOpticalFlow() for dense optical flow. The broken build keeps the types and drops the algorithms. Listing the namespace shows the same eight core names every time: cv2.cuda_GpuMat, cv2.cuda_Stream, cv2.cuda_HostMem, cv2.cuda_Event, cv2.cuda_DeviceInfo, cv2.cuda_BufferPool, cv2.cuda_GpuMatAllocator and cv2.cuda_TargetArchs. Every factory function and every cudaimgproc or cudaoptflow call is absent, so the first algorithm call dies with AttributeError.

Two failure shapes exist, and they need different fixes. If import cv2 itself fails, the build generated no Python wrappers at all. If the import works but the namespace holds only those eight types, the wrappers exist and the binding export for the algorithm classes is what went wrong — the case this guide repairs.

Test 1: which wheel did the interpreter actually load

OpenCV variants — the base package, the contrib package, a locally built wheel — all install a module named cv2. The variant installed last shadows the others, so the wheel you configured CMake for is not necessarily the one Python imports. Ask the interpreter, not the shell:

import cv2
print(cv2.__version__)  # str; 4.6.0+4638ce5 marks a local build of commit 4638ce5
print(cv2.__file__)     # str; the binary file that actually runs

If file points outside the environment you configured, or pip list shows more than one OpenCV entry, stop here: uninstall every OpenCV package and install exactly one. The same shadowing logic hides GenICam packages on a mismatched interpreter — GenICam Python package not found: match your interpreter walks that variant.

Then print the build report from inside the same interpreter:

print(cv2.getBuildInformation())  # str: the configure summary of the loaded binary

The report travels with the binary; the console output of pip wheel describes the build folder, and the two diverge once a later attempt overwrites or bypasses an earlier wheel.

Read the report: four lines decide it

Scan the report for four lines. Everything else — compiler flags, image codecs, GUI backends — does not affect the bindings.

Report line Healthy answer What a failure means
NVIDIA CUDA YES (ver 11.7), with the GPU arch list under it WITH_CUDA never reached CMake; no CUDA code in the wheel
OpenCV modules: To be built cudaarithm, cudaimgproc, cudaoptflow and the other cuda modules listed OPENCV_EXTRA_MODULES_PATH was lost, so the contrib modules were skipped
Python 3: numpy a path plus a version, for example 1.23.2 NO means wrappers can not be generated: the wheel has no Python bindings
Python 3: Interpreter the interpreter you deploy with a mismatch binds the wheel to a different Python

All four healthy and the namespace still core-only? The C++ side compiled and the algorithm bindings were dropped downstream of compilation — go straight to the rebuild. A numpy line reading NO is a different defect: the headers were missing at configure time, the same failure family as missing SDK headers in a camera build, and CMake's dependency diagnostics for vision builds help you trace it. A To be built list without cuda entries points at the contrib path — the next section.

Likely causes, ranked

From the tests above, the causes in order of how often they turn up:

  1. A different wheel is imported. Several OpenCV packages or a stale site-packages copy wins the import. Test: cv2.file and pip list, as in test 1.
  2. Wrappers never generated. The numpy headers were missing when CMake configured, which fails with fatal error C1083: Cannot open include file: 'numpy/ndarrayobject.h'. Test: the Python 3 numpy line in the loaded binary's report.
  3. Contrib modules skipped. A mangled module path — C:\opencv_contrib\modules arriving at CMake as C:opencv_contribmodules — ends with No modules has been found, and the cuda modules never enter To be built. Test: the module list in the report; check the build log for that error. The same failure class hides a contrib aruco module in calibration builds — the missing aruco module in a CMake calibration build covers it.
  4. Wrappers built, algorithm bindings absent in that release. The report is healthy, the interpreter still lists eight names. A flag cannot repair a release gap; move forward a tag, as in the rebuild section.

Worked example: the 4.6.0 wheel that exposed eight core names

Take the case this pattern fits exactly. Inputs, each from the deployed interpreter or the wheel's own report:

  • Wheel: opencv-contrib-python 4.6.0+4638ce5, the only OpenCV entry in pip list (installer output).
  • Report, printed by cv2.getBuildInformation() in that interpreter: NVIDIA CUDA YES (ver 11.7), NVIDIA GPU arch 61, cuDNN 8.4.1, numpy 1.23.2, with cudaimgproc and cudaoptflow both under To be built.
  • Namespace: dir(cv2.cuda) offers exactly the eight core types from the symptom section.
  • Pipeline: the code needs two core members (GpuMat, Stream) and two algorithm calls (cv2.cuda.cvtColor, cv2.cuda.createFarnebackOpticalFlow).

The rule: a wheel can run a CUDA pipeline only when the loaded binary exposes both the core members and the algorithm calls your code makes. The build report can clear only the C++ half of that requirement.

The arithmetic: core members 2 needed, 2 exposed — 2 of 2. Algorithm calls 2 needed, 0 exposed — 0 of 2. Total 4 calls required, 2 available, and the two missing ones are precisely the binding-generated algorithm names.

Result: compilation passed — CUDA YES, modules built — while binding export failed, 0 of 2 algorithm calls present.

Decision: 0 of the algorithm names means rebuild for the bindings — correct the flags below or move one tag forward — and leave the driver alone. If instead both algorithm calls existed but failed at run time, the defect would sit in the runtime, device count or driver version, a different repair path.

The rebuild that restores the algorithm bindings

The binding generator needs three things at configure time: CUDA switched on, the contrib modules found, and the numpy headers resolvable under the variable names CMake's own lists read. Set them as CMAKE_ARGS and drive the build:

CMAKE_ARGS=-DWITH_CUDA=ON -DOPENCV_EXTRA_MODULES_PATH=C:/opencv_contrib/modules -DPYTHON3_EXECUTABLE=C:/Python310/python.exe -DPYTHON3_NUMPY_INCLUDE_DIRS=C:/Python310/Lib/site-packages/numpy/core/include -DCUDA_ARCH_BIN=6.1,7.5,8.6
pip wheel . --verbose
  • Forward slashes everywhere, even on Windows. CMake accepts them and no shell eats them. If you must keep backslashes, wrap the whole value in double quotes — the bare form loses the separators and CMake reports C:opencv_contribmodules.
  • Spell the names the way CMakeLists.txt prints them. PYTHON3_NUMPY_INCLUDE_DIRS works; a renamed or shortened argument is silently ignored, and the wrappers come out missing. pip's isolated build may contribute its own numpy — after the build, read the numpy line in the fresh report to see which include folder was used; it may name a path under a temporary pip-build-env folder. A wheel built against one numpy and later run against another fails at import instead — the cv2 version mismatch behind numpy.core.multiarray failures covers that side.
  • Set CUDA_ARCH_BIN to the compute capabilities you deploy. 6.1 in the example covers the Pascal-class card the first build targeted; adding PTX keeps cards beyond the list able to compile kernels on first run.

If the flags were already right and a fresh, healthy report still leaves a core-only namespace, the release itself is the cause: 4.6-era builds showed exactly this gap, and later maintenance tags restored the algorithm bindings. Build one and let the next section's test arbitrate.

Prove the fix, then keep it proving itself

import cv2

print(cv2.getBuildInformation())                        # str: NVIDIA CUDA: YES and the cuda modules listed
print(hasattr(cv2.cuda, "createFarnebackOpticalFlow"))  # bool: True once the algorithm bindings came back
print(cv2.cuda.getCudaEnabledDeviceCount())             # int: at least 1 on the box that runs the code

import numpy as np
gpu = cv2.cuda_GpuMat()               # core type: one frame on the GPU
img = np.zeros((480, 640), np.uint8)  # declared test frame: 640 x 480, 8-bit single channel
gpu.upload(img)
out = cv2.cuda.cvtColor(gpu, cv2.COLOR_GRAY2BGR)   # runs on the GPU
print(out.size())                     # (640, 480)

A False on the hasattr line sends you back to the rebuild; a 0 from the device count means the runtime cannot open a GPU — fix the driver before touching the wheel again. Once the test passes, store the getBuildInformation() output next to the wheel artifact so any mystery build identifies itself later.

Prevention, in the order the failures came:

  • One OpenCV package per environment; rerun the three print lines after every install or upgrade.
  • Match the CUDA toolkit major version to the driver on every runtime box.
  • List every deployed compute capability in CUDA_ARCH_BIN, with PTX for cards you have not bought yet.
  • Commission on the target machine, not only the build machine: run the three lines in the deployed interpreter before the first production frame.

With the bindings live, keep frames on the GPU between operations instead of round-tripping through host memory — CUDA image to NumPy array for OpenCV without round trips shows the transfer side.

When you should not build CUDA at all

Commit to the build only when the workload justifies it. The contrib cuda modules pay off on dense per-pixel work: optical flow, stereo disparity, hundreds of template matches per frame, or several camera streams through one pipeline. A single 1-2 MP stream doing thresholding, blob analysis and measurements usually holds its frame rate on the CPU build — measure your loop before spending a day on toolchains.

If the goal is running a trained network rather than hand-written kernels, you need a different switch set anyway: the DNN module's CUDA backend comes from WITH_CUDA plus OPENCV_DNN_CUDA with a cuDNN install, not from the contrib cuda modules. GPU memory pressure on that path behaves like the training case in YOLO training segmentation fault: GPU memory and CUDA fixes — batch size and buffer count set the ceiling.

The box that runs the wheel

The same three-line check belongs at commissioning, on whatever machine the application ships on. On the shop floor that machine is usually a vision controller: camera ports, light outputs and the compute in one unit, so the interpreter you test is the interpreter production uses. The MV-VC5525-256G70-NN carries 32 GB of memory, PoE camera ports and 8 built-in light channels. The MV-VC3301H-128G66 sits a tier down with 8 GB of memory, 4 built-in light channels and 5+ LAN ports.

Vision controllersHikrobot MV-VC5525-256G70-NN VC5000 Vision Controller, 12th-I5, 32GB+256G SSD, Supported PCIEMV-VC5525-256G70-NN
LAN ports
5+ LAN ports
USB 3 ports
3-4 USB 3 ports
$4,479.00 · quotedView and quote
Vision controllersHikrobot MV-VC3301H-128G66 I3-8100, 8GB+128G SSD, No PoE, PCIe expansion supported, Incl. VM6200Pro licenseMV-VC3301H-128G66
LAN ports
5+ LAN ports
USB 3 ports
3-4 USB 3 ports
$2,419.00View part

Send the camera count, light count and the frameworks you run to the team through the contact page and we will size the box — or start from the configurator and pick the ports yourself. More interpreter and build repairs live on the systems topic page.

Questions

Do the standard pip wheels for OpenCV include CUDA?

No. The wheels published on the public package index are CPU-only; the project ships no CUDA variant, because a CUDA build is tied to specific GPU architectures and toolkit versions. A CUDA-enabled cv2 therefore always comes from a source build, which is also why a locally built version string carries a commit suffix such as +4638ce5 after the release number.

How do I list everything my cv2.cuda namespace exposes?

Run [n for n in dir(cv2.cuda) if not n.startswith('_')] in the interpreter you deploy with and scan the result. A complete build lists algorithm entry points, not just the core types; Python exposes factory functions such as createFarnebackOpticalFlow rather than bare class names, so look for the create prefix when you scan. Anything short of that points back at the bindings.

Can opencv-python and opencv-contrib-python coexist in one environment?

Install exactly one. Both packages ship a module named cv2, so the later install shadows the earlier one and the import path no longer matches the build you configured. Uninstall every OpenCV package, install the single variant your pipeline needs, and rerun the interpreter checks before writing GPU code.

Why does cv2.cuda.getCudaEnabledDeviceCount() return 0 on a machine with a GPU?

The count reflects the runtime, not the build: OpenCV initializes the CUDA driver on first call, and 0 means it found no usable device. The usual causes are a driver older than the toolkit the wheel was built against, or a GPU the process cannot see, for example inside a container without the device passed through. Update the driver first; the wheel itself is rarely at fault once the interpreter test passes.

Do I need to rebuild the wheel for every GPU model in the fleet?

No. CUDA_ARCH_BIN lists the compute capabilities that kernels are compiled for. Give one entry per architecture you deploy — 6.1 for Pascal-class boards, 7.5 for Turing, 8.6 for Ampere — and add PTX so cards newer than the list can compile the kernels on first run. One wheel then serves the fleet; only hardware outside the compiled list forces another build.