Camera helpers

Every camera driver built on CameraTemplate can offer five properties. Each reads and writes the active configuration. Exposure time, binning and frame rate have the same units for all drivers. The ROI uses the pixels of the vendor API and the gain the native unit of the driver, see ROI units and Gain and frame rate.

Property

Type

Unit

exposure_time

float

seconds

roi_coordinates

(x_offset, y_offset, width, height)

pixels of the vendor API, see ROI units

binning

(horizontal, vertical)

pixel factors

gain

float

driver specific, see Gain and frame rate

frame_rate

float or None

Hz, None removes the limit

The ROI and binning getters return a tuple or None, also if the stored configuration holds a list (for example from a JSON file).

Reading

A getter returns None if the value is not set in the active configuration or if the driver does not support the feature. supported_features() tells the cases apart. It returns the sorted names of the properties the driver supports.

Some getters return None for stored values they cannot interpret, for example a DCAM binning mode that is not a symmetric factor of 1, 2 or 4.

get_available_options() is the second introspection call. It lists the raw device and configuration keys, which are the keys to use in a configuration dict. supported_features() lists which helper properties the driver implements. On GenICam drivers the helpers write keys that get_available_options() also lists, for example Gain and AcquisitionFrameRate. Drivers whose vendor API cannot enumerate options raise NotImplementedError, for example PvcamCamera.

Writing

A setter computes a configuration patch, merges it into the active configuration and calls configure(). It fails in these ways:

  • The acquisition is running: RuntimeError. Nothing is changed. Stop the acquisition and set again.

  • _set_config returns False or raises: the previous configuration is restored and the device is re-configured with it on a best-effort basis. A returned False raises RuntimeError, an exception from the driver is re-raised. If the re-configuration fails too, the error is logged and the hardware may be partially configured.

  • The driver does not support the feature: FeatureNotSupportedError, a subclass of NotImplementedError. Nothing is changed.

  • The driver supports the feature but the camera model has no node for it: the same error, naming the node. The previous configuration is restored. The IDS driver, for example, checks this.

  • The value is invalid for the driver: ValueError. Nothing is changed. Examples are asymmetric DCAM binning or a PVCam exposure time that is not a whole number of microseconds.

  • The patched configuration lacks a required config key: ValueError. Nothing is changed.

Config key order

Most drivers apply the configuration in key order, for example the IDS driver, and the valid range of some properties depends on others. A setter moves the keys of its patch to the end of the stored configuration of the active name, in patch order. Keys that are also in default_config_dict keep their position in get_configuration(), because the defaults are merged first.

Example

from herosdevices.hardware.dummy.cameras import CameraDummy

camera = CameraDummy(config_dict={"default": {"exposure_time": 0.01}})
camera.supported_features()
camera.roi_coordinates  # None, no ROI configured
camera.roi_coordinates = (0, 0, 256, 128)
camera.binning = (2, 2)
camera.roi_coordinates  # (0, 0, 256, 128)

Writing a driver

The ten hooks _get_*/_set_* for exposure time, ROI, binning, gain and frame rate are optional. A feature counts as supported if the subclass overrides both hooks of its pair. A pair with only one hook overridden is unsupported, and a warning is logged the first time supported_features() is called for the class. The property still calls the overridden hook, while the other direction raises FeatureNotSupportedError.

  • A _get_* hook reads the value from the stored configuration only (self.get_configuration()), never from the device. It may return None.

  • A _set_* hook only returns a configuration patch. It does not write to the device or change self._config. The driver applies the patch in _set_config.

  • A hook that needs another value, such as the binning for a ROI conversion, reads it from the configuration instead of calling the other hook, which may be unsupported.

  • If the device model may lack the node of a helper, _set_config raises FeatureNotSupportedError for it. While a setter applies its patch, the patch keys are in self._patch_keys, so the driver can raise only for these keys and handle a missing node for a key from the user configuration as before. The setter restores the configuration and passes the error on.

To add a feature, add to CameraTemplate the pair of hooks with the default body raise FeatureNotSupportedError(...) and the property. The getter returns None on FeatureNotSupportedError. The setter passes the hook result to _apply_config_patch. Add the pair to _FEATURE_HOOKS. In tests/hardware/test_camera_helpers.py, add a test value to FEATURE_VALUES and the feature to the expected features of each driver that supports it.

ROI units

roi_coordinates is (x_offset, y_offset, width, height) in the pixels the vendor API uses for its ROI. Some APIs count binned pixels once the binning is larger than 1, for example the GenICam nodes OffsetX, OffsetY, Width and Height. The same values then cover a different area of the sensor after the binning changes. Other APIs count unbinned sensor pixels. Check the vendor documentation of the camera.

Gain and frame rate

The gain has no common unit. Each driver passes the value to its vendor API unchanged, for example to the GenICam Gain node. The setter raises a ValueError for NaN, infinity, booleans and non-numbers. Range checks and side effects, such as switching automatic gain off, depend on the driver and are described in its class documentation.

frame_rate is a limit, not a measurement. The camera may deliver fewer frames if the exposure time, the ROI or the interface bandwidth do not allow the rate. Setting None removes the limit. The getter returns None for a removed limit and also if no frame rate is configured or the driver does not support the feature. Use supported_features() to tell unsupported from unlimited. How a driver removes the limit depends on the vendor API, for example the IDS driver writes the maximum of the AcquisitionFrameRate node.

The exposure time must not exceed the frame period. A driver that retries rejected keys after the others, for example the IDS driver, accepts ExposureTime and AcquisitionFrameRate in either order.

The setter raises a ValueError for a frame rate that is not positive and finite. None is allowed.