Python OpenCV VideoCapture won't read image from IMX477 HQ Camera on Pi CM4 Bullseye

Hi all, I’m stuck with a 12.3MP IR-CUT HQ Camera with 6mm CS Lens for Raspberry Pi (IMX477) on a Pi CM4 running Bullseye 32-bit. I’ve honestly never gotten it to work properly. My goal is to grab frames with cv2.VideoCapture in Python (OpenCV), but OpenCV just won’t read an image from it. I followed the hardware setup guide on the Arducam docs page for the 12MP IMX477 camera, so the hardware side should be fine. Anyone know what I’m doing wrong here?

Welcome! First thing worth clarifying: on the native Raspberry Pi camera stack (libcamera) in Bullseye, OpenCV can’t read the camera directly. cv2.VideoCapture is built around V4L2/USB-style capture devices, and the IMX477 via libcamera isn’t exposed that way. So VideoCapture will typically just fail or return nothing.

Can you tell me a bit more:

  1. Does the camera show up with libcamera-hello or libcamera-still?
  2. Which VideoCapture backends have you tried (e.g. cv2.CAP_V4L2, cv2.CAP_GSTREAMER)?
  3. Are you running headless over SSH?

Most people solve this by capturing with picamera2 and then handing the frames to OpenCV for processing. There’s a good reference example here: https://github.com/raspberrypi/picamera2/blob/main/examples/opencv_face_detect.py

Thanks, that helps explain a lot. To answer:

  1. Yes, I can get a still image out of it with libcamera-still. So the camera itself works.
  2. I also managed to stream the feed over the network using RTSP-Simple-Server, and that works too.
  3. I’ve tried several VideoCapture backends in OpenCV, none of them read an image.

On top of that I’ve enabled and disabled legacy support in raspi-config back and forth, thinking maybe it needed the old stack, but that didn’t fix it either. The only way I got anything into OpenCV was by going through libcamera and GStreamer. So I’m pretty confused why the plain VideoCapture approach won’t work.

That all lines up with what I expected. The key point: on this setup OpenCV can’t read the camera data directly. The IMX477 on the Pi CM4 with Bullseye 32-bit is accessed through libcamera, and OpenCV has no native libcamera backend. That’s why libcamera-still and your RTSP stream work fine, but cv2.VideoCapture(0) gets you nothing.

So toggling legacy support in raspi-config won’t help here — the camera is on the new libcamera stack, not the old MMAL/V4L2 one. And cycling through VideoCapture backends won’t help either, since none of them talk to libcamera.

The correct approach is to capture frames with picamera2, then pass those frames into OpenCV as numpy arrays. That GStreamer route you got working is basically doing the same thing with more moving parts.

Have you tried picamera2 at all yet?

Not really, I assumed OpenCV could just open the camera like a normal webcam. Let me make sure I understand: I capture with picamera2, and then each frame is a numpy array I can feed to OpenCV functions? Do I still use cv2.VideoCapture anywhere in that flow, or does picamera2 replace it entirely?

Exactly — picamera2 replaces the capture part. You don’t use cv2.VideoCapture at all for this camera. picamera2 captures the frame as a numpy array and you hand that to OpenCV for whatever processing you want (color conversion, detection, writing out, etc.).

Here’s the reference example that shows both combined, which is basically what you want:
https://github.com/raspberrypi/picamera2/blob/main/examples/opencv_face_detect.py

Roughly the flow in that example: configure a still/video config with picamera2, start it, then loop on capture_array() and process each array with OpenCV. It even handles the BGR/RGB ordering for you, which is a common gotcha.

If your goal is just to read frames and process them, this is the path. Give it a try and let me know if you hit an error on import picamera2 or anything like that — that part is usually just an apt install python3-picamera2 away if it isn’t already present on your Bullseye image.

Got it, that makes much more sense now. So the short version is: OpenCV can’t read this camera directly, use picamera2 to grab the frames and then do the OpenCV work on the arrays. I’ll wire that up with the face-detect example as a template and see how it goes. Thanks for clearing up why the RTSP/GStreamer detour was even necessary.

Right on, that’s the conclusion. To summarize for anyone finding this thread later:

  • Setup: IMX477 12.3MP IR-CUT HQ camera (6mm CS lens) on a Pi CM4, Bullseye 32-bit.
  • Symptom: libcamera-still works and RTSP-Simple-Server streaming works, but cv2.VideoCapture never returns a frame, regardless of backend.
  • Root cause: OpenCV cannot read the native Raspberry Pi camera / libcamera stack directly. Toggling legacy support in raspi-config and swapping VideoCapture backends won’t change that.
  • Solution: capture frames with picamera2 and pass the resulting numpy arrays to OpenCV for processing. Working example: https://github.com/raspberrypi/picamera2/blob/main/examples/opencv_face_detect.py

If you hit any snags getting picamera2 running, just post back with the traceback.