Seek ThermalThermal sensing for mission critical applications
Concept

Key Concepts

Core abstractions and design patterns


Overview

seekcamera-python is built around a small set of core abstractions that work together to let you discover cameras, capture thermal frames, and react to camera lifecycle events. Understanding how the camera manager, camera, frame, and event system relate to each other will help you write correct, responsive applications and avoid common pitfalls when working with one or more Seek Thermal OEM cores.


Content

The camera manager

SeekCameraManager is the entry point for every seekcamera-python application. It owns the connection to the Seek Thermal SDK, handles device discovery, and dispatches lifecycle events to your code. You always create a manager first, and everything else flows from it.

The manager accepts an IO type argument that tells it which transport protocol to watch:

  • SeekCameraIOType.USB — for cameras connected over USB
  • SeekCameraIOType.SPI — for cameras connected over SPI

Multiple cameras can be managed by a single SeekCameraManager instance. The library handles the bookkeeping; your callback receives a distinct SeekCamera object for each device.


Event-driven lifecycle

seekamera-python uses an asynchronous, event-driven model. Rather than polling for camera state, you register a callback with the manager. The SDK calls that callback whenever the state of any connected camera changes. This keeps your application responsive and avoids busy-waiting.

Each callback invocation receives a SeekCameraManagerEvent that describes what happened:

EventMeaning
CONNECTA camera connected and is paired — ready to stream
DISCONNECTA previously connected camera has been removed
ERRORA connected camera has reported an error
READY_TO_PAIRA new, unpaired camera has connected

Your callback signature receives the SeekCamera instance, the event type, the error status (if any), and an optional user-data object you pass when registering the callback. This lets you share application state with the callback without relying on global variables.


Camera objects

SeekCamera represents a single physical camera core. You never construct one directly — the manager creates and passes camera objects to your event callback. A camera object exposes:

  • Capture control — start and stop frame streaming
  • Image pipeline settings — color palette, AGC mode, shutter mode, temperature units, filters, and pipeline mode
  • Device identity — firmware version, IO properties (bus number, port numbers, or chip-select)
  • App resource regions — three reserved memory regions on the device for customer data

All camera settings are applied per-device, so when you work with multiple cameras you configure each SeekCamera object independently.

IO properties

Each camera carries an SeekCameraIOProperties object that describes its physical connection. You can inspect camera.io_properties.type to determine whether a camera is USB or SPI, then read the relevant sub-object (usb or spi) for bus and port information. This is useful when you need to distinguish between cameras of the same model.


Frame capture and the frame callback

Once a camera is connected, you start streaming by calling the capture session method on the SeekCamera object and providing a frame callback. The SDK calls this callback every time a new frame is available.

Each frame callback invocation receives a SeekCameraFrame object. You lock the frame to access its data safely, then request the specific format you need.

Frame formats

SeekCameraFrameFormat controls what kind of data a frame contains. Common formats include colorized ARGB images (ready for display) and thermography data (floating-point temperatures per pixel). You specify the format(s) you want when you start the capture session, and the SDK processes only the requested formats — avoiding unnecessary computation.

SeekFrame and numpy integration

Calling the appropriate accessor on a locked SeekCameraFrame returns a SeekFrame object. Its .data property exposes the frame pixel data as a numpy array, which makes it straightforward to pass frames to libraries like OpenCV, run numerical analysis, or write values to disk. Frame metadata (width, height, timestamps, etc.) is available via SeekCameraFrameHeader.


Image processing pipeline

The SDK processes raw sensor data through a configurable pipeline before delivering frames to your callback. Key pipeline concepts:

  • Pipeline mode (SeekCameraPipelineMode) — selects the overall processing profile: LITE, LEGACY, or SEEKVISION.
  • AGC (Automated Gain Control) — maps raw thermal data to the 8-bit display range. SeekCameraAGCMode selects between linear min/max (LINEAR) and histogram equalization (HISTEQ). SeekCameraLinearAGCLockMode lets you fix the min, max, or both bounds manually.
  • Color palette (SeekCameraColorPalette) — controls colorization of display-ready frames. Built-in palettes include WHITE_HOT, BLACK_HOT, IRON, SPECTRA, and others. You can also define custom palettes with SeekCameraColorPaletteData, which holds 256 BGRA entries going from coldest to hottest.
  • Filters (SeekCameraFilter) — optional per-frame processing steps such as gradient correction, flat scene correction, and sharpening. Each filter can be independently enabled or disabled via SeekCameraFilterState.
  • Shutter mode (SeekCameraShutterMode) — applicable to Mosaic cores only; controls whether calibration shuttering is automatic or manually triggered.
  • Temperature unit (SeekCameraTemperatureUnit) — selects Celsius, Fahrenheit, or Kelvin for thermography frames.

Error handling

The library represents errors as Python exceptions that all inherit from SeekCameraError. Each error condition has a specific subclass (for example, SeekCameraDeviceCommunicationError, SeekCameraNotPairedError, SeekCameraTimeoutError), so you can handle them selectively with standard try/except blocks. Errors delivered through the event callback carry a status code you can inspect to determine the cause.


Using multiple cameras

Because the event-driven model delivers a distinct SeekCamera object per device, supporting multiple cameras requires no special setup. A single SeekCameraManager instance and a single callback function handle all connected devices. Your callback receives the specific camera that triggered the event, so you can maintain per-camera state in a dictionary or similar structure, keyed by camera identity.


Context manager support

SeekCameraManager supports Python's context manager protocol (with statement), which ensures the SDK is properly shut down and resources are released even if an exception occurs. Using it as a context manager is strongly recommended over manual lifecycle management.


Examples

Minimal event-driven skeleton

This example shows the relationship between the manager, the event callback, and a camera object. It prints each lifecycle event as it arrives.

from seekcamera import SeekCameraManager, SeekCameraIOType, SeekCameraManagerEvent

def on_event(camera, event_type, error, user_data):
    if event_type == SeekCameraManagerEvent.CONNECT:
        print(f"Camera connected: {camera}")
    elif event_type == SeekCameraManagerEvent.DISCONNECT:
        print(f"Camera disconnected: {camera}")
    elif event_type == SeekCameraManagerEvent.ERROR:
        print(f"Camera error: {error}")
    elif event_type == SeekCameraManagerEvent.READY_TO_PAIR:
        print(f"Camera ready to pair: {camera}")

with SeekCameraManager(SeekCameraIOType.USB) as manager:
    manager.register_event_callback(on_event)
    input("Press Enter to exit...\n")

Expected output (with one USB camera attached):

Camera connected: <SeekCamera ...>
Press Enter to exit...

Capturing frames and accessing pixel data

Once a camera connects, start a capture session and supply a frame callback. This example requests a thermography frame and prints the mean temperature across the scene.

from seekcamera import (
    SeekCameraManager,
    SeekCameraIOType,
    SeekCameraManagerEvent,
    SeekCameraFrameFormat,
)

def on_frame(camera, camera_frame, user_data):
    with camera_frame as frame:
        thermography = frame.get_thermography_float()
        mean_temp = thermography.data.mean()
        print(f"Mean scene temperature: {mean_temp:.2f} °C")

def on_event(camera, event_type, error, user_data):
    if event_type == SeekCameraManagerEvent.CONNECT:
        camera.register_frame_available_callback(on_frame)
        camera.capture_session_start(SeekCameraFrameFormat.THERMOGRAPHY_FLOAT)
    elif event_type == SeekCameraManagerEvent.DISCONNECT:
        camera.capture_session_stop()

with SeekCameraManager(SeekCameraIOType.USB) as manager:
    manager.register_event_callback(on_event)
    input("Press Enter to exit...\n")

Expected output (values depend on scene temperature):

Mean scene temperature: 24.73 °C
Mean scene temperature: 24.71 °C
...

Configuring the image pipeline

This snippet shows how to set a color palette and AGC mode on a connected camera before starting capture. Apply settings inside the CONNECT handler so they take effect before the first frame arrives.

from seekcamera import (
    SeekCameraManagerEvent,
    SeekCameraColorPalette,
    SeekCameraAGCMode,
    SeekCameraFrameFormat,
)

def on_event(camera, event_type, error, user_data):
    if event_type == SeekCameraManagerEvent.CONNECT:
        camera.color_palette = SeekCameraColorPalette.TYRIAN
        camera.agc_mode = SeekCameraAGCMode.HISTEQ
        camera.register_frame_available_callback(on_frame)
        camera.capture_session_start(SeekCameraFrameFormat.COLOR_ARGB8888)

Distinguishing multiple cameras by IO properties

When more than one camera is attached, use IO properties to tell them apart.

from seekcamera import SeekCameraIOType, SeekCameraManagerEvent

def on_event(camera, event_type, error, user_data):
    if event_type == SeekCameraManagerEvent.CONNECT:
        props = camera.io_properties
        if props.type == SeekCameraIOType.USB:
            bus = props.usb.bus_number
            ports = [p for p in props.usb.port_numbers if p > 0]
            print(f"USB camera on bus {bus}, ports {ports}")

Expected output (with two cameras on different buses):

USB camera on bus 1, ports [2]
USB camera on bus 3, ports [1, 4]

Handling errors selectively

from seekcamera import (
    SeekCameraManagerEvent,
    SeekCameraDeviceCommunicationError,
    SeekCameraTimeoutError,
)

def on_event(camera, event_type, error, user_data):
    if event_type == SeekCameraManagerEvent.ERROR:
        try:
            raise error
        except SeekCameraDeviceCommunicationError:
            print("Communication lost — check the physical connection.")
        except SeekCameraTimeoutError:
            print("Operation timed out — the camera may be busy.")
        except Exception as e:
            print(f"Unexpected error: {e}")

Related concepts
  • Installation — Set up the Seek Thermal SDK and install seekcamera-python before working with these abstractions.
  • Sample applications — The seekcamera-opencv and seekcamera-simple examples demonstrate a complete, working integration of the manager, event callback, and frame callback patterns described here.
  • Error reference — Full list of SeekCameraError subclasses and the conditions that raise them.
  • Frame formats reference — Details on every SeekCameraFrameFormat value and the numpy array shape and dtype each one produces.
  • Working with multiple cameras — Patterns for managing per-camera state and coordinating capture sessions across several devices simultaneously.