Your GigE Vision camera streams happily in the vendor's own tool, yet cv2.VideoCapture(1) fails on Windows 10 and isOpened() returns False. The rtsp:// URL fails too. Neither symptom means a broken install or a wrong IP: VideoCapture can only open devices the operating system lists as capture devices, plus media URLs a device actually serves. A GigE Vision camera is neither, so no index number and no URL string ever reach it. This guide separates the three real causes, gives a ten-minute test for each, and shows the capture paths that do work: the SDK-to-NumPy wrap, an Aravis-based route on Linux, and the narrow case where RTSP is genuine. A worked example then checks whether your stream fits the link you have.
What cv2.VideoCapture actually enumerates
An integer argument selects a position in the operating system's capture-device list: DirectShow devices on Windows, V4L2 devices on Linux. Webcams and capture cards land in that list; a string argument is read as a file path or media URL and handed to the media backends.
A GigE Vision camera fits neither slot. Its stream is negotiated over the GigE Vision and GenICam protocols as UDP packets between two network peers, so Windows and Linux see a network peer, not a capture device. Enumeration returns the laptop webcam at index 0 and the industrial camera at no index at all. That is why isOpened() comes back False before any packet moves.
The test takes a minute: open indexes 0 through 3 in a loop and print what each opens. If index 0 is a webcam and nothing else appears, VideoCapture told you the truth — the camera was never in its list. For what the protocol does promise your software, see what GigE Vision camera compatibility guarantees; for the broader case of a camera one tool finds and another does not, the VideoCapture initialization checklist is the companion read.
Cause 1: your build has no GigE Vision backend
OpenCV carries a fixed set of video-I/O backends, compiled in per build. A stock wheel gives you file, USB and OS capture backends and none of the GenICam-based ones, so auto-detection has nothing to try for a network camera. The backend list does include SDK backends from two Ethernet-camera makers, but each speaks only that maker's own devices; a generic GigE Vision camera still fails.
This is the cause behind most reports of exactly this symptom: one build opens nothing, the same script on a second PC with a different build works immediately, and the code never changed. The build decides, not the script. Auto-detection makes it harder to see, because OpenCV falls back quietly between backends and reports the last failure instead of the real one — the backend fallback walkthrough shows how that masking works.
Fix: rebuild OpenCV with a GenICam layer enabled, which is expensive on Windows toolchains, or leave the build alone and use the two capture paths below, which do not rely on the wheel at all.
Cause 2: the rtsp:// URL points at a service the camera does not run
RTSP is a delivery protocol a device must serve. VideoCapture opens an rtsp:// string only when the camera itself runs an RTSP server that answers at that address and path. That server is not part of the GigE Vision protocol: a GenICam camera negotiates its stream over the control channel and then sends UDP packets straight to your network card.
So the URL fails on every GigE Vision camera without a built-in streaming service, no matter how you rearrange the path. Some smart cameras and code readers do serve RTSP, and for those the URL is the right call. The test: open the camera's own configuration tool and look for a streaming or RTSP page. No such page means no URL will ever open it — stop tuning the string and move to the SDK path.
Cause 3: the stream is lossy, not closed
When the vendor tool shows frames and your script shows blank or grey ones, the API question is settled and the network question starts. Packet loss between camera and network card produces exactly this signature; the packet loss diagnosis for blank frames walks the usual suspects. On small embedded boards the receive buffers are the next suspect — the socket buffer tuning guide for GigE timeouts covers the settings. If frames arrive everywhere but look washed out in every tool, that is exposure, not transport: the grey image at runtime checklist sorts it.
Two quick checks before anything else:
- Ping the camera, then run the vendor's viewer on the same port. If the viewer streams, the hardware path is good and the fault is in code.
- Read the port's negotiated speed. A 1,000 Mbit/s result is the baseline; a 100 Mbit/s negotiation divides the whole budget by ten.
Worked example: does a 6 MP mono stream fit on one GigE link?
The SDK path moves the whole stream, so the link budget decides what you can ask the camera for.
Inputs
- 6,000,000 pixels per frame — from a camera in the 6 MP resolution class.
- 1 byte per pixel — the 8-bit mono format the SDK hands over.
- 25 fps — the target you would set for a conveyor check.
- 1,000 Mbit/s — the line rate of a Gigabit Ethernet port.
- About 950 Mbit/s of usable payload per link — an estimate leaving room for Ethernet, IP and UDP headers on every packet.
The arithmetic
Per frame: 6,000,000 px × 1 B = 6,000,000 B, and 6,000,000 × 8 = 48,000,000 bit, i.e. 48 Mbit. The target then needs 25 × 48 = 1,200 Mbit/s, which is above the roughly 950 Mbit/s one link carries, so the full-resolution stream overflows a single GigE link. Run the formula the other way for the ceiling: 950 ÷ 48 ≈ 19.8 fps.
The decision
At full 6 MP resolution, plan on roughly 19-20 fps per GigE link. Above that threshold, cut the region of interest, lower the frame rate, or move to 10GigE, CoaXPress or USB3 area scan cameras. Pushing past the ceiling does not fail politely — it arrives as the blank frames of cause 3, so the ceiling is also the first number to check when drops appear.
The fix that always works: grab with the SDK, wrap in NumPy
Keep acquisition where the protocol lives and give OpenCV only images. The SDK — the vendor library the camera's own tool already uses — owns the GigE Vision negotiation, packet reassembly and buffer management. Your code takes each finished buffer, maps it onto a NumPy array, and from that line on it is ordinary image processing.
import numpy as np
# Illustrative values for a 6 MP, 8-bit mono camera.
# Read width, height and pixel format from the metadata
# your SDK returns with every buffer.
width, height, bytes_per_pixel = 3000, 2000, 1 # ints
payload = bytes(width * height * bytes_per_pixel) # one grabbed buffer: bytes
img = np.frombuffer(payload, dtype=np.uint8).reshape(height, width)
# The test that proves the wrap:
assert img.shape == (2000, 3000)
assert img.dtype == np.uint8
assert img.size == 6_000_000
If those three asserts pass, img is a real grayscale image — 3,000 × 2,000 pixels, 8 bits each, 6,000,000 bytes total — and thresholding, blob analysis or measurement code runs on it unchanged. Keep the buffer raw between grab and array; the unencoded capture to a NumPy array guide shows what the JPEG detour costs.
The Linux alternative: capture through Aravis
Aravis is an open-source acquisition library for GenICam cameras on Linux that implements both the Gigabit Ethernet and USB3 Vision protocols. Use it two ways: as the acquisition layer in your own program in place of the vendor SDK, or compiled into OpenCV as a video backend so that VideoCapture itself finally opens a GigE Vision camera.
Existing community wrappers bridge the last step, handing Aravis frames over as Mat and IplImage objects through Python bindings. Expect to build from source, which suits Linux benches and headless boxes first; find the project and its wrappers through your package manager or a search for the Aravis project pages. The rule of thumb: one camera with an installed SDK — wrap the SDK; a mixed fleet or no SDK — put Aravis in.
Hardware that keeps the link out of the debug list
After the wrap, the failures that remain are usually link failures, and three choices remove most of them. Put each camera on a dedicated network port rather than the office network, so the stream never queues behind anything. Use a camera data cable built for machine-vision GigE links and for the motion the camera lives in. On the controller side, PoE ports power the camera over the same cable and give one port per camera without a switch hop — worth checking both ends first, per the PoE port check.
The LS-CBL-0199 is a 3 m GigE camera cable with screw locks and a high-flex, drag-chain-rated jacket. The MV-VC5525-256G70-NN vision controller pairs PoE camera ports and 5+ LAN ports with 8 built-in light channels and 32 GB of memory.
- LAN ports
- 5+ LAN ports
- USB 3 ports
- 3-4 USB 3 ports
- PoE
- PoE camera ports
- Light outputs
- 8 built-in channels
Which path to pick
| Your case | Path | Why it works |
|---|---|---|
| One camera, vendor SDK installed, any OS | SDK grab, NumPy wrap | no rebuild; the same wrap serves GigE, USB3 and CoaXPress SDKs |
| Linux box, mixed fleet, no SDK | Aravis, standalone or built into OpenCV | one GenICam layer speaks every GenICam device |
| The camera's own tool shows an RTSP page | cv2.VideoCapture with the rtsp URL | the device serves a media URL VideoCapture can open |
| VideoCapture with an index for a GigE camera | never | the OS lists capture devices, and this camera is not one |
| Frames arrive blank or grey | network triage first | the API is open; the stream is lossy |
If you later move the camera to a CoaXPress or Camera Link card, the wrap does not change — only the acquisition call names a different device. Keep the wrapper thin; it is the portable part of the system.
Checks before the next script
- Read the camera data sheet once for the protocol line: GigE Vision or USB3 Vision there means plan the SDK or Aravis path on day one, not after VideoCapture fails.
- Fix addressing before writing code: one static IP per camera on a subnet the PC shares, or DHCP with a reservation made in the vendor tool.
- Read the port's negotiated speed after plugging in; 100 Mbit/s explains any bandwidth shortfall tenfold.
- Confirm discovery in the vendor tool first. If that tool cannot list the camera, no library will.
- Keep buffers raw end to end, and log a frame counter and timestamp in the grab callback so dropouts show up in minutes, not days.
When the decision table sends you shopping, the camera finder filters by interface and resolution, and the system configurator pairs camera, lens, light and controller in one pass. For a case stranger than the table, the applications team answers through the contact page.
Questions
Can I open the camera by IP in VideoCapture with an http:// or rtsp:// string?
VideoCapture accepts only media URLs a device actually serves, such as RTSP or HTTP motion JPEG, plus OS capture indexes. A GigE Vision camera does not listen as a web service: its stream is negotiated over the GigE Vision control protocol and delivered as UDP. Any URL built from the camera IP therefore returns False from isOpened(), unless the firmware explicitly ships a streaming service. Use the SDK or an Aravis-based path instead.
Why did the same VideoCapture code work on a colleague's PC?
Because builds differ, not because the code does. A build compiled with a GenICam-based backend can open GigE Vision cameras directly through VideoCapture; a stock wheel usually cannot. In the case behind this guide, a build near 3.4.1 on a second PC opened the camera while a build near 4.1 on the first did not. Check each machine's video-I/O build report before you port working code between PCs.
Does this change for a USB3 Vision camera?
The cause and the fix are the same. USB3 Vision is also negotiated by its own protocol, so the operating system still lists no capture device at any index. Aravis implements the USB3 protocol alongside the Gigabit Ethernet one, and the SDK-to-NumPy wrap applies unchanged. Only the link budget differs: a USB 3 port carries several times the payload of a GigE link.
How do I display the NumPy frame while the SDK keeps streaming?
Treat the wrapped array as any grayscale image and hand it to your OpenCV display or processing call; the SDK callback only fills the buffer. Convert color formats once per frame, at the SDK level if the SDK offers the conversion, otherwise in the array step. Keep grabbing in its own thread so a slow display never stalls the stream, and drop frames rather than queue them when processing falls behind.
Do I need jumbo frames or a dedicated network card for the SDK path?
Neither touches the API question, but both help the link. One port per camera keeps the stream off shared queues; a switch works only while the total of all streams fits the roughly 950 Mbit/s payload of each link they share. A network card with large-frame support lowers interrupt load on big streams; the setting lives in the adapter's advanced driver properties, and the vendor viewer shows whether drops change.

