The main Carrida API function - process

Revision: 1.0
Date: 2020-12-15
Contact: support@carrida-technologies.com
Copyright: 1996-2020 Carrida Technologies GmbH, Ettlingen, Germany
Author: Carrida Support

Home page

Table of Contents

1   Introduction

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.

2   Delay in results - option without a listener

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

3   Dealing with Carrida listener

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.

4   License restriction

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.