77#include < chrono>
88#include < vector>
99#include " edge-impulse-sdk/classifier/ei_run_classifier.h"
10+ #include " edge-impulse-sdk/classifier/postprocessing/ei_postprocessing_common.h"
1011#include " json/json.hpp"
1112#include " rapidjson/document.h"
1213#include " rapidjson/prettywriter.h"
@@ -77,6 +78,43 @@ void json_send_classification_response(int id,
7778 }
7879
7980#if EI_CLASSIFIER_OBJECT_DETECTION == 1
81+ #if EI_CLASSIFIER_OBJECT_TRACKING_ENABLED == 1
82+
83+ // For object tracking we'll do two things:
84+ // 1. we create bounding boxes for backwards compatibility (unique label per bb)
85+ // 2. separate object with traces
86+ nlohmann::json bb_res = nlohmann::json::array ();
87+ nlohmann::json tracking_res = nlohmann::json::array ();
88+ for (uint32_t ix = 0 ; ix < result.postprocessed_output .object_tracking_output .open_traces_count ; ix++) {
89+ ei_object_tracking_trace_t trace = result.postprocessed_output .object_tracking_output .open_traces [ix];
90+
91+ char label[100 ];
92+ snprintf (label, 100 , " %s (id=%d)" , trace.label , (int )trace.id );
93+
94+ nlohmann::json bb_json = {
95+ {" label" , label},
96+ {" value" , trace.value == 0 .0f ? 1 .0f : trace.value },
97+ {" x" , trace.x },
98+ {" y" , trace.y },
99+ {" width" , trace.width },
100+ {" height" , trace.height },
101+ };
102+ bb_res.push_back (bb_json);
103+
104+ nlohmann::json tracking_json = {
105+ {" object_id" , trace.id },
106+ {" label" , trace.label },
107+ {" value" , trace.value == 0 .0f ? 1 .0f : trace.value },
108+ {" x" , trace.x },
109+ {" y" , trace.y },
110+ {" width" , trace.width },
111+ {" height" , trace.height },
112+ };
113+ tracking_res.push_back (tracking_json);
114+ }
115+
116+ #else
117+
80118 nlohmann::json bb_res = nlohmann::json::array ();
81119 for (size_t ix = 0 ; ix < result.bounding_boxes_count ; ix++) {
82120 auto bb = result.bounding_boxes [ix];
@@ -93,6 +131,8 @@ void json_send_classification_response(int id,
93131 };
94132 bb_res.push_back (bb_json);
95133 }
134+
135+ #endif // EI_CLASSIFIER_OBJECT_TRACKING_ENABLED == 1
96136#else
97137 #if EI_CLASSIFIER_LABEL_COUNT > 0
98138 nlohmann::json classify_res;
@@ -127,6 +167,9 @@ void json_send_classification_response(int id,
127167 {" result" , {
128168#if EI_CLASSIFIER_OBJECT_DETECTION == 1
129169 {" bounding_boxes" , bb_res},
170+ #if EI_CLASSIFIER_OBJECT_TRACKING_ENABLED == 1
171+ {" object_tracking" , tracking_res},
172+ #endif
130173#else
131174 #if EI_CLASSIFIER_LABEL_COUNT > 0
132175 {" classification" , classify_res},
@@ -196,6 +239,7 @@ void json_message_handler(rapidjson::Document &msg, char *resp_buffer, size_t re
196239
197240 run_classifier_init ();
198241
242+ vector<std::string> engine_properties;
199243 vector<std::string> labels;
200244 for (size_t ix = 0 ; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
201245 labels.push_back (std::string (ei_classifier_inferencing_categories[ix]));
@@ -220,41 +264,64 @@ void json_message_handler(rapidjson::Document &msg, char *resp_buffer, size_t re
220264 const char *model_type = " object_detection" ;
221265 #endif // EI_CLASSIFIER_OBJECT_DETECTION_LAST_LAYER
222266#else
223- const char *model_type = " classification" ;
267+ const char *model_type = " classification" ;
224268#endif // EI_CLASSIFIER_OBJECT_DETECTION
225269
226270 // keep track of configurable thresholds
271+ // this needs to be kept in sync with jobs-container/cpp-exporter/wasm/emcc_binding.cpp
227272 nlohmann::json thresholds = nlohmann::json::array ();
228- for (size_t ix = 0 ; ix < ei_learning_blocks_size; ix++) {
229- const ei_learning_block_t learn_block = ei_learning_blocks[ix];
230- if (learn_block.infer_fn == run_gmm_anomaly) {
231- ei_learning_block_config_anomaly_gmm_t *config = (ei_learning_block_config_anomaly_gmm_t *)learn_block.config ;
273+ const ei_impulse_t *impulse = ei_default_impulse.impulse ;
274+
275+ for (size_t ix = 0 ; ix < impulse->postprocessing_blocks_size ; ix++) {
276+ const ei_postprocessing_block_t pp_block = impulse->postprocessing_blocks [ix];
277+ float threshold = 0 .0f ;
278+ std::string type_str = " unknown" ;
279+ std::string threshold_name_str = " unknown" ;
280+ auto res = get_threshold_postprocessing (&type_str, &threshold_name_str, pp_block.config , pp_block.type , &threshold);
281+ if (res == EI_IMPULSE_OK) {
232282 thresholds.push_back ({
233- { " id" , learn_block.blockId },
234- { " type" , " anomaly_gmm" },
235- { " min_anomaly_score" , config->anomaly_threshold }
283+ { " id" , pp_block.block_id },
284+ { " type" , type_str.c_str () },
285+ { threshold_name_str.c_str (), threshold }
286+ });
287+ };
288+ #if EI_CLASSIFIER_OBJECT_TRACKING_ENABLED == 1
289+ if (pp_block.init_fn == init_object_tracking) {
290+ const ei_object_tracking_config_t *config = (ei_object_tracking_config_t *)pp_block.config ;
291+
292+ thresholds.push_back ({
293+ { " id" , pp_block.block_id },
294+ { " type" , " object_tracking" },
295+ { " keep_grace" , config->keep_grace },
296+ { " max_observations" , config->max_observations },
297+ { " threshold" , config->threshold },
236298 });
237299 }
238- else if (learn_block.infer_fn == run_nn_inference) {
239- ei_learning_block_config_tflite_graph_t *config = (ei_learning_block_config_tflite_graph_t *)learn_block.config ;
240- if (config->classification_mode == EI_CLASSIFIER_CLASSIFICATION_MODE_OBJECT_DETECTION) {
241- thresholds.push_back ({
242- { " id" , learn_block.blockId },
243- { " type" , " object_detection" },
244- { " min_score" , config->threshold }
245- });
246- }
247- }
300+ #endif // #if EI_CLASSIFIER_OBJECT_TRACKING_ENABLED == 1
248301 }
249302
303+ #if EI_CLASSIFIER_OBJECT_TRACKING_ENABLED == 1
304+ const bool has_object_tracking = true ;
305+ #else
306+ const bool has_object_tracking = false ;
307+ #endif
308+ #if EI_CLASSIFIER_USE_GPU_DELEGATES == 1
309+ engine_properties.push_back (" gpu_delegates" );
310+ #endif
311+ #if EI_CLASSIFIER_USE_QNN_DELEGATES == 1
312+ engine_properties.push_back (" qnn_delegates" );
313+ #endif
314+
250315 nlohmann::json resp = {
251316 {" id" , id},
252317 {" success" , true },
253318 {" project" , {
254- {" id" , EI_CLASSIFIER_PROJECT_ID},
255- {" owner" , std::string (EI_CLASSIFIER_PROJECT_OWNER)},
256- {" name" , std::string (EI_CLASSIFIER_PROJECT_NAME)},
257- {" deploy_version" , EI_CLASSIFIER_PROJECT_DEPLOY_VERSION},
319+ {" id" , ei_default_impulse.impulse ->project_id },
320+ {" owner" , std::string (ei_default_impulse.impulse ->project_owner )},
321+ {" name" , std::string (ei_default_impulse.impulse ->project_name )},
322+ {" deploy_version" , ei_default_impulse.impulse ->deploy_version },
323+ {" impulse_id" , ei_default_impulse.impulse ->impulse_id },
324+ {" impulse_name" , std::string (ei_default_impulse.impulse ->impulse_name )},
258325 }},
259326 {" model_parameters" , {
260327 {" input_features_count" , EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE},
@@ -269,13 +336,18 @@ void json_message_handler(rapidjson::Document &msg, char *resp_buffer, size_t re
269336 {" image_resize_mode" , EI_RESIZE_STRINGS[EI_CLASSIFIER_RESIZE_MODE]},
270337 {" label_count" , EI_CLASSIFIER_LABEL_COUNT},
271338 {" has_anomaly" , EI_CLASSIFIER_HAS_ANOMALY},
339+ {" has_object_tracking" , has_object_tracking},
272340 {" labels" , labels},
273341 {" model_type" , model_type},
274342 {" slice_size" , EI_CLASSIFIER_SLICE_SIZE},
275343 {" use_continuous_mode" , EI_CLASSIFIER_SENSOR == EI_CLASSIFIER_SENSOR_MICROPHONE},
276344 {" inferencing_engine" , EI_CLASSIFIER_INFERENCING_ENGINE},
277345 {" thresholds" , thresholds},
278346 }},
347+ {" inferencing_engine" , {
348+ {" engine_type" , EI_CLASSIFIER_INFERENCING_ENGINE},
349+ {" properties" , engine_properties},
350+ }}
279351 };
280352
281353 snprintf (resp_buffer, resp_buffer_size, " %s\n " , resp.dump ().c_str ());
@@ -393,31 +465,63 @@ void json_message_handler(rapidjson::Document &msg, char *resp_buffer, size_t re
393465 return ;
394466 }
395467
468+ // this needs to be kept in sync with jobs-container/cpp-exporter/wasm/emcc_binding.cpp
396469 bool found_block = false ;
397470 int block_id = set_threshold[" id" ].GetInt ();
398- printf (" block_id=%d\n " , block_id);
399- for (size_t ix = 0 ; ix < ei_learning_blocks_size; ix++) {
400- const ei_learning_block_t learn_block = ei_learning_blocks[ix];
401- if (learn_block.blockId != block_id) continue ;
471+ const ei_impulse_t *impulse = ei_default_impulse.impulse ;
402472
473+ for (size_t ix = 0 ; ix < impulse->postprocessing_blocks_size ; ix++) {
474+ const ei_postprocessing_block_t pp_block = impulse->postprocessing_blocks [ix];
475+ if (pp_block.block_id != (uint32_t )block_id) continue ;
403476 found_block = true ;
477+ if (set_threshold.HasMember (" min_score" ) && set_threshold[" min_score" ].IsNumber ()) {
478+ set_threshold_postprocessing (pp_block.block_id , pp_block.config , pp_block.type , set_threshold[" min_score" ].GetFloat ());
479+ }
480+ }
481+
482+ for (size_t ix = 0 ; ix < ei_default_impulse.impulse ->postprocessing_blocks_size ; ix++) {
483+ const ei_postprocessing_block_t processing_block = ei_default_impulse.impulse ->postprocessing_blocks [ix];
484+ if ((int )processing_block.block_id != block_id) continue ;
404485
405- if (learn_block.infer_fn == run_gmm_anomaly) {
406- ei_learning_block_config_anomaly_gmm_t *config = (ei_learning_block_config_anomaly_gmm_t *)learn_block.config ;
486+ found_block = true ;
487+
488+ #if EI_CLASSIFIER_OBJECT_TRACKING_ENABLED == 1
489+ if (processing_block.init_fn == init_object_tracking) {
490+ const ei_object_tracking_config_t *old_config = (ei_object_tracking_config_t *)processing_block.config ;
491+
492+ ei_object_tracking_config_t new_config = {
493+ .implementation_version = old_config->implementation_version ,
494+ .keep_grace = old_config->keep_grace ,
495+ .max_observations = old_config->max_observations ,
496+ .threshold = old_config->threshold ,
497+ .use_iou = old_config->use_iou ,
498+ };
407499
408- if (set_threshold.HasMember (" min_anomaly_score " ) && set_threshold[" min_anomaly_score " ].IsNumber ()) {
409- config-> anomaly_threshold = set_threshold[" min_anomaly_score " ].GetFloat ();
500+ if (set_threshold.HasMember (" keep_grace " ) && set_threshold[" keep_grace " ].IsNumber ()) {
501+ new_config. keep_grace = ( uint32_t ) set_threshold[" keep_grace " ].GetUint64 ();
410502 }
411- }
412- else if (learn_block.infer_fn == run_nn_inference) {
413- ei_learning_block_config_tflite_graph_t *config = (ei_learning_block_config_tflite_graph_t *)learn_block.config ;
414- if (config->classification_mode == EI_CLASSIFIER_CLASSIFICATION_MODE_OBJECT_DETECTION) {
415- if (set_threshold.HasMember (" min_score" ) && set_threshold[" min_score" ].IsNumber ()) {
416- config->threshold = set_threshold[" min_score" ].GetFloat ();
417- printf (" min_score is now %f\n " , config->threshold );
418- }
503+ if (set_threshold.HasMember (" max_observations" ) && set_threshold[" max_observations" ].IsNumber ()) {
504+ new_config.max_observations = (uint16_t )set_threshold[" max_observations" ].GetUint64 ();
505+ }
506+ if (set_threshold.HasMember (" threshold" ) && set_threshold[" threshold" ].IsNumber ()) {
507+ new_config.threshold = set_threshold[" threshold" ].GetFloat ();
508+ }
509+
510+ EI_IMPULSE_ERROR ret = set_post_process_params (&ei_default_impulse, &new_config);
511+ if (ret != EI_IMPULSE_OK) {
512+ char err_msg[1024 ];
513+ snprintf (err_msg, 1024 , " set_threshold: set_post_process_params returned %d" , ret);
514+
515+ nlohmann::json err = {
516+ {" id" , id},
517+ {" success" , false },
518+ {" error" , err_msg},
519+ };
520+ snprintf (resp_buffer, resp_buffer_size, " %s\n " , err.dump ().c_str ());
521+ return ;
419522 }
420523 }
524+ #endif // #if EI_CLASSIFIER_OBJECT_TRACKING_ENABLED == 1
421525 }
422526
423527 if (!found_block) {
@@ -572,9 +676,9 @@ int socket_main(char *socket_path) {
572676 int connfd = accept (fd, (struct sockaddr *)NULL , NULL );
573677 printf (" Connected\n " );
574678
575- char *socket_buffer = (char *)malloc (STDIN_BUFFER_SIZE);
576- char *stdin_buffer = (char *)malloc (STDIN_BUFFER_SIZE);
577- char *response_buffer = (char *)malloc (STDIN_BUFFER_SIZE);
679+ char *socket_buffer = (char *)calloc (STDIN_BUFFER_SIZE, sizeof ( char ) );
680+ char *stdin_buffer = (char *)calloc (STDIN_BUFFER_SIZE, sizeof ( char ) );
681+ char *response_buffer = (char *)calloc (STDIN_BUFFER_SIZE, sizeof ( char ) );
578682 if (!socket_buffer || !stdin_buffer || !response_buffer) {
579683 printf (" ERR: Could not allocate buffers\n " );
580684 return 1 ;
0 commit comments