System designExplainer

Thermal camera not detected by your vision SDK

A thermal camera is not detected by a vision SDK when it serves RTSP instead of GigE Vision. The fix: OpenCV VideoCapture, or a vision-standard LWIR camera.

LumaSpec Vision11 min read Share on LinkedIn

On this page 10 sections
  1. 01The decision, up front
  2. 02How a vision SDK finds cameras
  3. 03Path one: the stream straight into OpenCV
  4. 04What the compressed stream costs you
  5. 05Thermal cameras a vision SDK does see
  6. 06Worked example: a person at 50 m through a 640 x 512 LWIR camera
  7. 07Choosing: keep the stream or change the camera
  8. 08When zero cameras means something else
  9. 09Checks before you commit
  10. 10Questions

You installed a machine vision SDK, cabled a marine pan-and-tilt thermal camera into the network, and ran the enumeration example: zero cameras. The camera's own web page works and ping answers, so the hardware is fine — and that is exactly the trap. Vision SDKs enumerate one specific class of device, and a streaming thermal camera built for maritime or surveillance duty is not that class. This explainer covers who hits this wall, the two-minute test that proves which side you are on, and both working paths: pull the RTSP or MJPEG stream straight into OpenCV, or replace the camera with a thermal camera built on a vision interface, with the coverage, pixel and bandwidth arithmetic for each.

The decision, up front

Your camera is not broken and your SDK is not misinstalled. A machine vision SDK lists devices that answer GigE Vision discovery on the network or enumerate as USB3 Vision devices on the bus. A network thermal camera of the pan-and-tilt, marine or security type serves RTSP or MJPEG video over HTTP and is driven from a web page or through ONVIF. It never answers GigE Vision discovery, so the camera list stays empty no matter how often you refresh, reinstall or re-cable.

Read the interface line on the camera's data sheet and the path is decided:

  • GigE Vision or USB3 Vision listed — the camera should appear. Your host is the problem: transport layer, network card or firewall. Fix that side.
  • Only RTSP, MJPEG or ONVIF listed — stop trying to enumerate. Open the stream URL in OpenCV VideoCapture, or swap in a thermal camera built on a vision interface.

No driver, patch or cable changes which column that camera sits in. The divide is at the discovery layer, below the image, and it is permanent for that unit.

How a vision SDK finds cameras

Every machine vision SDK builds its camera list from transport layers, one per interface. For GigE Vision the transport layer sends a discovery broadcast over UDP on the local subnet and every compliant camera answers with its identity; for USB3 Vision the device enumerates on the USB bus like any class device. After discovery the SDK reads the camera's GenICam feature description — the tree that exposes exposure, gain, trigger and frame metadata as readable and writable nodes — and acquisition then flows as raw pixel packets carrying frame numbers and timestamps.

A streaming thermal camera ends its network stack at an RTSP server, an HTTP snapshot page and an ONVIF control port. Ping proves the IP layer. The maker's own app streaming perfectly proves the maker's protocol. Neither produces the discovery answer the SDK is listening for, which is the only thing that would put the camera on the list.

Two failures look identical from the outside — zero cameras — and the split matters:

  • The camera is GigE Vision but the transport layer is missing or blocked on your host. That is the common failure with real vision cameras, and ping works, zero cameras: GigE transport layer not loaded walks the fix.
  • The camera is not a vision device at all. No host-side change can fix this; change the capture path instead.

Path one: the stream straight into OpenCV

OpenCV's cv2.VideoCapture accepts URLs, not just device indexes, and its FFmpeg or GStreamer backend handles RTSP and MJPEG over HTTP natively. Your machine learning loop barely changes.

import cv2  # cv2: documented OpenCV module

stream_url = "rtsp://192.168.0.10:554/live"  # illustrative; take the real URL from the camera's web page
cap = cv2.VideoCapture(stream_url)            # cv2.VideoCapture: documented API
ok, frame = cap.read()                        # ok: bool, False on failure; frame: array or None
print("opened:", cap.isOpened(), "shape:", None if frame is None else frame.shape)

The print line is the test: opened: True with a shape such as (512, 640, 3) proves the pipe end to end before any model code runs. If the open fails, try the MJPEG URL the same web page usually lists; it is the same call with an http:// address.

Three behaviors decide whether the stream path is good enough:

  1. Latency. A decoded H.264 path typically lands 100-500 ms behind the scene because encoder and decoder both buffer; MJPEG frames decode independently and usually sit at the low end of that band. If your loop steers anything, measure glass-to-glass with a flashing LED before trusting it.
  2. Queuing. VideoCapture buffers internally, so a consumer slower than the frame rate falls behind real time. Read in a worker thread and hand the model the newest frame only.
  3. Metadata. Stream containers often report zero or stale frame rates. Video FPS returns zero in OpenCV shows how to measure instead of trusting the header.

If the task is code reading rather than detection, decoding barcodes from a live RTSP or MJPEG stream uses this same capture pattern with preprocessing on top. Note the mirror trap, too: OpenCV VideoCapture cannot open a GigE Vision camera. The two camera families sit on opposite sides of this divide, each with its own capture path.

What the compressed stream costs you

RTSP video exists to be watchable, not measurable, and the difference lands directly on your model.

  • Bit depth. The stream carries 8-bit display pixels. LWIR cores carry 14-16 bit radiometric counts internally; none of that survives the encoder. The camera's own gain and histogram mapping set the contrast, and they shift scene by scene, so a model trained on one mapping drifts when the camera re-balances.
  • Temperature. Gray level to degrees is not invertible from display video: many temperatures collapse onto one 8-bit value, often through a colormap. If the pipeline needs real temperatures, work from raw counts — raw thermal counts to temperature: calibration essentials is that path — and to store full depth, export high bitdepth grayscale images from thermal cameras instead of saving decoded video.
  • Control. No GenICam tree means no trigger, no hardware sync between cameras and no deterministic frame identifiers.

The scale of the loss is arithmetic: a 640-class H.264 substream at a typical 4 Mbit/s rides the wire at roughly one sixty-fifth of the same sensor's raw radiometric rate, about 262 Mbit/s at 16 bits and 50 Hz, computed below. Compression is what lets a maritime camera serve several viewers from a boat network, and it is also why that stream can never be a measurement instrument.

Thermal cameras a vision SDK does see

When the answer is replacement, the dividing line is the same: look for GigE Vision or USB3 Vision on the interface line. In the infrared cameras category, 26 of 58 models are GigE, 11 are USB3 and 6 are Camera Link — every one of them enumerates in a vision SDK through the matching transport layer. The archetype for a wide, passive LWIR feed:

Infrared cameras640 x 512 thermal camera, 8-14 μm, 50 Hz, GigE, FOV 88.5° × 73.2°, 9-24 V DC (LS-IRC-0044)LS-IRC-0044
Lens mount
C-mount
Interface
GigE
Resolution
Up to 3 MP
Spectrum
LWIR
$5,885.00 · quotedView and quote

The LS-IRC-0044 prints 640 x 512 resolution, 8-14 μm, 50 Hz, GigE. It reads radiated heat directly: no illuminator, nothing leaves the camera, no eye-safety burden on deck. The narrower and portable options, side by side:

Infrared camerasHikrobot MV-CI003-GL-N25 0.3 MP LWIR Camera, GigE, EFL 25mmMV-CI003-GL-N25
Lens mount
M34x0.75
Interface
GigE
Price on requestView and quote
Infrared camerasLWIR thermal camera module, USB3, 640×512 resolution (LS-IRC-0016)LS-IRC-0016
Interface
USB3
$3,999.00 · quotedView and quote
Infrared camerasThermal imaging camera, 0.5 MP, GigE (LS-IRC-0026)LS-IRC-0026
Interface
GigE
Resolution
Up to 3 MP
$3,999.00 · quotedView and quote

The MV-CI003-GL-N25 prints EFL 25 mm for narrow-field work. The LS-IRC-0016 is a 640×512 USB3 module for embedded hosts. The LS-IRC-0026 is a 0.5 MP GigE unit, and the LS-IRC-0007 is the gas-leak imager: MWIR, GigE, 50 mm lens.

One caution at the other end of the band: SWIR cameras such as the LS-IRC-0029 see reflected light, not heat, and need illumination like any visible camera. LWIR is the passive choice for people, engines and heat signatures.

Worked example: a person at 50 m through a 640 x 512 LWIR camera

Inputs. The camera is the LS-IRC-0044. Its data prints 640 x 512 resolution, FOV 88.5° × 73.2° and 50 Hz. The scenario is a person 1.8 m tall, broadside, at 50 m — a planning distance for small-craft approach, chosen here, not a spec. Radiometric depth is 2 bytes per pixel, the budget for the 14-16 bit counts LWIR cores carry. The link budget is about 100 MB/s of usable payload per 1 Gbit/s port with jumbo frames, the standard GigE Vision planning figure.

Rule. Half the viewed width at range equals range times the tangent of half the FOV; ground sample distance is coverage divided by pixels; pixels on target is target height divided by sample distance; raw rate is width times height times bytes per pixel times frame rate.

half_w = 50 m × tan(88.5° / 2) = 50 × tan(44.25°) = 50 × 0.974 = 48.7 m width = 2 × 48.7 m = 97.4 m height = 2 × 50 m × tan(73.2° / 2) = 100 × tan(36.6°) = 100 × 0.743 = 74.3 m sample = 97.4 m ÷ 640 px = 0.152 m/px person = 1.8 m ÷ 0.152 m/px = 11.8 px ≈ 12 px tall rate = 640 × 512 px × 2 B × 50 Hz = 32,768,000 B/s ≈ 32.8 MB/s ≈ 262 Mbit/s

Result. At 50 m the frame covers 97.4 m × 74.3 m of water and samples every 0.152 m, so a 1.8 m person stands about 12 pixels tall. The raw radiometric stream needs 32.8 MB/s, 33 percent of one GigE port's planning payload.

Decision. Detection of a person-sized target holds from about 4 pixels on the short axis — the Johnson-criterion floor — so 12 pixels detects with margin at 50 m. Recognition wants about 16 pixels, which this field of view delivers only inside 37 m: 1.8 m ÷ 16 px = 0.113 m/px, × 640 px = 72 m of coverage, ÷ (2 × tan 44.25°) = 37 m of range. If the task says classify at 50 m, this wide lens is the wrong part — take the narrow-EFL model and re-run these three lines with its sensor width before ordering. On the wire, one camera is trivial and two (65.6 MB/s combined) still fit a jumbo-frame port; past two, add a port, and GigE camera network planning: switch ports and bandwidth covers the layout.

Run the same trade-off interactively:

Camera resolution for the smallest feature
Units
Pixels needed
–
Sensor size
– MP
Smallest sensor that fits
–
Pixel on the part
– mm
Pixels across the feature, that sensor
–

Pixels needed = field / feature × pixels per feature on each axis (field incl. margin). The lens must resolve the pixels too: Nyquist = 1000 / (2 × pixel µm) lp/mm.

Find cameras with enough pixels Open the full calculator

Choosing: keep the stream or change the camera

RTSP/MJPEG stream GigE Vision thermal camera
Appears in SDK enumeration Never Yes, via the transport layer
Pixel data 8-bit display video 14-16 bit radiometric counts
Glass-to-glass latency 100-500 ms typical for H.264 About one frame period, 20 ms at 50 Hz
Camera control Web page or ONVIF GenICam tree: trigger, sync, gain mode
Wire load per camera A few Mbit/s 32.8 MB/s at 640 x 512, 16 bit, 50 Hz
Best for Detection ML on watchable video Measurement, trigger, multi-camera rigs

The decision by case:

  • You already own the pan-and-tilt unit and the model detects appearances. Keep it. Stream into VideoCapture and ship.
  • The model estimates temperature, or you need deterministic timing across cameras. Replace it with a GigE Vision LWIR camera; the compressed stream can never carry that.
  • You need both. Keep the streamer for the wide situational view and add one GigE Vision camera on the targets that matter. They share a switch without conflict.

When zero cameras means something else

  • The camera is a real vision camera and still absent. Then the host is the suspect: transport layer, firewall on the discovery broadcast, or the network card. A purpose-built card such as the LS-FGB-0004 rules out the marginal-NIC class of trouble.
  • The "thermal camera" is a USB webcam. Handheld and board-level thermal modules often enumerate as UVC webcams. A vision SDK will not list those either; OpenCV opens them by device index, and UVC camera not detected by software: choose the right capture path sorts the routes.
  • Only a snapshot URL exists. Some units expose an HTTP snapshot endpoint and no stream. Poll it from your code and wrap each image for the model; the 8-bit limit still applies, and your poll interval becomes the frame rate.

Checks before you commit

  1. Read the interface line on the camera's data sheet. The words GigE Vision or USB3 Vision pick one path; RTSP or ONVIF alone picks the other.
  2. Paste the stream URL into a media player before writing code. If it will not play there, it will not play in OpenCV.
  3. Measure glass-to-glass latency with a flashing LED against what your loop tolerates.
  4. If temperature appears anywhere in the model, confirm the camera outputs radiometric data, not only video.
  5. Run the coverage arithmetic at your worst-case range before choosing a lens, not after.
  6. Give a GigE Vision camera its own switch port and network card; discovery broadcasts and heavy pixel traffic do not improve each other.

For the replacement path, start at the camera finder and build the matched chain here:

Build the whole station

The configurator matches a camera, lens, light, light controller and cables to each other, step by step, and lists only parts that fit what you already picked.

Start with the camera

If the unit you must integrate is still unclear, bring the interface page to our contact page and we will call the column it belongs in.

Questions

Can an SDK update ever make a streaming thermal camera enumerate?

No. Enumeration rides GigE Vision discovery or USB3 Vision device enumeration, and a streaming camera answers neither. A few vision SDKs ship a bridge that ingests a network stream into their pipeline, but even then there is no GenICam feature tree behind it, so there is no trigger or exposure control. If your SDK has no bridge, OpenCV VideoCapture on the URL is the supported path and leaves your model code unchanged.

Ping works but the SDK lists zero cameras. Interface or host?

Ping only proves the IP layer. If the data sheet says GigE Vision, suspect the host first: the SDK's GigE transport layer missing or blocked stops discovery, and that is fixable. If the sheet lists only RTSP, ONVIF and a web UI, the camera will never enumerate and the stream path is the answer. Open the stream URL in a media player to confirm which case you are in.

How do I open the RTSP feed in OpenCV, and is MJPEG better?

Pass the rtsp:// URL straight to cv2.VideoCapture and test with isOpened() plus one read(). MJPEG over HTTP usually lands with less delay than H.264 because every frame decodes independently, at several times the bitrate. For detection loops that must work on the newest frame, prefer the MJPEG URL when the camera offers one.

Can I recover temperature values from the compressed video?

No. The stream carries 8-bit display pixels after the camera's own gain and histogram mapping, often through a colormap, and many temperatures collapse onto one gray level, so the conversion is not invertible. Measurement needs the radiometric stream of a GigE Vision LWIR camera, calibrated from raw counts to temperature.

Which thermal cameras will a vision SDK see directly?

In the infrared category, 26 of 58 cameras are GigE and 11 are USB3, both GenICam-controlled, and 6 more are Camera Link. An example is the LS-IRC-0044: 640 x 512, 8-14 μm, 50 Hz, GigE. Read the interface line on the data sheet before buying; RTSP alone means the stream path, whatever the brand.