Camera API¶
The Camera API is a low level API built on top of the different vendor SDKs and provides a uniform interface to the camera configuration and frame acquisition. A Camera Plugin is an implementation of this interface built on top of the various vendor SDKs.
Synopsis¶
class camera
{
// Define the supported image types (a vector of types)
typedef ... images_t;
// Define the type of the initialization parameters
typedef ... init_params_t;
// Define the type of the acquisition parameters
typedef ... acq_params_t;
// Returns the description of the layout
layout_t get_layout();
// Control part of the camera
struct control
{
// Initialize the camera
void control(const init_params_t& params);
// Introspect the capabilities of the camera
template <typename Capability>
std::optional<Capability> get_capability();
// Prepare the camera for acquisition
void prepare(const acq_params_t& params);
// Start the acquisition
void start();
// Software trigger if the camera supports it
void trigger();
// Stop the acquisition
void stop();
// Returns the effective acquisition parameters
acq_params_t acq_params() const;
};
// Acquisition part of the camera
struct acquisition
{
// Initialize the camera
void acquisition(const init_params_t& params);
// Returns an allocator associated with the buffers
allocator_t get_allocator();
#if !defined(LIMA_IS_MULTI_DATA_CHANNELS)
// Returns a newly acquired set of images
// \warning this call might block and should be called asynchronously
images_t get_images();
#else
// Returns a newly acquired set of images for a given data channel
// \warning this call might block and should be called asynchronously
images_t get_images(int channel = 0);
// Returns the number of data channels
int nb_channels() const;
#endif // !defined(LIMA_IS_MULTI_DATA_CHANNELS)
};
};
State machine¶
Because different camera SDKs require different steps to the implement the transition from one state to another (e.g. prepared -> running), the FSM’s actions are fully overridable.
TODO
Detector modules layout¶
A detector layout is composed of modular items. Each item can be rotated and/or
flipped due to detector readout electronics design. In such cases, the isometric
transformation necessary to reconstruct the data in the final layout must be
defined. See :doc:geometry_transformations
.
Further operations can be performed on the full layout, affecting all the items. One specific operation is image crop (RoI), which may result in the exclusion of one or more items from the layout. Those “not-in-layout” items are nevertheless referenced by the layout structure in order to not change the item index list.
The layout is just a description of how the modular items are arranged. In order to assemble the final image the source data must be provided. The implementation expects one source view per layout item, even “not-in-layout” items.
An affine matrix transforming from sensor coordinates to final image coordinates is kept by the layout. This is useful when the user wants to keep the same region-of-interest in the sensor while adding/removing geometric transformations.
struct layout_item
{
// Position in the destination
point_t dst_topleft;
// Selection within the source
point_t src_topleft;
point_t src_dimensions;
// Transformation to be applied on item to reconstruct the layout
any_isometric_xform_t xform; // default is none
bool in_layout() const;
image_rect get_src_bounding_box() const;
image_rect get_dst_bounding_box() const;
point_t get_dst_dimensions() const;
};
// A layout is basically a container of items
struct layout
{
// Add/retreive a layout item
void add_item(layout_item i);
const layout_item& get_item(int i) const;
std::size_t size() const;
// Return/set the dimension of the full image
const point_t& get_dims() const;
void set_dims(point_t dims);
// converts sensor pixel coordinates into layout coordinates
affine_t get_sensor_coordinates_matrix() const;
...
};
Transformation¶
The layout implements the following transformations:
// Image algorithms
void vert_flip();
void horz_flip();
void rotate90cw();
void rotate90ccw();
void rotate180();
void crop(point_t topleft, point_t dimensions);
Each transformation updates the item state as well as the layout dimensions and the sensor-coordinates-matrix.
See :doc:geometry_transformations
.
Reconstruction¶
The layout reconstruction can be performed in two variants
Memory. This implementation uses serial Boost.Gil algorithms to reconstruct the layout items into a single image:
// Reconstruction to memory template <typename Range, typename Image, typename Value> void assemble(const Range& views, Image& out, Value fillvalue) const;
Virtual data set: TODO
// Reconstruction to file template <typename Range, typename T> void generate_vds(const std::string& filename, Range h5_sources, T fillvalue) const;
Usage¶
Camera construction¶
// Set the initialization parameters
camera::init_params_t init_params;
init.ip = "127.0.0.1";
init.port = 80;
// Construct the camera
camera cam(init_params);
// Or construct the camera directly with initialization list
camera cam({"127.0.0.1", 8080});
Acquisition¶
// Set the acquisition parameters
camera::acq_params_t acq_params;
acq.shutter_speed = 5;
acq.binning = {2, 2};
cam.prepare(acq_params);
cam.start();
for (int i : )
Implementation¶
CRTP¶
Delegates part of the implementation to the base class.
class config
{
// Define the supported image types (a vector of types)
typedef ... images_t;
// Define the type of the initialization parameters
typedef ... init_params_t;
// Define the type of the acquisition parameters
typedef ... acq_params_t;
};
class camera : lima::camera<camera, config>
{
}
Reflection / Introspection¶
Use reflection for parameters so that serialization and visitation could be generated.
with Boost.Hana:
struct init_params {
BOOST_HANA_DEFINE_STRUCT(Person,
(std::string, ip),
(int, port)
);
};
using namespace hana = boost::hana;
hana::for_each(john, [](auto pair) {
std::cout << hana::to<char const*>(hana::first(pair)) << ": "
<< hana::second(pair) << std::endl;
});
with Boost.PFR:
struct init_params {
BOOST_HANA_DEFINE_STRUCT(Person,
(std::string, ip),
(int, port)
);
};
init_params params;
boost::pfr::for_each_field(params, [](const auto& field, std::size_t idx) {
std::cout << idx << ": " << boost::typeindex::type_id_runtime(field) << '\n';
});