From f82414cc075c224cff42ebf5ade7c77a16ddb9cd Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Fri, 11 Jul 2014 11:06:28 +0200 Subject: Split up the manual --- docs/api.rst | 211 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 docs/api.rst (limited to 'docs/api.rst') diff --git a/docs/api.rst b/docs/api.rst new file mode 100644 index 0000000..8bb26b9 --- /dev/null +++ b/docs/api.rst @@ -0,0 +1,211 @@ +Application Programming Interface +================================= + +In the introduction we had a quick glance over the basic API used to communicate +with a camera. Now we will go into more detail and explain required background +to understand the execution model. + + +Instantiating cameras +--------------------- + +We have already seen how to instantiate a camera object from a name. If +you have more than one camera connected to a machine, you will most +likely want the user decide which to use. To do so, you can enumerate +all camera strings with ``uca_plugin_manager_get_available_cameras``:: + + GList *types; + + types = uca_camera_get_available_cameras (manager); + + for (GList *it = g_list_first; it != NULL; it = g_list_next (it)) + g_print ("%s\n", (gchar *) it->data); + + /* free the strings and the list */ + g_list_foreach (types, (GFunc) g_free, NULL); + g_list_free (types); + + +Errors +------ + +All public API functions take a location of a pointer to a ``GError`` +structure as a last argument. You can pass in a ``NULL`` value, in which +case you cannot be notified about exceptional behavior. On the other +hand, if you pass in a pointer to a ``GError``, it must be initialized +with ``NULL`` so that you do not accidentally overwrite and miss an +error occurred earlier. + +Read more about ``GError``\ s in the official GLib +`documentation `__. + + +Recording +--------- + +Recording frames is independent of actually grabbing them and is started +with ``uca_camera_start_recording``. You should always stop the +recording with ``ufo_camera_stop_recording`` when you finished. When the +recording has started, you can grab frames synchronously as described +earlier. In this mode, a block to ``uca_camera_grab`` blocks until a +frame is read from the camera. Grabbing might block indefinitely, when +the camera is not functioning correctly or it is not triggered +automatically. + + +Triggering +---------- + +``libuca`` supports three trigger modes through the "trigger-mode" +property: + +1. ``UCA_CAMERA_TRIGGER_AUTO``: Exposure is triggered by the camera + itself. +2. ``UCA_CAMERA_TRIGGER_INTERNAL``: Exposure is triggered via software. +3. ``UCA_CAMERA_TRIGGER_EXTERNAL``: Exposure is triggered by an external + hardware mechanism. + +With ``UCA_CAMERA_TRIGGER_INTERNAL`` you have to trigger with +``uca_camera_trigger``:: + + /* thread A */ + g_object_set (G_OBJECT (camera), + "trigger-mode", UCA_CAMERA_TRIGGER_INTERNAL, + NULL); + + uca_camera_start_recording (camera, NULL); + uca_camera_grab (camera, &buffer, NULL); + uca_camera_stop_recording (camera, NULL); + + /* thread B */ + uca_camera_trigger (camera, NULL); + + +Grabbing frames asynchronously +------------------------------ + +In some applications, it might make sense to setup asynchronous frame +acquisition, for which you will not be blocked by a call to ``libuca``:: + + static void + callback (gpointer buffer, gpointer user_data) + { + /* + * Do something useful with the buffer and the string we have got. + */ + } + + static void + setup_async (UcaCamera *camera) + { + gchar *s = g_strdup ("lorem ipsum"); + + g_object_set (G_OBJECT (camera), + "transfer-asynchronously", TRUE, + NULL); + + uca_camera_set_grab_func (camera, callback, s); + uca_camera_start_recording (camera, NULL); + + /* + * We will return here and `callback` will be called for each newo + * new frame. + */ + } + + +Bindings +-------- + +.. highlight:: python + +Since version 1.1, libuca generates GObject introspection meta data if +``g-ir-scanner`` and ``g-ir-compiler`` can be found. When the XML +description ``Uca-x.y.gir`` and the typelib ``Uca-x.y.typelib`` are +installed, GI-aware languages can access libuca and create and modify +cameras, for example in Python:: + + from gi.repository import Uca + + pm = Uca.PluginManager() + + # List all cameras + print(pm.get_available_cameras()) + + # Load a camera + cam = pm.get_camerav('pco', []) + + # You can read and write properties in two ways + cam.set_properties(exposure_time=0.05) + cam.props.roi_width = 1024 + +Note, that the naming of classes and properties depends on the GI +implementation of the target language. For example with Python, the +namespace prefix ``uca_`` becomes the module name ``Uca`` and dashes +separating property names become underscores. + +Integration with Numpy is relatively straightforward. The most important +thing is to get the data pointer from a Numpy array to pass it to +``uca_camera_grab``:: + + import numpy as np + + def create_array_from(camera): + """Create a suitably sized Numpy array and return it together with the + arrays data pointer""" + bits = camera.props.sensor_bitdepth + dtype = np.uint16 if bits > 8 else np.uint8 + a = np.zeros((cam.props.roi_height, cam.props.roi_width), dtype=dtype) + return a, a.__array_interface__['data'][0] + + # Suppose 'camera' is a already available, you would get the camera data like + # this: + a, buf = create_array_from(camera) + camera.start_recording() + camera.grab(buf) + + # Now data is in 'a' and we can use Numpy functions on it + print(np.mean(a)) + + camera.stop_recording() + + +Integrating new cameras +======================= + +A new camera is integrated by +`sub-classing `__ +``UcaCamera`` and implement all virtual methods. The simplest way is to +take the ``mock`` camera and rename all occurences. Note, that if you +class is going to be called ``FooBar``, the upper case variant is +``FOO_BAR`` and the lower case variant is ``foo_bar``. + +In order to fully implement a camera, you need to override at least the +following virtual methods: + +- ``start_recording``: Take suitable actions so that a subsequent call + to ``grab`` delivers an image or blocks until one is exposed. +- ``stop_recording``: Stop recording so that subsequent calls to + ``grab`` fail. +- ``grab``: Return an image from the camera or block until one is + ready. + + +Asynchronous operation +---------------------- + +When the camera supports asynchronous acquisition and announces it with +a true boolean value for ``"transfer-asynchronously"``, a mechanism must +be setup up during ``start_recording`` so that for each new frame the +grab func callback is called. + + +Cameras with internal memory +---------------------------- + +Cameras such as the pco.dimax record into their own on-board memory +rather than streaming directly to the host PC. In this case, both +``start_recording`` and ``stop_recording`` initiate and end acquisition +to the on-board memory. To initiate a data transfer, the host calls +``start_readout`` which must be suitably implemented. The actual data +transfer happens either with ``grab`` or asynchronously. -- cgit v1.2.3