summaryrefslogtreecommitdiffstats
path: root/docs/api.rst
blob: 3bdde88c7ebd91b49274090570bde0ea08bc1218 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
Application Programming Interface
=================================

.. highlight:: c

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_plugin_manager_get_available_cameras (manager);

        for (GList *it = g_list_first (types); 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 <http://developer.gnome.org/glib/stable/glib-Error-Reporting.html>`__.


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 sources through the "trigger-source"
property:

1. ``UCA_CAMERA_TRIGGER_SOURCE_AUTO``: Exposure is triggered by the camera
   itself.
2. ``UCA_CAMERA_TRIGGER_SOURCE_SOFTWARE``: Exposure is triggered via software.
3. ``UCA_CAMERA_TRIGGER_SOURCE_EXTERNAL``: Exposure is triggered by an external
   hardware mechanism.

With ``UCA_CAMERA_TRIGGER_SOURCE_SOFTWARE`` you have to trigger with
``uca_camera_trigger``::

        /* thread A */
        g_object_set (G_OBJECT (camera),
                      "trigger-source", UCA_CAMERA_TRIGGER_SOURCE_SOFTWARE,
                      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);

Moreover, the "trigger-type" property specifies if the exposure should be
triggered at the rising edge or during the level signal.


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 <http://developer.gnome.org/gobject/stable/howto-gobject.html>`__
``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.