Welcome¶
libuca is a light-weight camera abstraction library written in C and GObject, focused on scientific cameras used at the ANKA synchrotron.

Contents¶
Quickstart¶
Installation¶
Before installing libuca itself, you should install any drivers and SDKs needed to access the cameras you want to access through libuca. Now you have two options: install pre-built packages or build from source.
Installing packages¶
Packages for the core library and all plugins are currently provided for openSUSE and can be obtained from the openSUSE Build Service at https://build.opensuse.org/package/show/home:ufo-kit/libuca.
Building on Linux¶
In order to build libuca from source, you need
- CMake,
- a C compiler (currently tested with gcc and clang),
- GLib and GObject development libraries and
- any required camera SDKs.
For the base system, install
[Debian] sudo apt-get install libglib2.0 cmake gcc
[openSUSE] sudo zypper in glib2-devel cmake gcc
In case you want to use the graphical user interface you also need the Gtk+ development libraries:
[Debian] sudo apt-get install libgtk+2.0-dev
[openSUSE] sudo zypper in gtk2-devel
To generate bindings for third-party languages, you have to install
[Debian] sudo apt-get install gobject-introspection
[openSUSE] sudo zypper in gobject-introspection-devel
Fetching the sources¶
Clone the repository
git clone https://github.com/ufo-kit/libuca
or download the latest release at https://github.com/ufo-kit/libuca/releases and
unzip the .zip
file:
unzip libuca-x.y.z.zip
or untar the .tar.gz
file:
tar -zxvf libuca-x.y.z.tar.gz
and create a new, empty build directory inside:
cd libuca/
mkdir build
Configuring and building¶
Now you need to create the Makefile with CMake. Go into the build directory and
point CMake to the libuca
top-level directory:
cd build/
cmake ..
As long as the last line reads “Build files have been written to”, the
configuration stage is successful. In this case you can build libuca
with
make
and install with
sudo make install
If an essential dependency could not be found, the configuration stage will stop and build files will not be written. If a non-essential dependency (such as a certain camera SDK) is not found, the configuration stage will continue but that particular camera support not built.
If you want to customize the build process you can pass several variables to CMake:
cmake .. -DPREFIX=/usr -DLIBDIR=/usr/lib64
The former tells CMake to install into /usr
instead of /usr/local
and
the latter that we want to install the libraries and plugins into the lib64
subdir instead of the default lib
subdir as it is common on SUSE systems.
Building on Windows¶
Using MSYS2, the build procedure is similar to Linux but differs in some points.
First, download msys2-<arch>-<release-date>.exe from msys2.org (preferably the x86_64 variant) and install it to
C:\msys64
or any other location.
Run the MSYS2 MinGW shell from the start menu and update the core if this is the first time using:
pacman -Syu
Close the terminal and open a new shell again. Install all required dependencies with:
pacman -S gcc make cmake pkg-config git glib2-devel gettext-devel
Clone libuca and any plugins you want to use on Windows:
git clone https://github.com/ufo-kit/libuca
and create an empty build
directory in libuca’s root folder. Change
directory to that folder, configure libuca using CMake and build and install it:
cd libuca
mkdir build && cd build
cmake -DCMAKE_INSTALL_PREFIX=/usr ..
make && make install
Before proceeding with the plugins you must soft link the library to fit the naming scheme:
ln -s /usr/bin/libuca.so /usr/lib/libuca.dll.a
To build plugins nothing special is required. Clone the repository, create an empty build directory, configure and build:
git clone https://github.com/ufo-kit/uca-net
cd uca-net
mkdir build && cd build
cmake ..
make && make install
Usage¶
The API for accessing cameras is straightforward. First you need to include the necessary header files:
#include <uca/uca-plugin-manager.h>
#include <uca/uca-camera.h>
Then you need to setup the type system:
int
main (int argc, char *argv[])
{
UcaPluginManager *manager;
UcaCamera *camera;
GError *error = NULL; /* this _must_ be set to NULL */
#if !(GLIB_CHECK_VERSION (2, 36, 0))
g_type_init();
#endif
Now you can instantiate new camera objects. Each camera is identified by a human-readable string, in this case we want to access any pco camera that is supported by libpco. To instantiate a camera we have to create a plugin manager first:
manager = uca_plugin_manager_new ();
camera = uca_plugin_manager_get_camera (manager, "pco", &error, NULL);
Errors are indicated with a returned value NULL
and error
set to
a value other than NULL
:
if (camera == NULL) {
g_error ("Initialization: %s", error->message);
return 1;
}
You should always remove the reference from the camera object when not using it in order to free all associated resources:
g_object_unref (camera);
return 0;
}
Compile this program with
cc `pkg-config --cflags --libs libuca glib-2.0` foo.c -o foo
Now, run foo
and verify that no errors occur.
Grabbing frames¶
To synchronously grab frames, first start the camera:
uca_camera_start_recording (camera, &error);
g_assert_no_error (error);
Now, you have to allocate a suitably sized buffer and pass it to
uca_camera_grab
:
gpointer buffer = g_malloc0 (640 * 480 * 2);
uca_camera_grab (camera, buffer, &error);
You have to make sure that the buffer is large enough by querying the size of the region of interest and the number of bits that are transferred.
Getting and setting camera parameters¶
Because camera parameters vary tremendously between different vendors
and products, they are realized with so-called GObject properties, a
mechanism that maps string keys to typed and access restricted values.
To get a value, you use the g_object_get
function and provide memory
where the result is stored:
guint roi_width;
gdouble exposure_time;
g_object_get (G_OBJECT(camera),
"roi-width", &roi_width,
"exposure-time", &exposure_time,
/* The NULL marks the end! */
NULL
);
g_print ("Width of the region of interest: %d\n", roi_width);
g_print ("Exposure time: %3.5fs\n", exposure_time);
In a similar way, properties are set with g_object_set
:
guint roi_width = 512;
gdouble exposure_time = 0.001;
g_object_set (G_OBJECT (camera),
"roi-width", roi_width,
"exposure-time", exposure_time,
NULL);
Each property can be associated with a physical unit. To query for the
unit call uca_camera_get_unit
and pass a property name. The function
will then return a value from the UcaUnit
enum.
Supported cameras¶
The following cameras are supported:
- pco.edge, pco.dimax, pco.4000 (all CameraLink) via
libpco. You need to have
the SiliconSoftware frame grabber SDK with the
menable
kernel module installed. - PhotonFocus
- Pylon
- UFO Camera developed at KIT/IPE.
A remote access is available for libuca
cameras.
Property documentation¶
mock¶
- string name
Name of the camera
Default:- unsigned int sensor-width
Width of the sensor in pixels
Default: 512Range: [1, 4294967295]- unsigned int sensor-height
Height of the sensor in pixels
Default: 512Range: [1, 4294967295]- double sensor-pixel-width
Width of sensor pixel in meters
Default: 1e-05Range: [2.22507385851e-308, 1.79769313486e+308]- double sensor-pixel-height
Height of sensor pixel in meters
Default: 1e-05Range: [2.22507385851e-308, 1.79769313486e+308]- unsigned int sensor-bitdepth
Number of bits per pixel
Default: 8Range: [1, 32]- unsigned int sensor-horizontal-binning
Number of sensor ADCs that are combined to one pixel in horizontal direction
Default: 1Range: [1, 4294967295]- unsigned int sensor-vertical-binning
Number of sensor ADCs that are combined to one pixel in vertical direction
Default: 1Range: [1, 4294967295]- None trigger-source
Trigger source
Default: <enum UCA_CAMERA_TRIGGER_SOURCE_AUTO of type UcaCameraTriggerSource>- None trigger-type
Trigger type
Default: <enum UCA_CAMERA_TRIGGER_TYPE_EDGE of type UcaCameraTriggerType>- double exposure-time
Exposure time in seconds
Default: 1.0Range: [0.0, 1.79769313486e+308]- double frames-per-second
Frames per second
Default: 1.0Range: [2.22507385851e-308, 1.79769313486e+308]- unsigned int roi-x0
Horizontal coordinate
Default: 0Range: [0, 4294967295]- unsigned int roi-y0
Vertical coordinate
Default: 0Range: [0, 4294967295]- unsigned int roi-width
Width of the region of interest
Default: 1Range: [1, 4294967295]- unsigned int roi-height
Height of the region of interest
Default: 1Range: [1, 4294967295]- unsigned int roi-width-multiplier
Minimum possible step size of horizontal ROI
Default: 1Range: [1, 4294967295]- unsigned int roi-height-multiplier
Minimum possible step size of vertical ROI
Default: 1Range: [1, 4294967295]- bool has-streaming
Is the camera able to stream the data
Default: True- bool has-camram-recording
Is the camera able to record the data in-camera
Default: False- unsigned int recorded-frames
Number of frames recorded into internal camera memory
Default: 0Range: [0, 4294967295]- bool transfer-asynchronously
Specify whether data should be transfered asynchronously using a specified callback
Default: False- bool is-recording
Is the camera currently recording
Default: False- bool is-readout
Is camera in readout mode
Default: False- bool buffered
TRUE if libuca should buffer frames
Default: False- unsigned int num-buffers
Number of frame buffers in the ring buffer
Default: 4Range: [0, 4294967295]- bool fill-data
Fill data with gradient and random image
Default: True
pco¶
- string name
Name of the camera
Default:- unsigned int sensor-width
Width of the sensor in pixels
Default: 1Range: [1, 4294967295]- unsigned int sensor-height
Height of the sensor in pixels
Default: 1Range: [1, 4294967295]- double sensor-pixel-width
Width of sensor pixel in meters
Default: 1e-05Range: [2.22507385851e-308, 1.79769313486e+308]- double sensor-pixel-height
Height of sensor pixel in meters
Default: 1e-05Range: [2.22507385851e-308, 1.79769313486e+308]- unsigned int sensor-bitdepth
Number of bits per pixel
Default: 1Range: [1, 32]- unsigned int sensor-horizontal-binning
Number of sensor ADCs that are combined to one pixel in horizontal direction
Default: 1Range: [1, 4294967295]- None sensor-horizontal-binnings
Array of possible binnings in horizontal direction
Default: None- unsigned int sensor-vertical-binning
Number of sensor ADCs that are combined to one pixel in vertical direction
Default: 1Range: [1, 4294967295]- None sensor-vertical-binnings
Array of possible binnings in vertical direction
Default: None- None trigger-source
Trigger source
Default: <enum UCA_CAMERA_TRIGGER_SOURCE_AUTO of type UcaCameraTriggerSource>- None trigger-type
Trigger type
Default: <enum UCA_CAMERA_TRIGGER_TYPE_EDGE of type UcaCameraTriggerType>- double exposure-time
Exposure time in seconds
Default: 1.0Range: [0.0, 1.79769313486e+308]- double frames-per-second
Frames per second
Default: 1.0Range: [2.22507385851e-308, 1.79769313486e+308]- unsigned int roi-x0
Horizontal coordinate
Default: 0Range: [0, 4294967295]- unsigned int roi-y0
Vertical coordinate
Default: 0Range: [0, 4294967295]- unsigned int roi-width
Width of the region of interest
Default: 1Range: [1, 4294967295]- unsigned int roi-height
Height of the region of interest
Default: 1Range: [1, 4294967295]- unsigned int roi-width-multiplier
Minimum possible step size of horizontal ROI
Default: 1Range: [1, 4294967295]- unsigned int roi-height-multiplier
Minimum possible step size of vertical ROI
Default: 1Range: [1, 4294967295]- bool has-streaming
Is the camera able to stream the data
Default: True- bool has-camram-recording
Is the camera able to record the data in-camera
Default: False- unsigned int recorded-frames
Number of frames recorded into internal camera memory
Default: 0Range: [0, 4294967295]- bool transfer-asynchronously
Specify whether data should be transfered asynchronously using a specified callback
Default: False- bool is-recording
Is the camera currently recording
Default: False- bool is-readout
Is camera in readout mode
Default: False- bool buffered
TRUE if libuca should buffer frames
Default: False- unsigned int num-buffers
Number of frame buffers in the ring buffer
Default: 4Range: [0, 4294967295]- bool sensor-extended
Use extended sensor format
Default: False- unsigned int sensor-width-extended
Width of the extended sensor in pixels
Default: 1Range: [1, 4294967295]- unsigned int sensor-height-extended
Height of the extended sensor in pixels
Default: 1Range: [1, 4294967295]- double sensor-temperature
Temperature of the sensor in degree Celsius
Default: 0.0Range: [-1.79769313486e+308, 1.79769313486e+308]- None sensor-pixelrates
Array of possible sensor pixel rates
Default: None- unsigned int sensor-pixelrate
Pixel rate
Default: 1Range: [1, 4294967295]- unsigned int sensor-adcs
Number of ADCs to use
Default: 1Range: [1, 2]- unsigned int sensor-max-adcs
Maximum number of ADCs that can be set with “sensor-adcs”
Default: 1Range: [1, 4294967295]- bool has-double-image-mode
Is double image mode supported by this model
Default: False- bool double-image-mode
Use double image mode
Default: False- bool offset-mode
Use offset mode
Default: False- None record-mode
Record mode
Default: <enum UCA_PCO_CAMERA_RECORD_MODE_SEQUENCE of type UcaPcoCameraRecordMode>- None storage-mode
Storage mode
Default: <enum UCA_PCO_CAMERA_STORAGE_MODE_FIFO_BUFFER of type UcaPcoCameraStorageMode>- None acquire-mode
Acquire mode
Default: <enum UCA_PCO_CAMERA_ACQUIRE_MODE_AUTO of type UcaPcoCameraAcquireMode>- bool fast-scan
Use fast scan mode with less dynamic range
Default: False- int cooling-point
Cooling point of the camera in degree celsius
Default: 5Range: [0, 10]- int cooling-point-min
Minimum cooling point in degree celsius
Default: 0Range: [-2147483648, 2147483647]- int cooling-point-max
Maximum cooling point in degree celsius
Default: 0Range: [-2147483648, 2147483647]- int cooling-point-default
Default cooling point in degree celsius
Default: 0Range: [-2147483648, 2147483647]- bool noise-filter
Noise filter
Default: False- None timestamp-mode
Timestamp mode
Default: <enum UCA_PCO_CAMERA_TIMESTAMP_NONE of type UcaPcoCameraTimestamp>- string version
Camera version given as ‘serial number, hardware major.minor, firmware major.minor’
Default: 0, 0.0, 0.0- bool global-shutter
Global shutter enabled
Default: False
file¶
- string name
Name of the camera
Default:- unsigned int sensor-width
Width of the sensor in pixels
Default: 512Range: [1, 4294967295]- unsigned int sensor-height
Height of the sensor in pixels
Default: 512Range: [1, 4294967295]- double sensor-pixel-width
Width of sensor pixel in meters
Default: 1e-05Range: [2.22507385851e-308, 1.79769313486e+308]- double sensor-pixel-height
Height of sensor pixel in meters
Default: 1e-05Range: [2.22507385851e-308, 1.79769313486e+308]- unsigned int sensor-bitdepth
Number of bits per pixel
Default: 8Range: [1, 32]- unsigned int sensor-horizontal-binning
Number of sensor ADCs that are combined to one pixel in horizontal direction
Default: 1Range: [1, 4294967295]- unsigned int sensor-vertical-binning
Number of sensor ADCs that are combined to one pixel in vertical direction
Default: 1Range: [1, 4294967295]- None trigger-source
Trigger source
Default: <enum UCA_CAMERA_TRIGGER_SOURCE_AUTO of type UcaCameraTriggerSource>- None trigger-type
Trigger type
Default: <enum UCA_CAMERA_TRIGGER_TYPE_EDGE of type UcaCameraTriggerType>- double exposure-time
Exposure time in seconds
Default: 1.0Range: [0.0, 1.79769313486e+308]- double frames-per-second
Frames per second
Default: 1.0Range: [2.22507385851e-308, 1.79769313486e+308]- unsigned int roi-x0
Horizontal coordinate
Default: 0Range: [0, 4294967295]- unsigned int roi-y0
Vertical coordinate
Default: 0Range: [0, 4294967295]- unsigned int roi-width
Width of the region of interest
Default: 1Range: [1, 4294967295]- unsigned int roi-height
Height of the region of interest
Default: 1Range: [1, 4294967295]- unsigned int roi-width-multiplier
Minimum possible step size of horizontal ROI
Default: 1Range: [1, 4294967295]- unsigned int roi-height-multiplier
Minimum possible step size of vertical ROI
Default: 1Range: [1, 4294967295]- bool has-streaming
Is the camera able to stream the data
Default: True- bool has-camram-recording
Is the camera able to record the data in-camera
Default: False- unsigned int recorded-frames
Number of frames recorded into internal camera memory
Default: 0Range: [0, 4294967295]- bool transfer-asynchronously
Specify whether data should be transfered asynchronously using a specified callback
Default: False- bool is-recording
Is the camera currently recording
Default: False- bool is-readout
Is camera in readout mode
Default: False- bool buffered
TRUE if libuca should buffer frames
Default: False- unsigned int num-buffers
Number of frame buffers in the ring buffer
Default: 4Range: [0, 4294967295]- string path
Path to directory containing TIFF files
Default: .
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_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.
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:
UCA_CAMERA_TRIGGER_SOURCE_AUTO
: Exposure is triggered by the camera itself.UCA_CAMERA_TRIGGER_SOURCE_SOFTWARE
: Exposure is triggered via software.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¶
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 tograb
delivers an image or blocks until one is exposed.stop_recording
: Stop recording so that subsequent calls tograb
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.
Tools¶
Several tools are available to ensure libuca
works as expected. All
of them are installed with make install
.
uca-camera-control – simple graphical user interface¶
Records and shows frames. Moreover, you can change the camera properties in a side pane:

You can see all available options of uca-camera-control
with:
$ uca-camera-control --help-all
uca-grab – grabbing frames¶
Grab frames with
$ uca-grab --num-frames=10 camera-model
store them on disk as frames.tif
if libtiff
is installed,
otherwise as frame-00000.raw
, frame-000001.raw
. The raw format
is a memory dump of the frames, so you might want to use
ImageJ to view them. You can also
specify the output filename or filename prefix with the -o/--output
option:
$ uca-grab -n 10 --output=foobar.tif camera-model
Instead of reading exactly n frames, you can also specify a duration in fractions of seconds:
$ uca-grab --duration=0.25 camera-model
You can see all available options of uca-grab
with:
$ uca-grab --help-all
uca-benchmark – check bandwidth¶
Measure the memory bandwidth by taking subsequent frames and averaging the grabbing time:
$ uca-benchmark option camera-model
You can specify the number of frames per run with the -n/--num-frames
option, the number of runs with the -r/--num-runs
option and test asynchronous mode with the async
option:
$ uca-benchmark -n 100 -r 3 --async mock
# Type Trigger Source FPS Bandwidth Frames acquired/total
sync auto 17.57 Hz 4.39 MB/s 300/300 acquired (0.00% dropped)
async auto 19.98 Hz 4.99 MB/s 300/300 acquired (0.00% dropped)
# --- General information ---
# Camera: mock
# Sensor size: 4096x4096
# ROI size: 512x512
# Exposure time: 0.050000s
You can see all available options of uca-benchmark
with:
$ uca-benchmark --help-all
uca-info – get properties information¶
Get information about camera properties with:
$ uca-info camera-model
For example:
$ uca-info mock
# RO | name | "mock camera"
# RO | sensor-width | 4096
# RO | sensor-height | 4096
# RO | sensor-pixel-width | 0.000010
# RO | sensor-pixel-height | 0.000010
# RO | sensor-bitdepth | 8
...
uca-gen-doc – generate properties documentation¶
Generate HTML source code of property documentation of a camera with:
$ uca-gen-doc camera-model
Concert¶
Concert is a light-weight control system interface, which can also control libuca
cameras.
Installation¶
In the official documentation you can read how to install Concert
.
Usage¶
Concert
can be used from a session and within an integrated IPython
shell or as a library.
In order to create a concert session you should first initialize the session and then start the editor:
$ concert init session
$ concert edit session
You can simply add your camera, for example the mock
camera with:
from concert.devices.cameras.uca import Camera
camera = Camera("mock")
and start the session with:
$ concert start session
The function ddoc()
will give you an overview of all defined devices in the session:
session > ddoc()
# ------------------------------------------------------------------------------------------------
# Name Description Parameters
# ------------------------------------------------------------------------------------------------
# camera libuca-based camera. Name Unit Description
# buffered None info TRUE if libuca should buffer
# All properties that are frames
# exported by the locked no
# underlying camera are exposure_time second info Exposure time in seconds
# also visible. locked no
# lower -inf second
# upper inf second
...
Getting and setting camera parameters¶
You can get an overview of the camera parameters by calling the dstate()
function:
session > dstate()
# ---------------------------------------------------------
# Name Parameters
# ---------------------------------------------------------
# camera buffered False
# exposure_time 0.05 second
# fill_data True
# frame_rate 20.0 1 / second
# has_camram_recording False
# has_streaming True
...
set the value of a parameter with:
session > camera.exposure_time = 0.01 * q.s
and check the set value with:
session > camera.exposure_time
# <Quantity(0.01, 'second')>
or you can use the get()
and set()
methods:
session > exposure_time = camera["exposure_time"]
session > exposure_time.set(0.1 * q.s)
session > exposure_time.get().result()
# <Quantity(0.1, 'second')>
In order to set the trigger source property you can use trigger_sources.AUTO
, trigger_sources.SOFTWARE
or trigger_sources.EXTERNAL
:
session > camera.trigger_source = camera.trigger_sources.AUTO
Grabbing frames¶
To grab a frame, first start the camera, use the grab()
function and stop the camera afterwards:
session > camera.start_recording()
session > frame = camera.grab()
session > camera.stop_recording()
You get the frame as an array:
session > frame
# array([[ 0, 0, 0, ..., 0, 0, 0],
# [ 0, 0, 0, ..., 0, 0, 0],
# [ 0, 0, 255, ..., 0, 0, 0],
# ...,
# [ 0, 0, 0, ..., 0, 0, 0],
# [ 0, 0, 0, ..., 0, 0, 0],
# [ 0, 0, 0, ..., 0, 0, 0]], dtype=uint8)
Saving state and locking parameters¶
You can store the current state of your camera with:
session > camera.stash()
# <Future at 0x2b8ab10 state=running>
And go back to it again with:
session > camera.restore()
# <Future at 0x299f550 state=running>
In case you want to prevent a parameter or all the parameters from being written you can use the lock()
method:
session > camera["exposure_time"].lock()
session > camera["exposure_time"].set(1 * q.s)
# <Future at 0x2bb3d90 state=finished raised LockError>
# lock all parameters of the camera device
session > camera.lock()
and to unlock them again, just use the unlock()
method:
session > camera.unlock()
Concert as a library - more examples¶
You can also use Concert
as a library.
For example test the bit depth consistency with:
import numpy as np
from concert.quantities import q
from concert.devices.cameras.uca import Camera
def acquire_frame(camera):
camera.start_recording()
frame = camera.grab()
camera.stop_recording()
return frame
def test_bit_depth_consistency(camera):
camera.exposure_time = 1 * q.s
frame = acquire_frame(camera)
bits = camera.sensor_bitdepth
success = np.mean(frame) < 2**bits.magnitude
print "success" if success else "higher values than possible"
camera = Camera("mock")
test_bit_depth_consistency(camera)
or the exposure time consistency with:
def test_exposure_time_consistency(camera):
camera.exposure_time = 1 * q.ms
first = acquire_frame(camera)
camera.exposure_time = 100 * q.ms
second = acquire_frame(camera)
success = np.mean(first) < np.mean(second)
print "success" if success else "mean image value is lower than expected"
Official Documentation¶
If you have more questions or just want to know more about Concert
, please take a look at the very detailed official documentation.
Remote access¶
A Remote access is available for libuca
cameras:
TCP-based network bridge camera¶
uca-net is a transparent TCP-based network bridge camera for remote access of libuca
cameras.
Installation¶
The only dependency is libuca itself and any camera you wish to access.
Clone the repository:
$ git clone https://github.com/ufo-kit/uca-net.git
and create a new build directory inside:
$ cd uca-net/
$ mkdir build
The installation process is the same as by libuca
:
$ cd build/
$ cmake ..
$ make
$ sudo make install
Usage¶
You can start a server on a remote machine with:
$ ucad camera-model
and connect to it from any other machine, for example:
$ UCA_NET_HOST=foo.bar.com:4567 uca-grab -n 10 net # grab ten frames
$ uca-camera-control -c net # control graphically
GObject Tango device¶
UcaDevice is a generic Tango Device that wraps libuca
in order to
make libuca controlled cameras available as Tango devices.
Note
The documentation of UcaDevice can be outdated.
Architecture¶
UcaDevice is derived from GObjectDevice and adds libuca specific features like
start/stop recording etc. The most important feature is acquisition control.
UcaDevice is responsible for controlling acquisition of images from libuca. The
last aquired image can be accessed by reading attribute SingleImage
.
UcaDevice is most useful together with ImageDevice. If used together, UcaDevice
sends each aquired image to ImageDevice, which in turn does configured
post-processing like flipping, rotating or writing the image to disk.
Attributes¶
Besides the dynamic attributes translated from libuca properties UcaDevice has the following attributes:
NumberOfImages (Tango::DevLong)
: how many images should be acquired? A value of -1 means unlimited (read/write)ImageCounter (Tango::DevULong)
: current number of acquired images (read-only)CameraName (Tango::DevString)
: name of libuca object type (read-only)SingleImage (Tango::DevUChar)
: holds the last acquired image
Acquisition Control¶
In UcaDevice acquisition control is mostly implemented by two
yat4tango::DeviceTasks
: AcquisitionTask and GrabTask.
GrabTask’s only responsibility is to call grab
on libuca
synchronously and post the data on to AcquisitionTask.
AcquisitionTask is responsible for starting and stopping GrabTask and
for passing image data on to ImageDevice
(if exisiting) and to
UcaDevice
for storage in attribute SingleImage
. It counts how
many images have been acquired and checks this number against the
configured NumberOfImages
. If the desired number is reached, it
stops GrabTask, calls stop_recording
on libuca
and sets the
Tango state to STANDBY.
Plugins¶
As different cameras have different needs, plugins are used for special implementations. Plugins also makes UcaDevice and Tango Servers based on it more flexible and independent of libuca implementation.
- PCO: The Pco plugin implements additional checks when writing ROI values.
- Pylon: The Pylon plugin sets default values for
roi-width
androi-height
from libuca propertiesroi-width-default
androi-height-default
.
Installation¶
Detailed installation depends on the manifestation of UcaDevice. All manifestations depend on the following libraries:
- YAT
- YAT4Tango
- Tango
- GObjectDevice
- ImageDevice
Build¶
export PKG_CONFIG_PATH=/usr/lib/pkgconfig
export PYLON_ROOT=/usr/pylon
export LD_LIBRARY_PATH=$PYLON_ROOT/lib64:$PYLON_ROOT/genicam/bin/Linux64_x64
git clone git@iss-repo:UcaDevice.git
cd UcaDevice
mkdir build
cd build
cmake ..
make
Setup in Tango Database / Jive¶
Before ds_UcaDevice
can be started, it has to be registered manually
in the Tango database. With Jive
the following steps are necessary:
Register Server Menu Tools → Server Wizard Server name → ds_UcaDevice Instance name → my_server (name can be chosen freely) Next Cancel
Register Classes and Instances In tab Server: context menu on ds_UcaDevice → my_server → Add Class Class: UcaDevice Devices:
iss/name1/name2
Register server same for class ImageDeviceStart server
export TANGO_HOST=anka-tango:100xx export UCA_DEVICE_PLUGINS_DIR=/usr/lib(64) ds_UcaDevice pco my_server
Setup properties for UcaDevice context menu on device → Device wizard Property StorageDevice: address of previously registered ImageDevice instance
Setup properties for ImageDevice context menu on device → Device wizard PixelSize: how many bytes per pixel for the images of this camera? GrabbingDevice: address of previously registered UcaDevice instance
Finish restart ds_UcaDevice
FAQ¶
UcaDevice refuses to start up…? Most likely there is no instance registered for class UcaDevice. Register an instance for this class and it should work.
Why does UcaDevice depend on ImageDevice? UcaDevice pushes each new Frame to ImageDevice. Polling is not only less efficient but also prone to errors, e.g. missed/double frames and so on. Perhaps we could use the Tango-Event-System here!
Open Questions, Missing Features etc.¶
Why do we need to specify
Storage
for UcaDevice andGrabbingDevice
for ImageDevice?ImageDevice needs the Tango-Address of UcaDevice to mirror all Attributes and Commands and to forward them to it. UcaDevice needs the Tango-Address of ImageDevice to push a new frame on reception. A more convenient solution could be using conventions for the device names, e.g. of the form
$prefix/$instance_name/uca
and$prefix/$instance_name/image
. That way we could get rid of the two Device-Properties and an easier installation without the process of registering the classes and instances inJive
.Why does UcaDevice dynamically link to GObjectDevice?
There is no good reason for it. Packaging and installing would be easier if we linked statically to
GObjectDevice
because we would hide this dependency. Having a separateGObjectDevice
is generally a nice feature to makeGObjects
available in Tango. However, there is currently no GObjectDevice in use other than in the context of UcaDevice.Why must the plugin name be given as a command line parameter instead of a Device-Property?
There is no good reason for it. UcaDevice would be easier to use, if the plugin was configured in the Tango database as a Device-Property for the respective server instance.
Python Tango server¶
libuca/tango
is a Python-based Tango server.
Installation¶
In order to install libuca/tango
you need
Go to the libuca
directory and install the server script with:
$ cd tango
$ sudo python setup.py install
and create a new TANGO server Uca/xyz
with a class named Camera
.
Usage¶
Before starting the server, you have to create a new device property camera
which specifies which camera to use. If not set, the mock
camera will be used
by default.
Start the device server with:
$ Uca device-property
You should be able to manipulate camera attributes like exposure_time
and to store frames using a Start
, Store
, Stop
cycle:
import PyTango
camera = PyTango.DeviceProxy("foo/Camera/mock")
camera.exposure_time = 0.1
camera.Start()
camera.Store('foo.tif')
camera.Stop()
The HZG Tango server can also be used with libuca
cameras.