Revision: | 1.0 |
---|---|
Date: | 2020-12-15 |
Contact: | support@carrida-technologies.com |
Copyright: | 1996-2020 Carrida Technologies GmbH, Ettlingen, Germany |
Author: | Carrida Support |
Table of Contents
The Carrida API is kept as simple as possible. Basically, there is init() function for engine initialization and process() function for processing of input frames. Additionally, Carrida parameters can be set/acquired using generic set_parameter() and get_parameter() functions. In the end, the process_finishing() function should be called to process all remaining in Carrida input queue frames. Finally, the engine can be released by calling the finish() function.
NOTE: All example codes in this document are given using the C++ interface.
// initialise LPR engine Carrida::LPR lpr; Carrida::LPR_listener* no_listener = NULL; lpr.init( lpr_ini_path, no_listener ); while( process ) { // process image LPR_processing_result processing_ok; const Carrida::LPR_results& results = lpr.process( image, processing_ok ); // handle results // ... } // process remaining images in queue const Carrida::LPR_results& last_results = lpr.process_remaining(); // release engine lpr->finish();
There are still some details that are good to know and to understand - they are described in the following sections.
First of all, Carrida library operates asynchronously to the main program. It has an intern buffer (or queue) of input images. The images are processed in parallel - they are distributed to Carrida workers, one worker per CPU. Standard Carrida license allows the use of up to 4 CPUs. The main impact is that the results that one gets are generally not related to the input image, but correspond to one or several previous images that are finished to be processed:
const Carrida::LPR_results& results = lpr.process( image, processing_ok ); // results are not related to this image
It can be that several images are finished to be processed at the same moment - that is why results is an array. An LPR_Result object contains ANPR reading results and the corresponding image object - so there is no ambiguity between images and their ANPR results.
struct LPR_result { svcapture::Image image; ///< image for which ANPR reading results are presented Carrida::License_plates plates; ///< all license plate results for this image ... }
Another case is that there are sometimes no results ready after the latest call of the process() function. In this case, the results array will be empty. It is always possible though to force the engine to deliver results for the input image by calling the process_remaining() function.
const Carrida::LPR_results& results = lpr.process( image, processing_ok ); // results may be empty (or they do not contain ANPR readings for this image) const Carrida::LPR_results& last_results = lpr.process_remaining(); // force Carrida to process all images in queue results.insert( results.end(), last_results.begin(), last_results.end() ); // now it is confident that the results array contains ANPR readings for the input image
Additionally, depending on the configuration (streaming mode parameter), results may come with a delay of about 2-20 frames. The reason is that the Carrida engine optionally collects multiple readings per license plate and uses them to produce results that are more robust against noise, occlusions, etc. The following example demonstrates what it means in the practice, assuming that results come with the delay of 2 frames:
Carrida::LPR_results results; results = lpr.process( image1, processing_ok ); // results are empty results = lpr.process( image2, processing_ok ); // results are empty results = lpr.process( image3, processing_ok ); // results contain ANPR readings for image1
The purpose of the Carrida listener is to get ANPR results immediately as they get ready. The described above delay logic is not relevant here. One registers a listener during Carrida initialization and implements the result_ready() function. Each time the next image is processed, the result_ready() function is called. Note that the result_ready() function runs in other thread than the main application, so some synchronization logic may be needed to consider. It is worth mentioning that using the listener option has less overhead and is generally faster.
The following few steps are needed to be done to work with a listener. First, a custom listener derived from the Carrida::LPR_listener class needs to be implemented.
class MyListener : public Carrida::LPR_listener { public: void result_ready( Carrida::LPR_result& result ) { // implement handling of ANPR result here } }
Second, the Carrida::LPR object needs to be initialized with the listener:
MyListener lis; Carrida::LPR lpr; lpr.init( lpr_ini_path, &lis );
Now, when the process() function is called, it always returns an empty array. Instead, each result will come to results_ready() function.
const Carrida::LPR_results& results = lpr.process( image, processing_ok ); // results is always empty
When using the option with a listener, it is still possible to force Carrida to process all input images in the queue by calling the process_remaining() function.
The default Carrida license allows simultaneous processing of one input channel, wherein up to 4 CPU's can be utilized. This means, that only one Carrida::LPR object can be initialized at a particular moment. The following example demonstrates this license restriction.
Carrida::LPR lpr1; lpr1.init( lpr_ini_path, &lis1 ); // one channel is occupied Carrida::LPR lpr2; // still ok, second LPR object is not initialised lpr2.init( lpr_ini_path, &lis2 ); // EXCEPTION! using of two channels is not allowed lpr1.finish(); // release channel lpr2.init( lpr_ini_path, &lis2 ); // now, second LPR object can be used
To query for the license information, Carrida::LPR::print_license_info() function can ge used.