Notifications on Camera Property Updates or "When has auto focus finished?"

Introduction

GenICam, and therefore also IC Imaging Control 4, provides a messaging system that allows camera properties to notify an application when they have changed. Examples include:

  • Manual exposure control is locked because automatic exposure has been enabled

  • One-push white balance has completed

  • Autofocus has completed

  • A value changed

Implementation

Property classes such as ProCommand, PropBoolean, and PropInteger inherit from the base class Property, which provides the functions eventAddNotification() and eventRemoveNotification().

A callback function is passed to eventAddNotification(), which is invoked whenever the property changes. The function returns a token that can be used with eventRemoveNotification() to remove the property from the notification queue.

Examples

C++ PropCommand

A callback function for autofocus, for example:

void auto_focus_done(ic4::Property& prop)
{       
    if (prop.asCommand().isDone())
    {
        std::cout << "Command execution finished!" << std::endl;
    }
}

The function is registered by first retrieving the property from the property map and then calling eventAddNotification() on it:

int main()
{
    // Open device first
    auto autofocuscmd = grabber.devicePropertyMap().findCommand("FocusAuto", err);
    auto notifytoken = autofocuscmd.eventAddNotification(auto_focus_done);

    // Do other processing here
    autofocuscmd.execute();

eventAddNotification() returns a NotificationToken, which is later used-when the camera is closed-to remove the property from the notification list:

    autofocuscmd.eventRemoveNotification(notifytoken);
    grabber.streamStop();
    grabber.deviceClose();

    return 0;
}

Whenever the Auto Focus OnePush is executed in the program, the auto_focus_done function is called once the camera has finished focusing.

The property object-in this case autofocuscmd-must remain alive for as long as the camera is open. Therefore, it cannot simply be created inside a function that exits immediately after calling execute().

The same principle applies to OnePush white balance, which performs a one-time white balance adjustment.

Python Exposure Time

In a Python example, the current exposure time is displayed in a GUI using a QDoubleSpinBox. The following behavior is implemented:

  • The exposure time is automatically updated when it is changed by the automatic exposure control

  • When automatic exposure is enabled, the input field is disabled, and it is re-enabled when automatic exposure is turned off

Reading the exposure time while automatic mode is active is not currently supported by all camera models. However, it works very well with TIS GigE cameras.

A class derived from QDoubleSpinBox implements this functionality:

class PropertyFloatEdit(QDoubleSpinBox):
    def __init__(self):
        super().__init__()
        self.property: ic4.Property = None

    def __delete__(self, instance):
        self.property.event_remove_notification(self.notify_token)

    def set_property(self, grabber: ic4.Grabber, property_name: str):
        self.property = grabber.device_property_map.find_float(property_name)
        if self.property is not None:
            self.setMinimum(self.property.minimum)
            self.setMaximum(self.property.maximum)
            self.value = self.property.value

            self.notify_token = self.property.event_add_notification(
                self.on_property_update
            )

    def on_property_update(self, prop: ic4.Property):
        self.setEnabled(not prop.is_locked)
        self.setValue(prop.value)

When the property (e.g., ic4.PropId.EXPOSURE_TIME) is assigned in set_property(), event_add_notification() is called. This function receives self.on_property_update as the callback and returns a notification token, which is later used to remove the property from the notification queue.

The callback function on_property_update is straightforward: it uses prop.is_locked to enable or disable the QDoubleSpinBox, and updates the displayed value with the current exposure time.

In the main Python application, the PropertyFloatEdit is created as follows:

self.edt_exposuretime = PropertyFloatEdit()

After opening the camera, the EXPOSURE_TIME property is assigned:

self.edt_exposuretime.set_property(
    self.grabber, ic4.PropId.EXPOSURE_TIME
)