| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #ifndef EI_POSTPROCESSING_COMMON_H |
| #define EI_POSTPROCESSING_COMMON_H |
|
|
| #include "model-parameters/model_metadata.h" |
| #include "edge-impulse-sdk/classifier/postprocessing/ei_postprocessing_types.h" |
| #include "edge-impulse-sdk/classifier/postprocessing/ei_postprocessing_ai_hub.h" |
| #include "edge-impulse-sdk/classifier/ei_model_types.h" |
| #include "edge-impulse-sdk/classifier/ei_classifier_types.h" |
| #include "edge-impulse-sdk/classifier/ei_nms.h" |
| #include "edge-impulse-sdk/dsp/ei_vector.h" |
| #include <string> |
|
|
| #ifdef EI_HAS_PADDLEOCR_DETECTOR |
| #include <utility> |
| #include <queue> |
| #include <limits> |
| #endif |
|
|
| int16_t get_block_number(ei_impulse_handle_t *handle, void *init_func) |
| { |
| for (size_t i = 0; i < handle->impulse->postprocessing_blocks_size; i++) { |
| if (handle->impulse->postprocessing_blocks[i].init_fn == init_func) { |
| return i; |
| } |
| } |
| return -1; |
| } |
|
|
| |
| |
| |
| |
| __attribute__((unused)) static bool ei_cube_check_overlap(ei_classifier_cube_t *c, uint32_t x, uint32_t y, uint32_t width, uint32_t height, float confidence) { |
| bool is_overlapping = !(c->x + c->width < x || c->y + c->height < y || c->x > x + width || c->y > y + height); |
| if (!is_overlapping) return false; |
|
|
| |
| if (x < c->x) { |
| |
| c->x = x; |
| c->width += c->x - x; |
| } |
| |
| if (y < c->y) { |
| |
| c->y = y; |
| c->height += c->y - y; |
| } |
| |
| if (x + width > c->x + c->width) { |
| |
| c->width += (x + width) - (c->x + c->width); |
| } |
| |
| if (y + height > c->y + c->height) { |
| |
| c->height += (y + height) - (c->y + c->height); |
| } |
| |
| if (confidence > c->confidence) { |
| c->confidence = confidence; |
| } |
| return true; |
| } |
|
|
| __attribute__((unused)) static void ei_handle_cube(std::vector<ei_classifier_cube_t*> *cubes, uint32_t x, uint32_t y, float vf, const char *label, float detection_threshold) { |
| if (vf < detection_threshold) return; |
|
|
| bool has_overlapping = false; |
| uint32_t width = 1; |
| uint32_t height = 1; |
|
|
| for (auto c : *cubes) { |
| |
| if (strcmp(c->label, label) != 0) continue; |
|
|
| if (ei_cube_check_overlap(c, x, y, width, height, vf)) { |
| has_overlapping = true; |
| break; |
| } |
| } |
|
|
| if (!has_overlapping) { |
| ei_classifier_cube_t *cube = new ei_classifier_cube_t(); |
| cube->x = x; |
| cube->y = y; |
| cube->width = 1; |
| cube->height = 1; |
| cube->confidence = vf; |
| cube->label = label; |
| cubes->push_back(cube); |
| } |
| } |
|
|
| __attribute__((unused)) static void process_cubes(ei_impulse_result_t *result, std::vector<ei_classifier_cube_t*> *cubes, uint32_t out_width_factor, uint32_t object_detection_count) { |
| std::vector<ei_classifier_cube_t*> bbs; |
| static std::vector<ei_impulse_result_bounding_box_t> results; |
| uint32_t added_boxes_count = 0; |
| results.clear(); |
|
|
| for (auto sc : *cubes) { |
| bool has_overlapping = false; |
|
|
| uint32_t x = sc->x; |
| uint32_t y = sc->y; |
| uint32_t width = sc->width; |
| uint32_t height = sc->height; |
| const char *label = sc->label; |
| float vf = sc->confidence; |
|
|
| for (auto c : bbs) { |
| |
| if (strcmp(c->label, label) != 0) continue; |
|
|
| if (ei_cube_check_overlap(c, x, y, width, height, vf)) { |
| has_overlapping = true; |
| break; |
| } |
| } |
|
|
| if (has_overlapping) { |
| continue; |
| } |
|
|
| bbs.push_back(sc); |
|
|
| ei_impulse_result_bounding_box_t tmp = { |
| .label = sc->label, |
| .x = (uint32_t)(sc->x * out_width_factor), |
| .y = (uint32_t)(sc->y * out_width_factor), |
| .width = (uint32_t)(sc->width * out_width_factor), |
| .height = (uint32_t)(sc->height * out_width_factor), |
| .value = sc->confidence |
| }; |
|
|
| results.push_back(tmp); |
| added_boxes_count++; |
| } |
|
|
| |
| if (added_boxes_count < object_detection_count) { |
| results.resize(object_detection_count); |
| for (size_t ix = added_boxes_count; ix < object_detection_count; ix++) { |
| results[ix].value = 0.0f; |
| } |
| } |
|
|
| for (auto c : *cubes) { |
| delete c; |
| } |
|
|
| result->bounding_boxes = results.data(); |
| result->bounding_boxes_count = added_boxes_count; |
| } |
|
|
| |
| |
| |
| EI_IMPULSE_ERROR process_classification_f32(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) |
| { |
| const ei_impulse_t *impulse = handle->impulse; |
|
|
| #ifdef EI_DSP_RESULT_OVERRIDE |
| uint32_t stop_count = EI_DSP_RESULT_OVERRIDE; |
| #else |
| uint32_t stop_count = impulse->label_count; |
| #endif |
|
|
| ei::matrix_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| for (uint32_t ix = 0; ix < stop_count; ix++) { |
| float value = raw_output_mtx->buffer[ix]; |
|
|
| #if EI_LOG_LEVEL == EI_LOG_LEVEL_DEBUG |
| ei_printf("%s:\t", impulse->categories[ix]); |
| ei_printf_float(value); |
| ei_printf("\n"); |
| #endif |
|
|
| |
| #ifndef EI_DSP_RESULT_OVERRIDE |
| result->classification[ix].label = impulse->categories[ix]; |
| #endif |
| result->classification[ix].value = value; |
| } |
|
|
| return EI_IMPULSE_OK; |
| } |
|
|
| |
| |
| |
| __attribute__((unused)) static EI_IMPULSE_ERROR process_classification_i8(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_classification_i8_config_t *config = (ei_fill_result_classification_i8_config_t*)config_ptr; |
|
|
| ei::matrix_i8_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| for (uint32_t ix = 0; ix < impulse->label_count; ix++) { |
| float value = static_cast<float>(raw_output_mtx->buffer[ix] - config->zero_point) * config->scale; |
|
|
| #if EI_LOG_LEVEL == EI_LOG_LEVEL_DEBUG |
| ei_printf("%s:\t", impulse->categories[ix]); |
| ei_printf_float(value); |
| ei_printf("\n"); |
| #endif |
| result->classification[ix].label = impulse->categories[ix]; |
| result->classification[ix].value = value; |
| } |
|
|
| return EI_IMPULSE_OK; |
| } |
|
|
| |
| |
| |
| __attribute__((unused)) static EI_IMPULSE_ERROR process_classification_u8(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_classification_i8_config_t *config = (ei_fill_result_classification_i8_config_t*)config_ptr; |
|
|
| |
| ei::matrix_u8_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| for (uint32_t ix = 0; ix < impulse->label_count; ix++) { |
| float value = static_cast<float>(raw_output_mtx->buffer[ix] - config->zero_point) * config->scale; |
|
|
| #if EI_LOG_LEVEL == EI_LOG_LEVEL_DEBUG |
| ei_printf("%s:\t", impulse->categories[ix]); |
| ei_printf_float(value); |
| ei_printf("\n"); |
| #endif |
|
|
| result->classification[ix].label = impulse->categories[ix]; |
| result->classification[ix].value = value; |
| } |
|
|
| return EI_IMPULSE_OK; |
| } |
|
|
| #if EI_CLASSIFIER_FREEFORM_OUTPUT == 1 |
| |
| |
| |
| EI_IMPULSE_ERROR process_freeform_f32(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) |
| { |
| const ei_impulse_t *impulse = handle->impulse; |
|
|
| if (handle->freeform_outputs == NULL) { |
| EI_LOGE("ERR: handle->freeform_outputs is NULL. You'll need to call ei_set_freeform_output before running your impulse.\n"); |
| return EI_IMPULSE_FREEFORM_OUTPUT_NULL; |
| } |
|
|
| for (size_t ix = 0; ix < impulse->freeform_outputs_size; ix++) { |
| ei::matrix_t* raw_output_mtx = NULL; |
| bool status = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id + ix, impulse->output_tensors_size); |
| if (!status) { |
| return EI_IMPULSE_POSTPROCESSING_ERROR; |
| } |
|
|
| matrix_t& freeform_output = handle->freeform_outputs[ix]; |
| |
| |
| if (freeform_output.rows * freeform_output.cols != raw_output_mtx->rows * raw_output_mtx->cols) { |
| return EI_IMPULSE_FREEFORM_OUTPUT_SIZE_MISMATCH; |
| } |
|
|
| memcpy(freeform_output.buffer, raw_output_mtx->buffer, raw_output_mtx->rows * raw_output_mtx->cols * sizeof(float)); |
| } |
|
|
| return EI_IMPULSE_OK; |
| } |
|
|
| |
| |
| |
| __attribute__((unused)) static EI_IMPULSE_ERROR process_freeform_i8(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_classification_i8_config_t *config = (ei_fill_result_classification_i8_config_t*)config_ptr; |
|
|
| if (handle->freeform_outputs == NULL) { |
| EI_LOGE("ERR: handle->freeform_outputs is NULL. You'll need to call ei_set_freeform_output before running your impulse.\n"); |
| return EI_IMPULSE_FREEFORM_OUTPUT_NULL; |
| } |
|
|
| for (size_t ix = 0; ix < impulse->freeform_outputs_size; ix++) { |
| ei::matrix_i8_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id + ix, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| matrix_t& freeform_output = handle->freeform_outputs[ix]; |
| if (freeform_output.rows * freeform_output.cols != raw_output_mtx->rows * raw_output_mtx->cols) { |
| |
| |
| return EI_IMPULSE_FREEFORM_OUTPUT_SIZE_MISMATCH; |
| } |
|
|
| for (uint32_t ix = 0; ix < freeform_output.rows * freeform_output.cols; ix++) { |
| float value = static_cast<float>(raw_output_mtx->buffer[ix] - config->zero_point) * config->scale; |
| freeform_output.buffer[ix] = value; |
| } |
| } |
|
|
| return EI_IMPULSE_OK; |
| } |
|
|
| |
| |
| |
| __attribute__((unused)) static EI_IMPULSE_ERROR process_freeform_u8(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
|
|
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_classification_i8_config_t *config = (ei_fill_result_classification_i8_config_t*)config_ptr; |
|
|
| if (handle->freeform_outputs == NULL) { |
| EI_LOGE("ERR: handle->freeform_outputs is NULL. You'll need to call ei_set_freeform_output before running your impulse.\n"); |
| return EI_IMPULSE_FREEFORM_OUTPUT_NULL; |
| } |
|
|
| for (size_t ix = 0; ix < impulse->freeform_outputs_size; ix++) { |
| ei::matrix_u8_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id + ix, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| matrix_t& freeform_output = handle->freeform_outputs[ix]; |
| if (freeform_output.rows * freeform_output.cols != raw_output_mtx->rows * raw_output_mtx->cols) { |
| |
| |
| return EI_IMPULSE_FREEFORM_OUTPUT_SIZE_MISMATCH; |
| } |
|
|
| for (uint32_t ix = 0; ix < freeform_output.rows * freeform_output.cols; ix++) { |
| float value = static_cast<float>(raw_output_mtx->buffer[ix] - config->zero_point) * config->scale; |
| freeform_output.buffer[ix] = value; |
| } |
| } |
|
|
| return EI_IMPULSE_OK; |
| } |
| #endif |
|
|
| |
| |
| |
| __attribute__((unused)) static EI_IMPULSE_ERROR process_anomaly(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| const ei_impulse_t *impulse = handle->impulse; |
|
|
| ei::matrix_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| result->anomaly = raw_output_mtx->buffer[0]; |
|
|
| return EI_IMPULSE_OK; |
| } |
|
|
| __attribute__((unused)) static EI_IMPULSE_ERROR process_fomo_f32(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| #if EI_HAS_FOMO |
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_fomo_f32_config_t *config = (ei_fill_result_fomo_f32_config_t*)config_ptr; |
|
|
| std::vector<ei_classifier_cube_t*> cubes; |
|
|
| int out_width_factor = impulse->input_width / config->out_width; |
|
|
| ei::matrix_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| for (size_t y = 0; y < config->out_width; y++) { |
| for (size_t x = 0; x < config->out_height; x++) { |
| size_t loc = ((y * config->out_height) + x) * (impulse->label_count + 1); |
|
|
| for (size_t ix = 1; ix < (size_t)impulse->label_count + 1; ix++) { |
| float vf = raw_output_mtx->buffer[loc+ix]; |
|
|
| ei_handle_cube(&cubes, x, y, vf, impulse->categories[ix - 1], config->threshold); |
| } |
| } |
| } |
|
|
| process_cubes(result, &cubes, out_width_factor, config->object_detection_count); |
|
|
| return EI_IMPULSE_OK; |
| #else |
| return EI_IMPULSE_LAST_LAYER_NOT_AVAILABLE; |
| #endif |
| } |
|
|
| __attribute__((unused)) static EI_IMPULSE_ERROR process_fomo_i8(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| #if EI_HAS_FOMO |
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_fomo_i8_config_t *config = (ei_fill_result_fomo_i8_config_t*)config_ptr; |
|
|
| std::vector<ei_classifier_cube_t*> cubes; |
|
|
| int out_width_factor = impulse->input_width / config->out_width; |
|
|
| ei::matrix_i8_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| for (size_t y = 0; y < config->out_width; y++) { |
| for (size_t x = 0; x < config->out_height; x++) { |
| size_t loc = ((y * config->out_height) + x) * (impulse->label_count + 1); |
|
|
| for (size_t ix = 1; ix < (size_t)impulse->label_count + 1; ix++) { |
| int8_t v = raw_output_mtx->buffer[loc+ix]; |
| float vf = static_cast<float>(v - config->zero_point) * config->scale; |
|
|
| ei_handle_cube(&cubes, x, y, vf, impulse->categories[ix - 1], config->threshold); |
| } |
| } |
| } |
|
|
| process_cubes(result, &cubes, out_width_factor, config->object_detection_count); |
|
|
| return EI_IMPULSE_OK; |
| #else |
| return EI_IMPULSE_LAST_LAYER_NOT_AVAILABLE; |
| #endif |
| } |
|
|
| |
| |
| |
| __attribute__((unused)) static EI_IMPULSE_ERROR process_visual_ad_f32(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| #if EI_CLASSIFIER_HAS_VISUAL_ANOMALY |
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_visual_ad_f32_config_t *config = (ei_fill_result_visual_ad_f32_config_t*)config_ptr; |
|
|
| float max_val = 0; |
| float sum_val = 0; |
|
|
| ei::matrix_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| for (uint32_t ix = 0; ix < config->grid_size_x * config->grid_size_y; ix++) { |
| float value = raw_output_mtx->buffer[ix]; |
| sum_val += value; |
| if (value > max_val) { |
| max_val = value; |
| } |
| } |
|
|
| result->visual_ad_result.mean_value = sum_val / (config->grid_size_x * config->grid_size_y); |
| result->visual_ad_result.max_value = max_val; |
|
|
| static ei_vector<ei_impulse_result_bounding_box_t> results; |
|
|
| results.clear(); |
|
|
| for (uint16_t x = 0; x <= config->grid_size_x - 1; x++) { |
| for (uint16_t y = 0; y <= config->grid_size_y - 1; y++) { |
| if (raw_output_mtx->buffer[(x * config->grid_size_x) + y] >= config->threshold) { |
| ei_impulse_result_bounding_box_t tmp = { |
| .label = "anomaly", |
| .x = static_cast<uint32_t>(y * (static_cast<float>(impulse->input_height) / config->grid_size_y)), |
| .y = static_cast<uint32_t>(x * (static_cast<float>(impulse->input_width) / config->grid_size_x)), |
| .width = (impulse->input_width / config->grid_size_x), |
| .height = (impulse->input_height / config->grid_size_y), |
| .value = raw_output_mtx->buffer[x * config->grid_size_x + y] |
| }; |
|
|
| results.push_back(tmp); |
| } |
| } |
| } |
|
|
| |
|
|
| result->visual_ad_grid_cells = results.data(); |
| result->visual_ad_count = results.size(); |
|
|
| #endif |
| return EI_IMPULSE_OK; |
| } |
|
|
|
|
|
|
| __attribute__((unused)) static EI_IMPULSE_ERROR process_ssd_f32(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| #if EI_HAS_SSD |
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_object_detection_f32_config_t *config = (ei_fill_result_object_detection_f32_config_t*)config_ptr; |
|
|
| static std::vector<ei_impulse_result_bounding_box_t> results; |
| int added_boxes_count = 0; |
| results.clear(); |
| results.resize(config->object_detection_count); |
|
|
| ei::matrix_t* data_mtx = NULL; |
| ei::matrix_t* scores_mtx = NULL; |
| ei::matrix_t* labels_mtx = NULL; |
|
|
| find_mtx_by_idx(result->_raw_outputs, &data_mtx, input_block_id + 1, impulse->output_tensors_size); |
| find_mtx_by_idx(result->_raw_outputs, &scores_mtx, input_block_id + 0, impulse->output_tensors_size); |
| find_mtx_by_idx(result->_raw_outputs, &labels_mtx, input_block_id + 3, impulse->output_tensors_size); |
|
|
| for (size_t ix = 0; ix < config->object_detection_count; ix++) { |
| float score = scores_mtx->buffer[ix]; |
| float label = labels_mtx->buffer[ix]; |
|
|
| if (score >= config->threshold) { |
| float ystart = data_mtx->buffer[(ix * 4) + 0]; |
| float xstart = data_mtx->buffer[(ix * 4) + 1]; |
| float yend = data_mtx->buffer[(ix * 4) + 2]; |
| float xend = data_mtx->buffer[(ix * 4) + 3]; |
|
|
| if (xstart < 0) xstart = 0; |
| if (xstart > 1) xstart = 1; |
| if (ystart < 0) ystart = 0; |
| if (ystart > 1) ystart = 1; |
| if (yend < 0) yend = 0; |
| if (yend > 1) yend = 1; |
| if (xend < 0) xend = 0; |
| if (xend > 1) xend = 1; |
| if (xend < xstart) xend = xstart; |
| if (yend < ystart) yend = ystart; |
|
|
| results[ix].label = impulse->categories[(uint32_t)label]; |
| results[ix].x = static_cast<uint32_t>(xstart * static_cast<float>(impulse->input_width)); |
| results[ix].y = static_cast<uint32_t>(ystart * static_cast<float>(impulse->input_height)); |
| results[ix].width = static_cast<uint32_t>((xend - xstart) * static_cast<float>(impulse->input_width)); |
| results[ix].height = static_cast<uint32_t>((yend - ystart) * static_cast<float>(impulse->input_height)); |
| results[ix].value = score; |
|
|
| added_boxes_count++; |
| } else { |
| results[ix].value = 0.0f; |
| } |
| } |
|
|
| result->bounding_boxes = results.data(); |
| result->bounding_boxes_count = added_boxes_count; |
|
|
| return EI_IMPULSE_OK; |
| #else |
| return EI_IMPULSE_LAST_LAYER_NOT_AVAILABLE; |
| #endif |
| } |
|
|
| __attribute__((unused)) static EI_IMPULSE_ERROR process_yolov5_f32(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| #if EI_HAS_YOLOV5 |
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_object_detection_f32_config_t *config = (ei_fill_result_object_detection_f32_config_t*)config_ptr; |
|
|
| ei::matrix_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| static std::vector<ei_impulse_result_bounding_box_t> results; |
| results.clear(); |
|
|
| size_t col_size = 5 + impulse->label_count; |
| size_t row_count = config->output_features_count / col_size; |
|
|
| for (size_t ix = 0; ix < row_count; ix++) { |
| size_t base_ix = ix * col_size; |
| float xc = raw_output_mtx->buffer[base_ix + 0]; |
| float yc = raw_output_mtx->buffer[base_ix + 1]; |
| float w = raw_output_mtx->buffer[base_ix + 2]; |
| float h = raw_output_mtx->buffer[base_ix + 3]; |
| float x = xc - (w / 2.0f); |
| float y = yc - (h / 2.0f); |
| if (x < 0) { |
| x = 0; |
| } |
| if (y < 0) { |
| y = 0; |
| } |
| if (x + w > impulse->input_width) { |
| w = impulse->input_width - x; |
| } |
| if (y + h > impulse->input_height) { |
| h = impulse->input_height - y; |
| } |
|
|
| if (w < 0 || h < 0) { |
| continue; |
| } |
|
|
| float score = raw_output_mtx->buffer[base_ix + 4]; |
|
|
| uint32_t label = 0; |
| float highest_value = 0.0f; |
| for (size_t lx = 0; lx < impulse->label_count; lx++) { |
| float l = raw_output_mtx->buffer[base_ix + 5 + lx]; |
| if (l > highest_value) { |
| label = lx; |
| highest_value = l; |
| } |
| } |
|
|
| if (score >= config->threshold && score <= 1.0f) { |
| ei_impulse_result_bounding_box_t r; |
| r.label = impulse->categories[label]; |
|
|
| if (config->version != 5) { |
| x *= static_cast<float>(impulse->input_width); |
| y *= static_cast<float>(impulse->input_height); |
| w *= static_cast<float>(impulse->input_width); |
| h *= static_cast<float>(impulse->input_height); |
| } |
|
|
| r.x = static_cast<uint32_t>(x); |
| r.y = static_cast<uint32_t>(y); |
| r.width = static_cast<uint32_t>(w); |
| r.height = static_cast<uint32_t>(h); |
| r.value = score; |
| results.push_back(r); |
| } |
| } |
|
|
| EI_IMPULSE_ERROR nms_res = ei_run_nms(impulse, &config->nms_config, &results); |
| if (nms_res != EI_IMPULSE_OK) { |
| return nms_res; |
| } |
|
|
| |
| size_t added_boxes_count = results.size(); |
| size_t min_object_detection_count = config->object_detection_count; |
| if (added_boxes_count < min_object_detection_count) { |
| results.resize(min_object_detection_count); |
| for (size_t ix = added_boxes_count; ix < min_object_detection_count; ix++) { |
| results[ix].value = 0.0f; |
| } |
| } |
|
|
| result->bounding_boxes = results.data(); |
| result->bounding_boxes_count = added_boxes_count; |
|
|
| return EI_IMPULSE_OK; |
| #else |
| return EI_IMPULSE_LAST_LAYER_NOT_AVAILABLE; |
| #endif |
| } |
|
|
| __attribute__((unused)) static EI_IMPULSE_ERROR process_yolov5_i8(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| #if EI_HAS_YOLOV5 |
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_object_detection_i8_config_t *config = (ei_fill_result_object_detection_i8_config_t*)config_ptr; |
|
|
| |
| ei::matrix_u8_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| static std::vector<ei_impulse_result_bounding_box_t> results; |
| results.clear(); |
|
|
| size_t col_size = 5 + impulse->label_count; |
| size_t row_count = config->output_features_count / col_size; |
|
|
| for (size_t ix = 0; ix < row_count; ix++) { |
| size_t base_ix = ix * col_size; |
| float xc = (raw_output_mtx->buffer[base_ix + 0] - config->zero_point) * config->scale; |
| float yc = (raw_output_mtx->buffer[base_ix + 1] - config->zero_point) * config->scale; |
| float w = (raw_output_mtx->buffer[base_ix + 2] - config->zero_point) * config->scale; |
| float h = (raw_output_mtx->buffer[base_ix + 3] - config->zero_point) * config->scale; |
| float x = xc - (w / 2.0f); |
| float y = yc - (h / 2.0f); |
| if (x < 0) { |
| x = 0; |
| } |
| if (y < 0) { |
| y = 0; |
| } |
| if (x + w > impulse->input_width) { |
| w = impulse->input_width - x; |
| } |
| if (y + h > impulse->input_height) { |
| h = impulse->input_height - y; |
| } |
|
|
| if (w < 0 || h < 0) { |
| continue; |
| } |
|
|
| float score = (raw_output_mtx->buffer[base_ix + 4] - config->zero_point) * config->scale; |
|
|
| uint32_t label = 0; |
| float highest_value = 0.0f; |
| for (size_t lx = 0; lx < impulse->label_count; lx++) { |
| float l = raw_output_mtx->buffer[base_ix + 5 + lx]; |
| if (l > highest_value) { |
| label = lx; |
| highest_value = l; |
| } |
| } |
|
|
| if (score >= config->threshold && score <= 1.0f) { |
| ei_impulse_result_bounding_box_t r; |
| r.label = impulse->categories[label]; |
|
|
| if (config->version != 5) { |
| x *= static_cast<float>(impulse->input_width); |
| y *= static_cast<float>(impulse->input_height); |
| w *= static_cast<float>(impulse->input_width); |
| h *= static_cast<float>(impulse->input_height); |
| } |
|
|
| r.x = static_cast<uint32_t>(x); |
| r.y = static_cast<uint32_t>(y); |
| r.width = static_cast<uint32_t>(w); |
| r.height = static_cast<uint32_t>(h); |
| r.value = score; |
| results.push_back(r); |
| } |
| } |
|
|
| EI_IMPULSE_ERROR nms_res = ei_run_nms(impulse, &config->nms_config, &results); |
| if (nms_res != EI_IMPULSE_OK) { |
| return nms_res; |
| } |
|
|
| |
| size_t added_boxes_count = results.size(); |
| size_t min_object_detection_count = config->object_detection_count; |
| if (added_boxes_count < min_object_detection_count) { |
| results.resize(min_object_detection_count); |
| for (size_t ix = added_boxes_count; ix < min_object_detection_count; ix++) { |
| results[ix].value = 0.0f; |
| } |
| } |
|
|
| result->bounding_boxes = results.data(); |
| result->bounding_boxes_count = added_boxes_count; |
|
|
| return EI_IMPULSE_OK; |
| #else |
| return EI_IMPULSE_LAST_LAYER_NOT_AVAILABLE; |
| #endif |
| } |
|
|
| __attribute__((unused)) static EI_IMPULSE_ERROR process_yolox_f32(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| #if EI_HAS_YOLOX |
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_object_detection_f32_config_t *config = (ei_fill_result_object_detection_f32_config_t*)config_ptr; |
|
|
| ei::matrix_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| static std::vector<ei_impulse_result_bounding_box_t> results; |
| results.clear(); |
|
|
| |
|
|
| |
| |
| |
| |
| const std::vector<int> strides { 8, 16, 32 }; |
|
|
| |
| |
| std::vector<int> hsizes(strides.size()); |
| std::vector<int> wsizes(strides.size()); |
| for (int ix = 0; ix < (int)strides.size(); ix++) { |
| hsizes[ix] = (int)floor((float)impulse->input_width / (float)strides[ix]); |
| wsizes[ix] = (int)floor((float)impulse->input_height / (float)strides[ix]); |
| } |
|
|
| |
| |
| |
| |
| |
| std::vector<ei::matrix_i32_t*> grids; |
| std::vector<ei::matrix_i32_t*> expanded_strides; |
|
|
| for (int ix = 0; ix < (int)strides.size(); ix++) { |
| int hsize = hsizes.at(ix); |
| int wsize = wsizes.at(ix); |
| int stride = strides.at(ix); |
|
|
| |
| |
| ei::matrix_i32_t *grid = new ei::matrix_i32_t(hsize * wsize, 2); |
| int grid_ix = 0; |
| for (int h = 0; h < hsize; h++) { |
| for (int w = 0; w < wsize; w++) { |
| grid->buffer[grid_ix + 0] = w; |
| grid->buffer[grid_ix + 1] = h; |
| grid_ix += 2; |
| } |
| } |
| grids.push_back(grid); |
|
|
| |
| |
| ei::matrix_i32_t *expanded_stride = new ei::matrix_i32_t(hsize * wsize, 1); |
| for (int ix = 0; ix < hsize * wsize; ix++) { |
| expanded_stride->buffer[ix] = stride; |
| } |
| expanded_strides.push_back(expanded_stride); |
| } |
|
|
| |
| int total_grid_rows = 0; |
| for (auto g : grids) { |
| total_grid_rows += g->rows; |
| } |
| ei::matrix_i32_t c_grid(total_grid_rows, 2); |
| int c_grid_ix = 0; |
| for (auto g : grids) { |
| for (int row = 0; row < (int)g->rows; row++) { |
| c_grid.buffer[c_grid_ix + 0] = g->buffer[(row * 2) + 0]; |
| c_grid.buffer[c_grid_ix + 1] = g->buffer[(row * 2) + 1]; |
| c_grid_ix += 2; |
| } |
| delete g; |
| } |
|
|
| |
| int total_stride_rows = 0; |
| for (auto g : expanded_strides) { |
| total_stride_rows += g->rows; |
| } |
| ei::matrix_i32_t c_expanded_strides(total_stride_rows, 1); |
| int c_expanded_strides_ix = 0; |
| for (auto g : expanded_strides) { |
| for (int row = 0; row < (int)g->rows; row++) { |
| c_expanded_strides.buffer[c_expanded_strides_ix + 0] = g->buffer[(row * 1) + 0]; |
| c_expanded_strides_ix += 1; |
| } |
| delete g; |
| } |
|
|
| const int output_rows = config->output_features_count / (5 + impulse->label_count); |
| ei::matrix_t outputs(output_rows, 5 + impulse->label_count, raw_output_mtx->buffer); |
| for (int row = 0; row < (int)outputs.rows; row++) { |
| float v0 = outputs.buffer[(row * outputs.cols) + 0]; |
| float v1 = outputs.buffer[(row * outputs.cols) + 1]; |
| float v2 = outputs.buffer[(row * outputs.cols) + 2]; |
| float v3 = outputs.buffer[(row * outputs.cols) + 3]; |
|
|
| float cgrid0 = (float)c_grid.buffer[(row * c_grid.cols) + 0]; |
| float cgrid1 = (float)c_grid.buffer[(row * c_grid.cols) + 1]; |
|
|
| float stride = (float)c_expanded_strides.buffer[row]; |
|
|
| |
| outputs.buffer[(row * outputs.cols) + 0] = (v0 + cgrid0) * stride; |
| outputs.buffer[(row * outputs.cols) + 1] = (v1 + cgrid1) * stride; |
|
|
| |
| outputs.buffer[(row * outputs.cols) + 2] = exp(v2) * stride; |
| outputs.buffer[(row * outputs.cols) + 3] = exp(v3) * stride; |
| } |
|
|
| |
|
|
| |
| ei::matrix_t boxes(outputs.rows, 4); |
| for (int row = 0; row < (int)outputs.rows; row++) { |
| boxes.buffer[(row * boxes.cols) + 0] = outputs.buffer[(row * outputs.cols) + 0]; |
| boxes.buffer[(row * boxes.cols) + 1] = outputs.buffer[(row * outputs.cols) + 1]; |
| boxes.buffer[(row * boxes.cols) + 2] = outputs.buffer[(row * outputs.cols) + 2]; |
| boxes.buffer[(row * boxes.cols) + 3] = outputs.buffer[(row * outputs.cols) + 3]; |
| } |
|
|
| |
| ei::matrix_t scores(outputs.rows, impulse->label_count); |
| for (int row = 0; row < (int)outputs.rows; row++) { |
| float confidence = outputs.buffer[(row * outputs.cols) + 4]; |
| for (int cc = 0; cc < impulse->label_count; cc++) { |
| scores.buffer[(row * scores.cols) + cc] = confidence * outputs.buffer[(row * outputs.cols) + (5 + cc)]; |
| } |
| } |
|
|
| |
| for (int row = 0; row < (int)scores.rows; row++) { |
| for (int col = 0; col < (int)scores.cols; col++) { |
| float confidence = scores.buffer[(row * scores.cols) + col]; |
|
|
| if (confidence >= config->threshold && confidence <= 1.0f) { |
| ei_impulse_result_bounding_box_t r; |
| r.label = impulse->categories[col]; |
| r.value = confidence; |
|
|
| |
| float xcenter = boxes.buffer[(row * boxes.cols) + 0]; |
| float ycenter = boxes.buffer[(row * boxes.cols) + 1]; |
| float width = boxes.buffer[(row * boxes.cols) + 2]; |
| float height = boxes.buffer[(row * boxes.cols) + 3]; |
|
|
| int x = (int)(xcenter - (width / 2.0f)); |
| int y = (int)(ycenter - (height / 2.0f)); |
|
|
| if (x < 0) { |
| x = 0; |
| } |
| if (x > (int)impulse->input_width) { |
| x = impulse->input_width; |
| } |
| if (y < 0) { |
| y = 0; |
| } |
| if (y > (int)impulse->input_height) { |
| y = impulse->input_height; |
| } |
|
|
| r.x = x; |
| r.y = y; |
| r.width = (int)round(width); |
| r.height = (int)round(height); |
|
|
| results.push_back(r); |
| } |
| } |
| } |
|
|
| EI_IMPULSE_ERROR nms_res = ei_run_nms(impulse, &config->nms_config, &results); |
| if (nms_res != EI_IMPULSE_OK) { |
| return nms_res; |
| } |
|
|
| |
| size_t added_boxes_count = results.size(); |
| size_t min_object_detection_count = config->object_detection_count; |
| if (added_boxes_count < min_object_detection_count) { |
| results.resize(min_object_detection_count); |
| for (size_t ix = added_boxes_count; ix < min_object_detection_count; ix++) { |
| results[ix].value = 0.0f; |
| } |
| } |
|
|
| result->bounding_boxes = results.data(); |
| result->bounding_boxes_count = added_boxes_count; |
|
|
| return EI_IMPULSE_OK; |
| #else |
| return EI_IMPULSE_LAST_LAYER_NOT_AVAILABLE; |
| #endif |
| } |
|
|
| |
| |
| |
| |
|
|
| __attribute__((unused)) static EI_IMPULSE_ERROR process_yolox_detect_f32(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| #if EI_HAS_YOLOX |
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_object_detection_f32_config_t *config = (ei_fill_result_object_detection_f32_config_t*)config_ptr; |
|
|
| ei::matrix_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| static std::vector<ei_impulse_result_bounding_box_t> results; |
| results.clear(); |
|
|
| |
| const int output_rows = config->output_features_count / 6; |
| ei::matrix_t outputs(output_rows, 6, raw_output_mtx->buffer); |
|
|
| |
| for (int row = 0; row < (int)outputs.rows; row++) { |
| float confidence = outputs.buffer[(row * outputs.cols) + 4]; |
| int class_idx = (int)outputs.buffer[(row * outputs.cols) + 5]; |
|
|
| if (confidence >= config->threshold && confidence <= 1.0f) { |
| ei_impulse_result_bounding_box_t r; |
| r.label = impulse->categories[class_idx]; |
| r.value = confidence; |
|
|
| |
| float xmin = outputs.buffer[(row * outputs.cols) + 0]; |
| float ymin = outputs.buffer[(row * outputs.cols) + 1]; |
| float xmax = outputs.buffer[(row * outputs.cols) + 2]; |
| float ymax = outputs.buffer[(row * outputs.cols) + 3]; |
|
|
| float width = xmax - xmin; |
| float height = ymax - ymin; |
|
|
| int x = (int)xmin; |
| int y = (int)ymin; |
|
|
| if (x < 0) { |
| x = 0; |
| } |
| if (x > (int)impulse->input_width) { |
| x = impulse->input_width; |
| } |
| if (y < 0) { |
| y = 0; |
| } |
| if (y > (int)impulse->input_height) { |
| y = impulse->input_height; |
| } |
|
|
| r.x = x; |
| r.y = y; |
| r.width = (int)round(width); |
| r.height = (int)round(height); |
|
|
| results.push_back(r); |
| } |
| } |
|
|
| result->bounding_boxes = results.data(); |
| result->bounding_boxes_count = results.size(); |
|
|
| return EI_IMPULSE_OK; |
| #else |
| return EI_IMPULSE_LAST_LAYER_NOT_AVAILABLE; |
| #endif |
| } |
|
|
| __attribute__((unused)) static EI_IMPULSE_ERROR process_yolov7_f32(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| #if EI_HAS_YOLOV7 |
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_object_detection_f32_config_t *config = (ei_fill_result_object_detection_f32_config_t*)config_ptr; |
|
|
| ei::matrix_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| static std::vector<ei_impulse_result_bounding_box_t> results; |
| results.clear(); |
|
|
| size_t col_size = 7; |
| |
| size_t row_count = raw_output_mtx->cols / col_size; |
|
|
| |
| |
| for (size_t ix = 0; ix < row_count; ix++) { |
| size_t base_ix = ix * col_size; |
| float xmin = raw_output_mtx->buffer[base_ix + 1]; |
| float ymin = raw_output_mtx->buffer[base_ix + 2]; |
| float xmax = raw_output_mtx->buffer[base_ix + 3]; |
| float ymax = raw_output_mtx->buffer[base_ix + 4]; |
| uint32_t label = (uint32_t)raw_output_mtx->buffer[base_ix + 5]; |
| float score = raw_output_mtx->buffer[base_ix + 6]; |
|
|
| if (score >= config->threshold && score <= 1.0f) { |
| ei_impulse_result_bounding_box_t r; |
| r.label = impulse->categories[label]; |
|
|
| r.x = static_cast<uint32_t>(xmin); |
| r.y = static_cast<uint32_t>(ymin); |
| r.width = static_cast<uint32_t>(xmax - xmin); |
| r.height = static_cast<uint32_t>(ymax - ymin); |
| r.value = score; |
| results.push_back(r); |
| } |
| } |
|
|
| |
| size_t added_boxes_count = results.size(); |
| size_t min_object_detection_count = config->object_detection_count; |
| if (added_boxes_count < min_object_detection_count) { |
| results.resize(min_object_detection_count); |
| for (size_t ix = added_boxes_count; ix < min_object_detection_count; ix++) { |
| results[ix].value = 0.0f; |
| } |
| } |
|
|
| result->bounding_boxes = results.data(); |
| result->bounding_boxes_count = added_boxes_count; |
|
|
| return EI_IMPULSE_OK; |
| #else |
| return EI_IMPULSE_LAST_LAYER_NOT_AVAILABLE; |
| #endif |
| } |
|
|
| __attribute__((unused)) inline float sigmoid(float a) { |
| return 1.0f / (1.0f + exp(-a)); |
| } |
|
|
| #if EI_HAS_YOLOV2 |
| |
| |
| __attribute__((unused)) static void softmax(std::vector<float>& input, const size_t nb_classes) |
| { |
| const float max = *std::max_element(input.begin(), input.end()); |
| const float min = *std::min_element(input.begin(), input.end()); |
| const float t = -100.0f; |
|
|
| |
| std::transform(input.begin(), input.end(), input.begin(), |
| [max](float x) { return x - max; }); |
|
|
| |
| std::transform(input.begin(), input.end(), input.begin(), |
| [min, t](float x) { return x < t ? (x / min * t): x; }); |
|
|
| |
| |
| std::transform(input.begin(), input.end(), input.begin(), |
| [](float x) { return std::exp(x); }); |
|
|
| |
| |
| for(auto it = input.begin(); it != input.end(); it += nb_classes) { |
| float sum = 0.0f; |
| |
| for(auto it2 = it; it2 != it + nb_classes; it2++) { |
| sum += *it2; |
| } |
| |
| std::transform(it, it + nb_classes, it, |
| [sum](float ex) { return ex / sum; }); |
| } |
| } |
|
|
| class BoundingBox { |
| public: |
| float x1, y1, x2, y2, confidence; |
| std::vector<float> classes; |
|
|
| BoundingBox(float x1, float y1, float x2, float y2, float confidence, const std::vector<float>& classes) |
| : x1(x1), y1(y1), x2(x2), y2(y2), confidence(confidence), classes(classes) {} |
|
|
| float get_score() const { |
| return confidence; |
| } |
|
|
| int get_label() const { |
| auto maxElementIndex = std::max_element(classes.begin(), classes.end()) - classes.begin(); |
| return maxElementIndex; |
| } |
|
|
| float _interval_overlap(float x1, float x2, float x3, float x4) const { |
| if(x3 < x1) { |
| if(x4 < x1) { |
| return 0; |
| } |
| return std::min(x2, x4) - x1; |
| } |
| if(x2 < x3) { |
| return 0; |
| } |
| return std::min(x2, x4) - x3; |
| } |
|
|
|
|
| float iou(const BoundingBox& other) const { |
| |
| float intersect_w = this->_interval_overlap(this->x1, this->x2, other.x1, other.x2); |
| float intersect_h = this->_interval_overlap(this->y1, this->y2, other.y1, other.y2); |
|
|
| float intersect = intersect_w * intersect_h; |
|
|
| float w1 = this->x2 - this->x1; |
| float h1 = this->y2 - this->y1; |
| float w2 = other.x2 - other.x1; |
| float h2 = other.y2 - other.y1; |
|
|
| float un = w1 * h1 + w2 * h2 - intersect; |
|
|
| return float(intersect) / un; |
| } |
| }; |
| #endif |
|
|
| __attribute__((unused)) static EI_IMPULSE_ERROR process_yolov2_f32(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| #if EI_HAS_YOLOV2 |
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_object_detection_f32_config_t *config = (ei_fill_result_object_detection_f32_config_t*)config_ptr; |
|
|
| ei::matrix_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| static std::vector<ei_impulse_result_bounding_box_t> results; |
| results.clear(); |
|
|
| |
| |
| |
| const size_t grid_h = 7; |
| const size_t grid_w = 7; |
| const size_t nb_box = 5; |
| const std::vector<std::pair<float, float>> anchors = {{0.56594, 1.05012}, {1.0897, 2.03908}, {2.37823, 3.00376}, {2.4593, 4.913}, {5.15981, 5.56699}}; |
|
|
| const size_t nb_classes = impulse->label_count; |
| const float obj_threshold = 0.5; |
| const float nms_threshold = 0.5; |
| std::vector<float> output; |
| const int stride = 4 + 1 + nb_classes; |
|
|
| output.assign(raw_output_mtx->buffer, raw_output_mtx->buffer + config->output_features_count); |
|
|
| |
| std::vector<BoundingBox> boxes; |
|
|
| |
| std::vector<float> classes_confidences; |
| const size_t dim = 5; |
| for(auto it = output.begin() + dim; it <= output.end(); it += (dim + nb_classes)) { |
| classes_confidences.insert(classes_confidences.end(), it, it + nb_classes); |
| } |
| |
| softmax(classes_confidences, nb_classes); |
|
|
| for (size_t row = 0; row < grid_h; ++row) { |
| for (size_t col = 0; col < grid_w; ++col) { |
| for (size_t b = 0; b < nb_box; ++b) { |
| size_t idx = row * grid_w * nb_box * stride + col * nb_box * stride + b * stride; |
| size_t classes_idx = row * grid_w * nb_box * nb_classes + col * nb_box * nb_classes + b * nb_classes; |
|
|
| |
| |
| float sigmoid_val = sigmoid(output[idx + 4]); |
| output[idx + 4] = sigmoid_val; |
|
|
| |
| std::vector<float> classes(classes_confidences.begin() + classes_idx, classes_confidences.begin() + classes_idx + nb_classes); |
|
|
| |
| |
| std::transform(classes.begin(), classes.end(), classes.begin(), |
| [sigmoid_val, obj_threshold](float c) { c *= sigmoid_val; return c > obj_threshold ? c : 0.0f; }); |
|
|
| |
| float sum = 0.0f; |
| for(auto it = classes.begin(); it != classes.end(); it++) { |
| sum += *it; |
| } |
| if(sum > 0.0f) { |
| |
| float x = output[idx + 0]; |
| float y = output[idx + 1]; |
| float w = output[idx + 2]; |
| float h = output[idx + 3]; |
|
|
| |
| x = (col + sigmoid(x)) / grid_w; |
| |
| y = (row + sigmoid(y)) / grid_h; |
| |
| w = anchors[b].first * std::exp(w) / grid_w; |
| |
| h = anchors[b].second * std::exp(h) / grid_h; |
|
|
| |
| float confidence = output[idx + 4]; |
|
|
| |
| float x1 = std::max(x - w / 2, 0.0f); |
| |
| float y1 = std::max(y - h / 2, 0.0f); |
| |
| float x2 = std::min(x + w / 2, static_cast<float>(grid_w)); |
| |
| float y2 = std::min(y + h / 2, static_cast<float>(grid_h)); |
|
|
| boxes.emplace_back(x1, y1, x2, y2, confidence, classes); |
| } |
| } |
| } |
| } |
|
|
| |
| for (size_t c = 0; c < nb_classes; ++c) { |
| std::vector<std::pair<float, int>> sorted_indices; |
| for (size_t i = 0; i < boxes.size(); ++i) { |
| sorted_indices.emplace_back(boxes[i].classes[c], i); |
| } |
|
|
| std::sort(sorted_indices.begin(), sorted_indices.end(), |
| [](const std::pair<float, int>& a, const std::pair<float, int>& b) { |
| return a.first > b.first; |
| }); |
|
|
| for (size_t i = 0; i < sorted_indices.size(); ++i) { |
| int index_i = sorted_indices[i].second; |
| if (boxes[index_i].classes[c] == 0) |
| continue; |
|
|
| for (size_t j = i + 1; j < sorted_indices.size(); ++j) { |
| int index_j = sorted_indices[j].second; |
|
|
| if ((boxes[index_i].iou(boxes[index_j]) >= nms_threshold) && |
| (boxes[index_i].get_label() == (int)c) && |
| (boxes[index_j].get_label() == (int)c)) { |
| boxes[index_j].confidence = 0; |
| } |
| } |
| } |
| } |
|
|
| |
| boxes.erase(std::remove_if(boxes.begin(), boxes.end(), |
| [obj_threshold](const BoundingBox& box) { |
| return box.get_score() <= obj_threshold; |
| }), boxes.end()); |
|
|
| |
| std::sort(boxes.begin(), boxes.end(), |
| [](const BoundingBox& a, const BoundingBox& b) { |
| return a.get_score() > b.get_score(); |
| }); |
|
|
| |
| for(auto & box: boxes) { |
| ei_impulse_result_bounding_box_t res; |
| res.label = impulse->categories[box.get_label()]; |
| res.x = ceil(box.x1 * impulse->input_width); |
| res.y = ceil(box.y1 * impulse->input_height); |
| res.width = ceil((box.x2 - box.x1) * impulse->input_width); |
| res.height = ceil((box.y2 - box.y1) * impulse->input_height); |
| res.value = box.get_score(); |
| results.push_back(res); |
| } |
|
|
| |
| size_t added_boxes_count = results.size(); |
| size_t min_object_detection_count = config->object_detection_count; |
| if (added_boxes_count < min_object_detection_count) { |
| results.resize(min_object_detection_count); |
| for (size_t ix = added_boxes_count; ix < min_object_detection_count; ix++) { |
| results[ix].value = 0.0f; |
| } |
| } |
|
|
| result->bounding_boxes = results.data(); |
| result->bounding_boxes_count = added_boxes_count; |
|
|
| return EI_IMPULSE_OK; |
| #else |
| return EI_IMPULSE_LAST_LAYER_NOT_AVAILABLE; |
| #endif |
| } |
|
|
| #if EI_HAS_TAO_DECODE_DETECTIONS |
| template<typename T> |
| __attribute__((unused)) static EI_IMPULSE_ERROR process_tao_decode_detections_common(const ei_impulse_t *impulse, |
| ei_impulse_result_t *result, |
| T *data, |
| float zero_point, |
| float scale, |
| size_t output_features_count, |
| float threshold, |
| size_t object_detection_count, |
| ei_object_detection_nms_config_t nms_config) { |
|
|
| size_t col_size = 12 + impulse->label_count + 1; |
| size_t row_count = output_features_count / col_size; |
|
|
| static std::vector<ei_impulse_result_bounding_box_t> results; |
| static std::vector<ei_impulse_result_bounding_box_t> class_results; |
| results.clear(); |
|
|
| for (size_t cls_idx = 1; cls_idx < (size_t)(impulse->label_count + 1); cls_idx++) { |
|
|
| std::vector<float> boxes; |
| std::vector<float> scores; |
| std::vector<int> classes; |
| class_results.clear(); |
|
|
| for (size_t ix = 0; ix < row_count; ix++) { |
|
|
| float score = (static_cast<float>(data[ix * col_size + cls_idx]) - zero_point) * scale; |
|
|
| if ((score < threshold) || (score > 1.0f)) { |
| continue; |
| } |
|
|
| |
| size_t base_ix = ix * col_size + col_size; |
|
|
| float r_12 = (static_cast<float>(data[base_ix - 12]) - zero_point) * scale; |
| float r_11 = (static_cast<float>(data[base_ix - 11]) - zero_point) * scale; |
| float r_10 = (static_cast<float>(data[base_ix - 10]) - zero_point) * scale; |
| float r_9 = (static_cast<float>(data[base_ix - 9]) - zero_point) * scale; |
| float r_8 = (static_cast<float>(data[base_ix - 8]) - zero_point) * scale; |
| float r_7 = (static_cast<float>(data[base_ix - 7]) - zero_point) * scale; |
| float r_6 = (static_cast<float>(data[base_ix - 6]) - zero_point) * scale; |
| float r_5 = (static_cast<float>(data[base_ix - 5]) - zero_point) * scale; |
| float r_4 = (static_cast<float>(data[base_ix - 4]) - zero_point) * scale; |
| float r_3 = (static_cast<float>(data[base_ix - 3]) - zero_point) * scale; |
| float r_2 = (static_cast<float>(data[base_ix - 2]) - zero_point) * scale; |
| float r_1 = (static_cast<float>(data[base_ix - 1]) - zero_point) * scale; |
|
|
| |
| |
| |
| |
| float cx_pred = r_12; |
| float cy_pred = r_11; |
| float w_pred = r_10; |
| float h_pred = r_9; |
|
|
| |
| |
| float w_anchor = r_6 - r_8; |
| float h_anchor = r_5 - r_7; |
|
|
| |
| |
| float cx_anchor = (r_6 + r_8) / 2.0f; |
| float cy_anchor = (r_5 + r_7) / 2.0f; |
|
|
| |
| |
| float cx_variance = r_4; |
| float cy_variance = r_3; |
|
|
| |
| |
| float variance_w = r_2; |
| float variance_h = r_1; |
|
|
| |
| |
| |
| |
| |
| float cx = cx_pred * cx_variance * w_anchor + cx_anchor; |
| float cy = cy_pred * cy_variance * h_anchor + cy_anchor; |
| float w = exp(w_pred * variance_w) * w_anchor; |
| float h = exp(h_pred * variance_h) * h_anchor; |
|
|
| |
| float xmin = cx - (w / 2.0f); |
| float ymin = cy - (h / 2.0f); |
| float xmax = cx + (w / 2.0f); |
| float ymax = cy + (h / 2.0f); |
|
|
| xmin *= impulse->input_width; |
| ymin *= impulse->input_height; |
| xmax *= impulse->input_width; |
| ymax *= impulse->input_height; |
|
|
| boxes.push_back(ymin); |
| boxes.push_back(xmin); |
| boxes.push_back(ymax); |
| boxes.push_back(xmax); |
| scores.push_back(score); |
| classes.push_back((int)(cls_idx-1)); |
| } |
|
|
| size_t nr_boxes = scores.size(); |
| EI_IMPULSE_ERROR nms_res = ei_run_nms(impulse, |
| &class_results, |
| boxes.data(), |
| scores.data(), |
| classes.data(), |
| nr_boxes, |
| true , |
| &nms_config); |
|
|
| if (nms_res != EI_IMPULSE_OK) { |
| return nms_res; |
| } |
|
|
| for (auto bb: class_results) { |
| results.push_back(bb); |
| } |
| } |
|
|
| prepare_nms_results_common(object_detection_count, result, &results); |
|
|
| return EI_IMPULSE_OK; |
| } |
| #endif |
|
|
| #if EI_HAS_TAO_YOLOV3 |
| template<typename T> |
| __attribute__((unused)) static EI_IMPULSE_ERROR process_tao_yolov3_common(const ei_impulse_t *impulse, |
| ei_impulse_result_t *result, |
| T *data, |
| float zero_point, |
| float scale, |
| size_t output_features_count, |
| float threshold, |
| size_t object_detection_count, |
| ei_object_detection_nms_config_t nms_config) { |
| |
| |
| size_t col_size = 11 + impulse->label_count; |
| size_t row_count = output_features_count / col_size; |
|
|
| static std::vector<ei_impulse_result_bounding_box_t> results; |
| static std::vector<ei_impulse_result_bounding_box_t> class_results; |
|
|
| results.clear(); |
| for (size_t cls_idx = 0; cls_idx < (size_t)impulse->label_count; cls_idx++) { |
|
|
| std::vector<float> boxes; |
| std::vector<float> scores; |
| std::vector<int> classes; |
| class_results.clear(); |
|
|
| for (size_t ix = 0; ix < row_count; ix++) { |
| size_t data_ix = ix * col_size; |
| float r_0 = (static_cast<float>(data[data_ix + 0]) - zero_point) * scale; |
| float r_1 = (static_cast<float>(data[data_ix + 1]) - zero_point) * scale; |
| float r_2 = (static_cast<float>(data[data_ix + 2]) - zero_point) * scale; |
| float r_3 = (static_cast<float>(data[data_ix + 3]) - zero_point) * scale; |
| float r_4 = (static_cast<float>(data[data_ix + 4]) - zero_point) * scale; |
| float r_5 = (static_cast<float>(data[data_ix + 5]) - zero_point) * scale; |
| float r_6 = (static_cast<float>(data[data_ix + 6]) - zero_point) * scale; |
| float r_7 = (static_cast<float>(data[data_ix + 7]) - zero_point) * scale; |
| float r_8 = (static_cast<float>(data[data_ix + 8]) - zero_point) * scale; |
| float r_9 = (static_cast<float>(data[data_ix + 9]) - zero_point) * scale; |
| float r_10 = (static_cast<float>(data[data_ix + 10]) - zero_point) * scale; |
|
|
| float cls = (static_cast<float>(data[data_ix + 11 + cls_idx]) - zero_point) * scale; |
| float score = sigmoid(cls) * sigmoid(r_10); |
|
|
| if ((score < threshold) || (score > 1.0f)) { |
| continue; |
| } |
|
|
| float by = r_0 + sigmoid(r_6) * r_4; |
| float bx = r_1 + sigmoid(r_7) * r_5; |
| float bh = r_2 * exp(r_8); |
| float bw = r_3 * exp(r_9); |
|
|
| float ymin = by - 0.5 * bh; |
| float xmin = bx - 0.5 * bw; |
| float ymax = by + 0.5 * bh; |
| float xmax = bx + 0.5 * bw; |
|
|
| |
| ymin *= impulse->input_height; |
| xmin *= impulse->input_width; |
| ymax *= impulse->input_height; |
| xmax *= impulse->input_width; |
|
|
| boxes.push_back(ymin); |
| boxes.push_back(xmin); |
| boxes.push_back(ymax); |
| boxes.push_back(xmax); |
| scores.push_back(score); |
| classes.push_back((int)cls_idx); |
| } |
|
|
| size_t nr_boxes = scores.size(); |
| EI_IMPULSE_ERROR nms_res = ei_run_nms(impulse, |
| &class_results, |
| boxes.data(), |
| scores.data(), |
| classes.data(), |
| nr_boxes, |
| true , |
| &nms_config); |
| if (nms_res != EI_IMPULSE_OK) { |
| return nms_res; |
| } |
|
|
| for (auto bb: class_results) { |
| results.push_back(bb); |
| } |
| } |
|
|
| prepare_nms_results_common(object_detection_count, result, &results); |
| return EI_IMPULSE_OK; |
| } |
| #endif |
|
|
| #if EI_HAS_TAO_YOLOV4 |
| template<typename T> |
| __attribute__((unused)) static EI_IMPULSE_ERROR process_tao_yolov4_common(const ei_impulse_t *impulse, |
| ei_impulse_result_t *result, |
| T *data, |
| float zero_point, |
| float scale, |
| size_t output_features_count, |
| float threshold, |
| size_t object_detection_count, |
| ei_object_detection_nms_config_t nms_config) { |
| |
| |
| size_t col_size = 11 + impulse->label_count; |
| size_t row_count = output_features_count / col_size; |
|
|
| static std::vector<ei_impulse_result_bounding_box_t> results; |
| static std::vector<ei_impulse_result_bounding_box_t> class_results; |
| results.clear(); |
|
|
| const float grid_scale_xy = 1.0f; |
|
|
| for (size_t cls_idx = 0; cls_idx < (size_t)impulse->label_count; cls_idx++) { |
|
|
| std::vector<float> boxes; |
| std::vector<float> scores; |
| std::vector<int> classes; |
| class_results.clear(); |
|
|
| for (size_t ix = 0; ix < row_count; ix++) { |
|
|
| float r_0 = (static_cast<float>(data[ix * col_size + 0]) - zero_point) * scale; |
| float r_1 = (static_cast<float>(data[ix * col_size + 1]) - zero_point) * scale; |
| float r_2 = (static_cast<float>(data[ix * col_size + 2]) - zero_point) * scale; |
| float r_3 = (static_cast<float>(data[ix * col_size + 3]) - zero_point) * scale; |
| float r_4 = (static_cast<float>(data[ix * col_size + 4]) - zero_point) * scale; |
| float r_5 = (static_cast<float>(data[ix * col_size + 5]) - zero_point) * scale; |
| float r_6 = (static_cast<float>(data[ix * col_size + 6]) - zero_point) * scale; |
| float r_7 = (static_cast<float>(data[ix * col_size + 7]) - zero_point) * scale; |
| float r_8 = (static_cast<float>(data[ix * col_size + 8]) - zero_point) * scale; |
| float r_9 = (static_cast<float>(data[ix * col_size + 9]) - zero_point) * scale; |
| float r_10 = (static_cast<float>(data[ix * col_size + 10]) - zero_point) * scale; |
|
|
| float cls = (static_cast<float>(data[ix * col_size + 11 + cls_idx]) - zero_point) * scale; |
| float score = sigmoid(cls) * sigmoid(r_10); |
|
|
| if ((score < threshold) || (score > 1.0f)) { |
| continue; |
| } |
|
|
| float pred_y = sigmoid(r_6) * grid_scale_xy - (grid_scale_xy - 1.0f) / 2.0f; |
| float pred_x = sigmoid(r_7) * grid_scale_xy - (grid_scale_xy - 1.0f) / 2.0f; |
| float pred_h = exp(std::min(r_8, 8.0f)); |
| float pred_w = exp(std::min(r_9, 8.0f)); |
|
|
| r_6 = pred_y; |
| r_7 = pred_x; |
| r_8 = pred_h; |
| r_9 = pred_w; |
|
|
| float by = r_0 + r_6 * r_4; |
| float bx = r_1 + r_7 * r_5; |
| float bh = r_2 * r_8; |
| float bw = r_3 * r_9; |
|
|
| float ymin = by - 0.5 * bh; |
| float xmin = bx - 0.5 * bw; |
| float ymax = by + 0.5 * bh; |
| float xmax = bx + 0.5 * bw; |
|
|
| |
| ymin *= impulse->input_height; |
| xmin *= impulse->input_width; |
| ymax *= impulse->input_height; |
| xmax *= impulse->input_width; |
|
|
| boxes.push_back(ymin); |
| boxes.push_back(xmin); |
| boxes.push_back(ymax); |
| boxes.push_back(xmax); |
| scores.push_back(score); |
| classes.push_back((int)cls_idx); |
| } |
|
|
| size_t nr_boxes = scores.size(); |
| EI_IMPULSE_ERROR nms_res = ei_run_nms(impulse, |
| &class_results, |
| boxes.data(), |
| scores.data(), |
| classes.data(), |
| nr_boxes, |
| true , |
| &nms_config); |
| if (nms_res != EI_IMPULSE_OK) { |
| return nms_res; |
| } |
|
|
| for (auto bb: class_results) { |
| results.push_back(bb); |
| } |
| } |
|
|
| prepare_nms_results_common(object_detection_count, result, &results); |
| return EI_IMPULSE_OK; |
| } |
| #endif |
|
|
| __attribute__((unused)) static EI_IMPULSE_ERROR process_tao_detection_i8(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| #if EI_HAS_TAO_DECODE_DETECTIONS |
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_object_detection_i8_config_t *config = (ei_fill_result_object_detection_i8_config_t*)config_ptr; |
|
|
| ei::matrix_i8_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| EI_IMPULSE_ERROR res = process_tao_decode_detections_common(impulse, |
| result, |
| raw_output_mtx->buffer, |
| config->zero_point, |
| config->scale, |
| config->output_features_count, |
| config->threshold, |
| config->object_detection_count, |
| config->nms_config); |
|
|
| return res; |
| #else |
| return EI_IMPULSE_LAST_LAYER_NOT_AVAILABLE; |
| #endif |
| } |
|
|
| __attribute__((unused)) static EI_IMPULSE_ERROR process_tao_detection_f32(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| #if EI_HAS_TAO_DECODE_DETECTIONS |
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_object_detection_f32_config_t *config = (ei_fill_result_object_detection_f32_config_t*)config_ptr; |
|
|
| ei::matrix_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| EI_IMPULSE_ERROR res = process_tao_decode_detections_common(impulse, |
| result, |
| raw_output_mtx->buffer, |
| 0.0f, |
| 1.0f, |
| config->output_features_count, |
| config->threshold, |
| config->object_detection_count, |
| config->nms_config); |
| return res; |
| #else |
| return EI_IMPULSE_LAST_LAYER_NOT_AVAILABLE; |
| #endif |
| } |
|
|
| __attribute__((unused)) static EI_IMPULSE_ERROR process_tao_yolov3_f32(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| #if EI_HAS_TAO_YOLOV3 |
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_object_detection_f32_config_t *config = (ei_fill_result_object_detection_f32_config_t*)config_ptr; |
|
|
| ei::matrix_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| EI_IMPULSE_ERROR res = process_tao_yolov3_common(impulse, |
| result, |
| raw_output_mtx->buffer, |
| 0.0f, |
| 1.0f, |
| config->output_features_count, |
| config->threshold, |
| config->object_detection_count, |
| config->nms_config); |
| return res; |
| #else |
| return EI_IMPULSE_LAST_LAYER_NOT_AVAILABLE; |
| #endif |
| } |
|
|
| __attribute__((unused)) static EI_IMPULSE_ERROR process_tao_yolov3_i8(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| #if EI_HAS_TAO_YOLOV3 |
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_object_detection_i8_config_t *config = (ei_fill_result_object_detection_i8_config_t*)config_ptr; |
|
|
| ei::matrix_i8_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| EI_IMPULSE_ERROR res = process_tao_yolov3_common(impulse, |
| result, |
| raw_output_mtx->buffer, |
| config->zero_point, |
| config->scale, |
| config->output_features_count, |
| config->threshold, |
| config->object_detection_count, |
| config->nms_config); |
| return res; |
| #else |
| return EI_IMPULSE_LAST_LAYER_NOT_AVAILABLE; |
| #endif |
| } |
|
|
| __attribute__((unused)) static EI_IMPULSE_ERROR process_tao_yolov4_f32(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| #if EI_HAS_TAO_YOLOV4 |
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_object_detection_f32_config_t *config = (ei_fill_result_object_detection_f32_config_t*)config_ptr; |
|
|
| ei::matrix_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| EI_IMPULSE_ERROR res = process_tao_yolov4_common(impulse, |
| result, |
| raw_output_mtx->buffer, |
| 0.0f, |
| 1.0f, |
| config->output_features_count, |
| config->threshold, |
| config->object_detection_count, |
| config->nms_config); |
| return res; |
| #else |
| return EI_IMPULSE_LAST_LAYER_NOT_AVAILABLE; |
| #endif |
| } |
|
|
| __attribute__((unused)) static EI_IMPULSE_ERROR process_tao_yolov4_i8(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| #if EI_HAS_TAO_YOLOV4 |
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_object_detection_i8_config_t *config = (ei_fill_result_object_detection_i8_config_t*)config_ptr; |
|
|
| ei::matrix_i8_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| EI_IMPULSE_ERROR res = process_tao_yolov4_common(impulse, |
| result, |
| raw_output_mtx->buffer, |
| config->zero_point, |
| config->scale, |
| config->output_features_count, |
| config->threshold, |
| config->object_detection_count, |
| config->nms_config); |
| return res; |
| #else |
| return EI_IMPULSE_LAST_LAYER_NOT_AVAILABLE; |
| #endif |
| } |
|
|
| #if EI_HAS_YOLO_PRO |
| template<typename T> |
| __attribute__((unused)) static EI_IMPULSE_ERROR fill_result_struct_yolo_pro_common(const ei_impulse_t *impulse, |
| ei_impulse_result_t *result, |
| T *data, |
| float zero_point, |
| float scale, |
| size_t output_features_count, |
| float threshold, |
| size_t object_detection_count, |
| ei_object_detection_nms_config_t nms_config) { |
| size_t col_size = 4 + impulse->label_count; |
| size_t row_count = output_features_count / col_size; |
|
|
| static std::vector<ei_impulse_result_bounding_box_t> results; |
| static std::vector<ei_impulse_result_bounding_box_t> class_results; |
| results.clear(); |
|
|
| |
| for (size_t cls_idx = 0; cls_idx < (size_t)impulse->label_count; cls_idx++) { |
|
|
| std::vector<float> boxes; |
| std::vector<float> scores; |
| std::vector<int> classes; |
| class_results.clear(); |
|
|
|
|
| for (size_t ix = 0; ix < row_count; ix++) { |
| size_t base_ix = ix * col_size; |
| float xmin = (static_cast<float>(data[base_ix + 0]) - zero_point) * scale; |
| float ymin = (static_cast<float>(data[base_ix + 1]) - zero_point) * scale; |
| float xmax = (static_cast<float>(data[base_ix + 2]) - zero_point) * scale; |
| float ymax = (static_cast<float>(data[base_ix + 3]) - zero_point) * scale; |
| float score = (static_cast<float>(data[base_ix + 4 + cls_idx]) - zero_point) * scale; |
|
|
| if (xmin < 0) xmin = 0; |
| if (xmin > 1) xmin = 1; |
| if (ymin < 0) ymin = 0; |
| if (ymin > 1) ymin = 1; |
| if (ymax < 0) ymax = 0; |
| if (ymax > 1) ymax = 1; |
| if (xmax < 0) xmax = 0; |
| if (xmax > 1) xmax = 1; |
| if (xmax < xmin) xmax = xmin; |
| if (ymax < ymin) ymax = ymin; |
|
|
| #if EI_LOG_LEVEL == EI_LOG_LEVEL_DEBUG |
| ei_printf("%s (", impulse->categories[(uint32_t)cls_idx]); |
| ei_printf_float(cls_idx); |
| ei_printf("): "); |
| ei_printf_float(score); |
| ei_printf(" [ "); |
| ei_printf_float(xmin); |
| ei_printf(", "); |
| ei_printf_float(ymin); |
| ei_printf(", "); |
| ei_printf_float(xmax); |
| ei_printf(", "); |
| ei_printf_float(ymax); |
| ei_printf(" ]\n"); |
| #endif |
|
|
| if (score >= threshold && score <= 1.0f) { |
| ymin *= static_cast<float>(impulse->input_height); |
| xmin *= static_cast<float>(impulse->input_width); |
| ymax *= static_cast<float>(impulse->input_height); |
| xmax *= static_cast<float>(impulse->input_width); |
|
|
| boxes.push_back(ymin); |
| boxes.push_back(xmin); |
| boxes.push_back(ymax); |
| boxes.push_back(xmax); |
| scores.push_back(score); |
| classes.push_back((int)cls_idx); |
| } |
| } |
|
|
| size_t nr_boxes = scores.size(); |
|
|
| EI_IMPULSE_ERROR nms_res = ei_run_nms(impulse, |
| &class_results, |
| boxes.data(), |
| scores.data(), |
| classes.data(), |
| nr_boxes, |
| true , |
| &nms_config); |
|
|
| if (nms_res != EI_IMPULSE_OK) { |
| return nms_res; |
| } |
|
|
| for (auto bb: class_results) { |
| results.push_back(bb); |
| } |
| } |
|
|
| prepare_nms_results_common(object_detection_count, result, &results); |
| return EI_IMPULSE_OK; |
| } |
| #endif |
|
|
| __attribute__((unused)) static EI_IMPULSE_ERROR process_yolo_pro_f32(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| #if EI_HAS_YOLO_PRO |
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_object_detection_f32_config_t *config = (ei_fill_result_object_detection_f32_config_t*)config_ptr; |
|
|
| ei::matrix_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
| EI_IMPULSE_ERROR res = fill_result_struct_yolo_pro_common(impulse, |
| result, |
| raw_output_mtx->buffer, |
| 0.0f, |
| 1.0f, |
| config->output_features_count, |
| config->threshold, |
| config->object_detection_count, |
| config->nms_config); |
| return res; |
| #else |
| return EI_IMPULSE_LAST_LAYER_NOT_AVAILABLE; |
| #endif |
| } |
|
|
| __attribute__((unused)) static EI_IMPULSE_ERROR process_yolo_pro_i8(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| #if EI_HAS_YOLO_PRO |
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_object_detection_i8_config_t *config = (ei_fill_result_object_detection_i8_config_t*)config_ptr; |
|
|
| ei::matrix_i8_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| EI_IMPULSE_ERROR res = fill_result_struct_yolo_pro_common(impulse, |
| result, |
| raw_output_mtx->buffer, |
| config->zero_point, |
| config->scale, |
| config->output_features_count, |
| config->threshold, |
| config->object_detection_count, |
| config->nms_config); |
| return res; |
| #else |
| return EI_IMPULSE_LAST_LAYER_NOT_AVAILABLE; |
| #endif |
| } |
|
|
| #if EI_HAS_YOLOV11 |
|
|
| #define EI_YOLOV11_COORD_ABSOLUTE 0 |
| #define EI_YOLOV11_COORD_NORMALIZED 1 |
|
|
| template<typename T> |
| __attribute__((unused)) static EI_IMPULSE_ERROR fill_result_struct_yolov11_common(const ei_impulse_t *impulse, |
| ei_impulse_result_t *result, |
| bool is_coord_normalized, |
| T *data, |
| float zero_point, |
| float scale, |
| size_t output_features_count, |
| float threshold, |
| size_t object_detection_count, |
| ei_object_detection_nms_config_t nms_config) { |
| size_t row_count = 4 + impulse->label_count; |
| size_t col_size = output_features_count / row_count; |
|
|
| static std::vector<ei_impulse_result_bounding_box_t> results; |
| static std::vector<ei_impulse_result_bounding_box_t> class_results; |
| results.clear(); |
|
|
| |
| |
| for (size_t cls_idx = 0; cls_idx < (size_t)impulse->label_count; cls_idx++) { |
| std::vector<float> boxes; |
| std::vector<float> scores; |
| std::vector<int> classes; |
| class_results.clear(); |
|
|
| for (size_t det_idx = 0; det_idx < col_size; det_idx++) { |
|
|
| float xcenter = (static_cast<float>(data[0 * col_size + det_idx]) - zero_point) * scale; |
| float ycenter = (static_cast<float>(data[1 * col_size + det_idx]) - zero_point) * scale; |
| float width = (static_cast<float>(data[2 * col_size + det_idx]) - zero_point) * scale; |
| float height = (static_cast<float>(data[3 * col_size + det_idx]) - zero_point) * scale; |
|
|
| |
| float xmin = xcenter - (width / 2.0f); |
| float ymin = ycenter - (height / 2.0f); |
| float xmax = xcenter + (width / 2.0f); |
| float ymax = ycenter + (height / 2.0f); |
|
|
| if (is_coord_normalized) { |
| ymin *= static_cast<float>(impulse->input_height); |
| xmin *= static_cast<float>(impulse->input_width); |
| ymax *= static_cast<float>(impulse->input_height); |
| xmax *= static_cast<float>(impulse->input_width); |
| } |
|
|
| if (xmin < 0) { |
| xmin = 0; |
| } |
| if (xmin > impulse->input_width) { |
| xmin = impulse->input_width; |
| } |
| if (ymin < 0) { |
| ymin = 0; |
| } |
| if (ymin > impulse->input_height) { |
| ymin = impulse->input_height; |
| } |
|
|
| if (xmax < 0) { |
| xmax = 0; |
| } |
| if (xmax > impulse->input_width) { |
| xmax = impulse->input_width; |
| } |
| if (ymax < 0) { |
| ymax = 0; |
| } |
| if (ymax > impulse->input_height) { |
| ymax = impulse->input_height; |
| } |
|
|
| float score = (static_cast<float>(data[(4+cls_idx) * col_size + det_idx]) - zero_point) * scale; |
|
|
| #if EI_LOG_LEVEL == EI_LOG_LEVEL_DEBUG |
| ei_printf("%s (", impulse->categories[(uint32_t)cls_idx]); |
| ei_printf_float(cls_idx); |
| ei_printf("): "); |
| ei_printf_float(score); |
| ei_printf(" [ "); |
| ei_printf_float(xmin); |
| ei_printf(", "); |
| ei_printf_float(ymin); |
| ei_printf(", "); |
| ei_printf_float(xmax); |
| ei_printf(", "); |
| ei_printf_float(ymax); |
| ei_printf(" ]\n"); |
| #endif |
|
|
| if (score >= threshold && score <= 1.0f) { |
| boxes.push_back(ymin); |
| boxes.push_back(xmin); |
| boxes.push_back(ymax); |
| boxes.push_back(xmax); |
| scores.push_back(score); |
| classes.push_back((int)cls_idx); |
| } |
| } |
|
|
| size_t nr_boxes = scores.size(); |
|
|
| EI_IMPULSE_ERROR nms_res = ei_run_nms(impulse, |
| &class_results, |
| boxes.data(), |
| scores.data(), |
| classes.data(), |
| nr_boxes, |
| true , |
| &nms_config); |
|
|
| if (nms_res != EI_IMPULSE_OK) { |
| return nms_res; |
| } |
|
|
| for (auto bb: class_results) { |
| results.push_back(bb); |
| } |
| } |
|
|
| prepare_nms_results_common(object_detection_count, result, &results); |
| return EI_IMPULSE_OK; |
| } |
| #endif |
|
|
| |
| |
| |
| __attribute__((unused)) static EI_IMPULSE_ERROR process_yolov11_f32(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| #if EI_HAS_YOLOV11 |
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_object_detection_f32_config_t *config = (ei_fill_result_object_detection_f32_config_t*)config_ptr; |
|
|
| ei::matrix_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| return fill_result_struct_yolov11_common(impulse, |
| result, |
| config->version == EI_YOLOV11_COORD_NORMALIZED, |
| raw_output_mtx->buffer, |
| 0.0f, |
| 1.0f, |
| config->output_features_count, |
| config->threshold, |
| config->object_detection_count, |
| config->nms_config); |
| #else |
| return EI_IMPULSE_LAST_LAYER_NOT_AVAILABLE; |
| #endif |
| } |
|
|
| |
| |
| |
| __attribute__((unused)) static EI_IMPULSE_ERROR process_yolov11_i8(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| #if EI_HAS_YOLOV11 |
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_object_detection_i8_config_t *config = (ei_fill_result_object_detection_i8_config_t*)config_ptr; |
|
|
| ei::matrix_i8_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| return fill_result_struct_yolov11_common(impulse, |
| result, |
| config->version == EI_YOLOV11_COORD_NORMALIZED, |
| raw_output_mtx->buffer, |
| config->zero_point, |
| config->scale, |
| config->output_features_count, |
| config->threshold, |
| config->object_detection_count, |
| config->nms_config); |
| #else |
| return EI_IMPULSE_LAST_LAYER_NOT_AVAILABLE; |
| #endif |
| } |
|
|
| #if EI_HAS_PADDLEOCR_DETECTOR |
|
|
| struct ei_paddleocr_contour_t { |
| int min_r = std::numeric_limits<int>::max(); |
| int max_r = std::numeric_limits<int>::min(); |
| int min_c = std::numeric_limits<int>::max(); |
| int max_c = std::numeric_limits<int>::min(); |
| }; |
|
|
| |
| template <typename MatrixT, typename GetPixelFn> |
| static std::vector<ei_paddleocr_contour_t> ei_paddleocr_find_contours_from_output_impl( |
| const MatrixT& m, |
| float minimum_confidence_rating, |
| GetPixelFn get_pixel |
| ) { |
| std::vector<ei_paddleocr_contour_t> contours; |
|
|
| const int rows = (int)m.rows; |
| const int cols = (int)m.cols; |
| if (rows <= 0 || cols <= 0) return contours; |
|
|
| std::vector<uint8_t> visited((size_t)rows * (size_t)cols, 0); |
|
|
| auto idx = [cols](int r, int c) -> size_t { |
| return (size_t)r * (size_t)cols + (size_t)c; |
| }; |
|
|
| const int dr[4] = {-1, 1, 0, 0}; |
| const int dc[4] = {0, 0, -1, 1}; |
|
|
| std::queue<std::pair<int,int>> q; |
|
|
| for (int r = 0; r < rows; ++r) { |
| for (int c = 0; c < cols; ++c) { |
| const size_t i = idx(r, c); |
| if (visited[i]) continue; |
|
|
| const float v0 = get_pixel(m, r, c); |
| if (v0 < minimum_confidence_rating) continue; |
|
|
| ei_paddleocr_contour_t contour; |
| visited[i] = 1; |
| q.push({r, c}); |
|
|
| while (!q.empty()) { |
| auto p = q.front(); q.pop(); |
| const int cr = p.first; |
| const int cc = p.second; |
|
|
| |
| if (cr < contour.min_r) contour.min_r = cr; |
| if (cr > contour.max_r) contour.max_r = cr; |
| if (cc < contour.min_c) contour.min_c = cc; |
| if (cc > contour.max_c) contour.max_c = cc; |
|
|
| for (int k = 0; k < 4; ++k) { |
| const int nr = cr + dr[k]; |
| const int nc = cc + dc[k]; |
| if ((int)nr >= (int)rows) continue; |
| if ((int)nc >= (int)cols) continue; |
|
|
| const size_t ni = idx(nr, nc); |
| if (visited[ni]) continue; |
|
|
| const float nv = get_pixel(m, nr, nc); |
| if (nv < minimum_confidence_rating) continue; |
|
|
| visited[ni] = 1; |
| q.push({nr, nc}); |
| } |
| } |
|
|
| contours.push_back(contour); |
| } |
| } |
|
|
| return contours; |
| } |
|
|
| static std::vector<ei_paddleocr_contour_t> |
| ei_paddleocr_find_contours_from_output_f32( |
| const ei::matrix_t& m, |
| float minimum_confidence_rating |
| ) { |
| return ei_paddleocr_find_contours_from_output_impl( |
| m, |
| minimum_confidence_rating, |
| [](const ei::matrix_t& m, int r, int c) -> float { |
| return m.buffer[(size_t)r * m.cols + (size_t)c]; |
| } |
| ); |
| } |
|
|
| static std::vector<ei_paddleocr_contour_t> |
| ei_paddleocr_find_contours_from_output_i8( |
| const ei::matrix_i8_t& m, |
| float minimum_confidence_rating, |
| float zero_point, |
| float scale |
| ) { |
| return ei_paddleocr_find_contours_from_output_impl( |
| m, |
| minimum_confidence_rating, |
| [zero_point, scale](const ei::matrix_i8_t& m, int r, int c) -> float { |
| const int8_t v = m.buffer[(size_t)r * m.cols + (size_t)c]; |
| return (float(v) - zero_point) * scale; |
| } |
| ); |
| } |
|
|
| static void ei_paddleocr_map_contour_to_bb( |
| const ei_impulse_t *impulse, |
| const ei_paddleocr_contour_t *contour, |
| ei_impulse_result_bounding_box_t *box, |
| const ei::matrix_t& m, |
| float unclip_ratio |
| ) { |
| uint32_t x = (uint32_t)contour->min_c; |
| uint32_t y = (uint32_t)contour->min_r; |
| uint32_t width = (uint32_t)(contour->max_c - contour->min_c + 1); |
| uint32_t height = (uint32_t)(contour->max_r - contour->min_r + 1); |
|
|
| |
| float total = 0.0f; |
| uint32_t count = 0; |
| for (uint32_t row = y; row < y + height; ++row) { |
| const float* rowptr = m.buffer + (size_t)row * m.cols; |
| for (uint32_t col = x; col < x + width; ++col) { |
| total += rowptr[col]; |
| count++; |
| } |
| } |
| const float value = count ? (total / (float)count) : 0.0f; |
|
|
| |
| uint32_t area = width * height; |
| uint32_t perimeter = 2 * (width + height); |
|
|
| uint32_t d = 0; |
| if (perimeter > 0) { |
| d = (area * unclip_ratio) / perimeter; |
| } |
|
|
| |
| x = x - d; |
| y = y - d; |
| width = width + (d * 2); |
| height = height + (d * 2); |
|
|
| |
| if (x < 0) { |
| x = 0; |
| } |
| if (y < 0) { |
| y = 0; |
| } |
| if ((x + width) > impulse->input_width) { |
| width = impulse->input_width - x; |
| } |
| if ((y + height) > impulse->input_height) { |
| height = impulse->input_height - y; |
| } |
|
|
| box->x = x; |
| box->y = y; |
| box->width = width; |
| box->height = height; |
| box->value = value; |
| } |
|
|
| static void ei_paddleocr_map_contour_to_bb( |
| const ei_impulse_t *impulse, |
| const ei_paddleocr_contour_t *contour, |
| ei_impulse_result_bounding_box_t *box, |
| const ei::matrix_i8_t& m, |
| float zero_point, |
| float scale, |
| float unclip_ratio |
| ) { |
| uint32_t x = (uint32_t)contour->min_c; |
| uint32_t y = (uint32_t)contour->min_r; |
| uint32_t width = (uint32_t)(contour->max_c - contour->min_c + 1); |
| uint32_t height = (uint32_t)(contour->max_r - contour->min_r + 1); |
|
|
| |
| float total = 0.0f; |
| uint32_t count = 0; |
| for (uint32_t row = y; row < y + height; ++row) { |
| const int8_t* rowptr = m.buffer + (size_t)row * m.cols; |
| for (uint32_t col = x; col < x + width; ++col) { |
| total += (float(rowptr[col]) - zero_point) * scale; |
| count++; |
| } |
| } |
| const float value = count ? (total / (float)count) : 0.0f; |
|
|
| |
| uint32_t area = width * height; |
| uint32_t perimeter = 2 * (width + height); |
|
|
| uint32_t d = 0; |
| if (perimeter > 0) { |
| d = (area * unclip_ratio) / perimeter; |
| } |
|
|
| |
| x = x - d; |
| y = y - d; |
| width = width + (d * 2); |
| height = height + (d * 2); |
|
|
| |
| if (x < 0) { |
| x = 0; |
| } |
| if (y < 0) { |
| y = 0; |
| } |
| if ((x + width) > impulse->input_width) { |
| width = impulse->input_width - x; |
| } |
| if ((y + height) > impulse->input_height) { |
| height = impulse->input_height - y; |
| } |
|
|
| box->x = x; |
| box->y = y; |
| box->width = width; |
| box->height = height; |
| box->value = value; |
| } |
|
|
| #endif |
|
|
| |
| |
| |
| __attribute__((unused)) static EI_IMPULSE_ERROR process_paddleocr_f32(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| #if EI_HAS_PADDLEOCR_DETECTOR |
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_paddleocr_f32_config_t *config = (ei_fill_result_paddleocr_f32_config_t*)config_ptr; |
|
|
| ei::matrix_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id, impulse->learning_blocks_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| |
| raw_output_mtx->rows = impulse->input_height; |
| raw_output_mtx->cols = impulse->input_width; |
|
|
| static std::vector<ei_impulse_result_bounding_box_t> results; |
| results.clear(); |
|
|
| auto contours = ei_paddleocr_find_contours_from_output_f32(*raw_output_mtx, config->min_score_pixel); |
|
|
| for (const auto& contour : contours) { |
| ei_impulse_result_bounding_box_t tmp = { |
| .label = impulse->categories[0], |
| .x = 0, |
| .y = 0, |
| .width = 0, |
| .height = 0, |
| .value = 0.0f, |
| }; |
| ei_paddleocr_map_contour_to_bb(impulse, &contour, &tmp, *raw_output_mtx, config->unclip_ratio); |
|
|
| if (tmp.value < config->min_score_box) continue; |
|
|
| results.push_back(tmp); |
| } |
|
|
| |
| std::sort(results.begin(), results.end(), |
| [](const ei_impulse_result_bounding_box_t& a, |
| const ei_impulse_result_bounding_box_t& b) { |
| return a.value > b.value; |
| }); |
|
|
| result->bounding_boxes = results.data(); |
| result->bounding_boxes_count = results.size(); |
|
|
| return EI_IMPULSE_OK; |
| #else |
| return EI_IMPULSE_LAST_LAYER_NOT_AVAILABLE; |
| #endif |
| } |
|
|
| |
| |
| |
| __attribute__((unused)) static EI_IMPULSE_ERROR process_paddleocr_i8(ei_impulse_handle_t *handle, |
| uint32_t block_index, |
| uint32_t input_block_id, |
| ei_impulse_result_t *result, |
| void *config_ptr, |
| void *state) { |
| #if EI_HAS_PADDLEOCR_DETECTOR |
| const ei_impulse_t *impulse = handle->impulse; |
| const ei_fill_result_paddleocr_i8_config_t *config = (ei_fill_result_paddleocr_i8_config_t*)config_ptr; |
|
|
| ei::matrix_i8_t* raw_output_mtx = NULL; |
| bool find_mtx_res = find_mtx_by_idx(result->_raw_outputs, &raw_output_mtx, input_block_id, impulse->output_tensors_size); |
| if (!find_mtx_res) { |
| return EI_IMPULSE_OUTPUT_TENSOR_NULL; |
| } |
|
|
| |
| raw_output_mtx->rows = impulse->input_height; |
| raw_output_mtx->cols = impulse->input_width; |
|
|
| static std::vector<ei_impulse_result_bounding_box_t> results; |
| results.clear(); |
|
|
| auto contours = ei_paddleocr_find_contours_from_output_i8(*raw_output_mtx, config->min_score_pixel, config->zero_point, config->scale); |
|
|
| for (const auto& contour : contours) { |
| ei_impulse_result_bounding_box_t tmp = { |
| .label = impulse->categories[0], |
| .x = 0, |
| .y = 0, |
| .width = 0, |
| .height = 0, |
| .value = 0.0f, |
| }; |
| ei_paddleocr_map_contour_to_bb(impulse, &contour, &tmp, *raw_output_mtx, config->zero_point, config->scale, config->unclip_ratio); |
|
|
| if (tmp.value < config->min_score_box) continue; |
|
|
| results.push_back(tmp); |
| } |
|
|
| |
| std::sort(results.begin(), results.end(), |
| [](const ei_impulse_result_bounding_box_t& a, |
| const ei_impulse_result_bounding_box_t& b) { |
| return a.value > b.value; |
| }); |
|
|
| result->bounding_boxes = results.data(); |
| result->bounding_boxes_count = results.size(); |
|
|
| return EI_IMPULSE_OK; |
| #else |
| return EI_IMPULSE_LAST_LAYER_NOT_AVAILABLE; |
| #endif |
| } |
|
|
| |
| template <typename T = void> |
| [[deprecated("The call signature set_threshold_postprocessing(int16_t, void*, uint8_t, float) has been removed in favor of set_threshold_postprocessing(const ei_postprocessing_block_t *, std::string, float) (edge-impulse-sdk/classifier/postprocessing/ei_postprocessing_thresholds.h)")]] |
| EI_IMPULSE_ERROR set_threshold_postprocessing(int16_t block_number, void* block_config, uint8_t type, float threshold) { |
| static_assert(ei_dependent_false_v<T>::value, |
| "The call signature set_threshold_postprocessing(int16_t, void*, uint8_t, float) has been removed in favor of set_threshold_postprocessing(const ei_postprocessing_block_t *, std::string, float) (edge-impulse-sdk/classifier/postprocessing/ei_postprocessing_thresholds.h)"); |
| return EI_IMPULSE_CALL_SIGNATURE_REMOVED; |
| } |
|
|
| template <typename T = void> |
| [[deprecated("get_threshold_postprocessing() has been removed in favor of get_thresholds_postprocessing(const ei_postprocessing_block_t *, std::vector<ei_threshold_desc_t>&) (edge-impulse-sdk/classifier/postprocessing/ei_postprocessing_thresholds.h)")]] |
| EI_IMPULSE_ERROR get_threshold_postprocessing(std::string* type_str, std::string* threshold_name_str, void* block_config, uint8_t type, float* threshold) { |
| static_assert(ei_dependent_false_v<T>::value, |
| "get_threshold_postprocessing() has been removed in favor of get_thresholds_postprocessing(const ei_postprocessing_block_t *, std::vector<ei_threshold_desc_t>&) (edge-impulse-sdk/classifier/postprocessing/ei_postprocessing_thresholds.h)"); |
| return EI_IMPULSE_CALL_SIGNATURE_REMOVED; |
| } |
|
|
| #endif |
|
|