IDS: Stream Live Video
SUMMARY
Stream continuous color frames at a controlled frame rate, JPEG-encode each frame to reduce bandwidth, and visualize the live feed with Rerun.
Example
Code
"""
Connect to an IDS camera, get/set parameters, and stream live video.
Run from a terminal to avoid issues with Rerun's spawn mode.
"""
import time
from loguru import logger
import cv2
import rerun as rr
from medulla.cameras import ids
def main():
camera = ids.IDS(
name="my_ids_camera",
serial_number="4108909352",
load_factory_defaults=False
)
try:
rr.init("IDS_Example", spawn=True)
camera.connect()
logger.info(f"AcquisitionFrameRate: {camera.get_parameter('AcquisitionFrameRate')}")
logger.info(f"ExposureTime: {camera.get_parameter('ExposureTime')}")
logger.info(f"DeviceLinkThroughputLimit: {camera.get_parameter('DeviceLinkThroughputLimit')}")
camera.set_parameter('ExposureTime', 35000.0)
camera.set_parameter('AcquisitionFrameRate', 14.0)
end_time = time.time() + 10
while time.time() < end_time:
image = camera.capture_video_color_frame()
if image is not None:
_, encoded = cv2.imencode(
'.jpg',
image,
[cv2.IMWRITE_JPEG_QUALITY, 80]
)
rr.log(
"Continuous_Image_Capture",
rr.EncodedImage(contents=encoded, media_type="image/jpeg")
)
except Exception as e:
logger.error(f"Unable to run video capture. {type(e).__name__}: {e}")
finally:
camera.disconnect()
if __name__ == "__main__":
main()Explanation
Now, let’s break down the code piece by piece.
The camera object is created the same way as in the single-image example — with a name, serial_number, and load_factory_defaults=False to preserve any settings configured in IDS Peak Cockpit.
camera = ids.IDS(
name="my_ids_camera",
serial_number="4108909352",
load_factory_defaults=False
)After opening the Rerun viewer and connecting, all three parameters supported by the IDS class are read and logged before any changes are made. This gives a clear picture of the camera's starting state and makes it easier to diagnose unexpected behavior after parameters are modified.
logger.info(f"AcquisitionFrameRate: {camera.get_parameter('AcquisitionFrameRate')}")
logger.info(f"ExposureTime: {camera.get_parameter('ExposureTime')}")
logger.info(f"DeviceLinkThroughputLimit: {camera.get_parameter('DeviceLinkThroughputLimit')}")Exposure is set to 35 ms and frame rate to 14 fps before streaming begins.
camera.set_parameter('ExposureTime', 35000.0)
camera.set_parameter('AcquisitionFrameRate', 14.0)The streaming loop runs for 10 seconds using a wall-clock deadline rather than a fixed frame counter, so the actual number of frames captured depends on the configured frame rate. Each call to capture_video_color_frame switches the camera to Continuous acquisition mode on the first call — keeping the sensor running between calls — and returns one frame as a NumPy array. Each frame is then JPEG-encoded at quality 80 with cv2.imencode to reduce the data volume before being logged to Rerun as an EncodedImage, which accepts the compressed bytes directly without an intermediate decode step.
end_time = time.time() + 10
while time.time() < end_time:
image = camera.capture_video_color_frame()
if image is not None:
_, encoded = cv2.imencode(
'.jpg',
image,
[cv2.IMWRITE_JPEG_QUALITY, 80]
)
rr.log(
"Continuous_Image_Capture",
rr.EncodedImage(contents=encoded, media_type="image/jpeg")
)The finally block disconnects the camera exactly as in the single-image example, stopping acquisition and releasing all resources.
finally:
camera.disconnect()Run
python capture_video_example.pyA Rerun viewer opens automatically. Frames stream under Continuous_Image_Capture for 10 seconds, then the camera disconnects cleanly.

