| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import ssl |
|
|
| ssl._create_default_https_context = ssl._create_unverified_context |
|
|
| import os |
| import shutil |
| import numpy as np |
| import tensorflow as tf |
|
|
| from hydra.core.hydra_config import HydraConfig |
| from omegaconf import DictConfig |
| from common.utils import aspect_ratio_dict, color_mode_n6_dict |
| from object_detection.tf.src.postprocessing.tflite_ssd_postprocessing_removal.ssd_model_cut_function import ssd_post_processing_removal |
|
|
|
|
|
|
|
|
| def gen_h_user_file_h7(config: DictConfig = None, quantized_model_path: str = None) -> None: |
| """ |
| Generates a C header file containing user configuration for the AI model. |
| |
| Args: |
| config: A configuration object containing user configuration for the AI model. |
| quantized_model_path: The path to the quantized model file. |
| |
| """ |
|
|
| class Flags: |
| def __init__(self, **entries): |
| self.__dict__.update(entries) |
|
|
| params = Flags(**config) |
| if quantized_model_path.lower().endswith('.tflite'): |
| interpreter_quant = tf.lite.Interpreter(model_path=quantized_model_path) |
| input_details = interpreter_quant.get_input_details()[0] |
| output_details = interpreter_quant.get_output_details()[0] |
| input_shape = input_details['shape'] |
| elif quantized_model_path.lower().endswith('.onnx'): |
| import onnxruntime |
|
|
|
|
| params = config |
|
|
| model = onnxruntime.InferenceSession(quantized_model_path) |
| inputs = model.get_inputs() |
| outputs = model.get_outputs() |
| input_shape_raw = inputs[0].shape |
| input_shape = [1,input_shape_raw[2],input_shape_raw[3],input_shape_raw[1]] |
| else: |
| raise TypeError("Please provide a TFLITE or ONNX model for N6 deployment") |
|
|
| class_names = params.dataset.class_names |
|
|
| path = os.path.join(HydraConfig.get().runtime.output_dir, "C_header/") |
|
|
| try: |
| os.mkdir(path) |
| except OSError as error: |
| print(error) |
|
|
| TFLite_Detection_PostProcess_id = False |
| XY, WH = None, None |
|
|
| if params.model.model_type == "st_ssd_mobilenet_v1": |
| classes = '{\\\n"background",' |
|
|
| elif params.model.model_type =="ssd_mobilenet_v2_fpnlite": |
|
|
| name_of_post_process_layer='TFLite_Detection_PostProcess' |
|
|
| for op in interpreter_quant._get_ops_details(): |
| if op['op_name'] == name_of_post_process_layer: |
| TFLite_Detection_PostProcess_id = op['index'] |
|
|
|
|
| if TFLite_Detection_PostProcess_id: |
| print('[INFO] : This TFLITE model contains a post-processing layer') |
| anchors_path = os.path.join(path,'anchors.h') |
| path_cut_model, XY, WH = ssd_post_processing_removal(quantized_model_path, TFLite_Detection_PostProcess_id, anchors_path) |
| quantized_model_path = path_cut_model |
| else: |
| print('[INFO] : This TFLITE model doesnt contain a post-processing layer') |
|
|
| classes = '{\\\n"background",' |
|
|
| else: |
| classes = '{\\\n' |
|
|
| for i, x in enumerate(params.dataset.class_names): |
| if i == (len(class_names) - 1): |
| classes = classes + ' "' + str(x) + '"' + '}\\' |
| else: |
| classes = classes + ' "' + str(x) + '"' + ' ,' + ('\\\n' if (i % 5 == 0 and i != 0) else '') |
|
|
|
|
|
|
| with open(os.path.join(path, "ai_model_config.h"), "wt") as f: |
| f.write("/**\n") |
| f.write(" ******************************************************************************\n") |
| f.write(" * @file ai_model_config.h\n") |
| f.write(" * @author Artificial Intelligence Solutions group (AIS)\n") |
| f.write(" * @brief User header file for Preprocessing configuration\n") |
| f.write(" ******************************************************************************\n") |
| f.write(" * @attention\n") |
| f.write(" *\n") |
| f.write(" * Copyright (c) 2024 STMicroelectronics.\n") |
| f.write(" * All rights reserved.\n") |
| f.write(" *\n") |
| f.write(" * This software is licensed under terms that can be found in the LICENSE file in\n") |
| f.write(" * the root directory of this software component.\n") |
| f.write(" * If no LICENSE file comes with this software, it is provided AS-IS.\n") |
| f.write(" *\n") |
| f.write(" ******************************************************************************\n") |
| f.write(" */\n\n") |
| f.write("/* --------------- Generated code ----------------- */\n") |
| f.write("#ifndef __AI_MODEL_CONFIG_H__\n") |
| f.write("#define __AI_MODEL_CONFIG_H__\n\n\n") |
| f.write("/* I/O configuration */\n") |
| if params.model.model_type == "st_ssd_mobilenet_v1" or params.model.model_type == "ssd_mobilenet_v2_fpnlite": |
| f.write("#define NB_CLASSES ({})\n".format(len(class_names)+1)) |
| else: |
| f.write("#define NB_CLASSES ({})\n".format(len(class_names))) |
| f.write("#define INPUT_HEIGHT ({})\n".format(int(input_shape[1]))) |
| f.write("#define INPUT_WIDTH ({})\n".format(int(input_shape[2]))) |
| f.write("#define INPUT_CHANNELS ({})\n".format(int(input_shape[3]))) |
| f.write("\n") |
| f.write("/* Classes */\n") |
| f.write("#define CLASSES_TABLE const char* classes_table[NB_CLASSES] = {}\n".format(classes)) |
| f.write("\n\n") |
| f.write("/***** Preprocessing configuration *****/\n\n") |
| f.write("/* Cropping configuration */\n") |
| yaml_opt = [False, "crop", "padding"] |
| opt = ["ASPECT_RATIO_FIT", "ASPECT_RATIO_CROP", "ASPECT_RATIO_PADDING"] |
| f.write("#define ASPECT_RATIO_FIT (1)\n") |
| f.write("#define ASPECT_RATIO_CROP (2)\n") |
| f.write("#define ASPECT_RATIO_PADDING (3)\n") |
| f.write("\n") |
| f.write("#define ASPECT_RATIO_MODE {}\n".format(aspect_ratio_dict[params.preprocessing.resizing.aspect_ratio])) |
| f.write("\n") |
|
|
| f.write("/***** Postprocessing configuration *****/\n\n") |
| f.write("/* Postprocessing type configuration */\n") |
| f.write("#define POSTPROCESS_CENTER_NET (1)\n") |
| f.write("#define POSTPROCESS_YOLO_V2 (2)\n") |
| f.write("#define POSTPROCESS_ST_SSD (3)\n") |
| f.write("#define POSTPROCESS_SSD (4)\n") |
| f.write("#define POSTPROCESS_ST_YOLO_X (5)\n\n") |
|
|
| if (params.model.model_type == "st_ssd_mobilenet_v1" or params.model.model_type == "ssd_mobilenet_v2_fpnlite") and not TFLite_Detection_PostProcess_id: |
| f.write("#define POSTPROCESS_TYPE POSTPROCESS_ST_SSD\n\n") |
| elif TFLite_Detection_PostProcess_id: |
| f.write("#define POSTPROCESS_TYPE POSTPROCESS_SSD\n\n") |
| elif params.model.model_type == "CENTER_NET": |
| f.write("#define POSTPROCESS_TYPE POSTPROCESS_CENTER_NET\n\n") |
| elif (params.model.model_type == "yolov2t" or params.model.model_type =="st_yololcv1"): |
| f.write("#define POSTPROCESS_TYPE POSTPROCESS_YOLO_V2\n\n") |
| elif params.model.model_type == "st_yoloxn": |
| f.write("#define POSTPROCESS_TYPE POSTPROCESS_ST_YOLO_X\n\n") |
| else: |
| raise TypeError("please select one of this supported post processing options [CENTER_NET,st_yoloxn, st_yololcv1, yolov2t, st_ssd_mobilenet_v1, ssd_mobilenet_v2_fpnlite ]") |
|
|
| if (params.model.model_type == "st_ssd_mobilenet_v1" or params.model.model_type == "ssd_mobilenet_v2_fpnlite") and not TFLite_Detection_PostProcess_id: |
| f.write("/* Postprocessing ST_SSD configuration */\n") |
| f.write("#define AI_OBJDETECT_SSD_ST_PP_NB_CLASSES ({})\n".format(len(class_names)+1)) |
| f.write("#define AI_OBJDETECT_SSD_ST_PP_IOU_THRESHOLD ({})\n".format(float(params.postprocessing.NMS_thresh))) |
| f.write("#define AI_OBJDETECT_SSD_ST_PP_CONF_THRESHOLD ({})\n".format(float(params.postprocessing.confidence_thresh))) |
| f.write("#define AI_OBJDETECT_SSD_ST_PP_MAX_BOXES_LIMIT ({})\n".format(int(params.postprocessing.max_detection_boxes))) |
| f.write("#define AI_OBJDETECT_SSD_ST_PP_TOTAL_DETECTIONS ({})\n".format(int(output_details['shape'][1]))) |
| elif TFLite_Detection_PostProcess_id: |
| f.write("\n/* Postprocessing SSD configuration */\n") |
| f.write("#define AI_OBJDETECT_SSD_PP_XY_SCALE ({})\n".format(XY)) |
| f.write("#define AI_OBJDETECT_SSD_PP_WH_SCALE ({})\n".format(WH)) |
| f.write("#define AI_OBJDETECT_SSD_PP_NB_CLASSES ({})\n".format(len(class_names)+1)) |
| f.write("#define AI_OBJDETECT_SSD_PP_IOU_THRESHOLD ({})\n".format(float(params.postprocessing.NMS_thresh))) |
| f.write("#define AI_OBJDETECT_SSD_PP_CONF_THRESHOLD ({})\n".format(float(params.postprocessing.confidence_thresh))) |
| f.write("#define AI_OBJDETECT_SSD_PP_MAX_BOXES_LIMIT ({})\n".format(int(params.postprocessing.max_detection_boxes))) |
| f.write("#define AI_OBJDETECT_SSD_PP_TOTAL_DETECTIONS ({})\n".format(int(output_details['shape'][1]))) |
| elif (params.model.model_type == "yolov2t" or params.model.model_type == "st_yololcv1"): |
| f.write("\n/* Postprocessing TINY_YOLO_V2 configuration */\n") |
| yolo_anchors = np.concatenate(params.postprocessing.yolo_anchors).flatten() |
| f.write("#define AI_OBJDETECT_YOLOV2_PP_NB_CLASSES ({})\n".format(len(class_names))) |
| f.write("#define AI_OBJDETECT_YOLOV2_PP_GRID_WIDTH ({})\n".format(int(input_shape[2]//params.postprocessing.network_stride))) |
| f.write("#define AI_OBJDETECT_YOLOV2_PP_GRID_HEIGHT ({})\n".format(int(input_shape[1]//params.postprocessing.network_stride))) |
| f.write("#define AI_OBJDETECT_YOLOV2_PP_NB_INPUT_BOXES (AI_OBJDETECT_YOLOV2_PP_GRID_WIDTH * AI_OBJDETECT_YOLOV2_PP_GRID_HEIGHT)\n") |
| f.write("#define AI_OBJDETECT_YOLOV2_PP_NB_ANCHORS ({})\n".format(int(len(yolo_anchors)/2))) |
| anchors_string = "{" + ", ".join([f"{(x):.6f}" for x in yolo_anchors]) + "}" |
| f.write("static const float32_t AI_OBJDETECT_YOLOV2_PP_ANCHORS[2*AI_OBJDETECT_YOLOV2_PP_NB_ANCHORS] ={};\n".format(anchors_string)) |
| f.write("#define AI_OBJDETECT_YOLOV2_PP_IOU_THRESHOLD ({})\n".format(float(params.postprocessing.NMS_thresh))) |
| f.write("#define AI_OBJDETECT_YOLOV2_PP_CONF_THRESHOLD ({})\n".format(float(params.postprocessing.confidence_thresh))) |
| f.write("#define AI_OBJDETECT_YOLOV2_PP_MAX_BOXES_LIMIT ({})\n".format(int(params.postprocessing.max_detection_boxes))) |
| elif (params.model.model_type == "st_yoloxn"): |
| f.write("\n/* Postprocessing ST_YOLO_X configuration */\n") |
| yolo_anchors = np.concatenate(params.postprocessing.yolo_anchors).flatten() |
| f.write("#define AI_OBJDETECT_YOLOVX_PP_NB_CLASSES ({})\n".format(len(class_names))) |
|
|
| f.write("#define AI_OBJDETECT_YOLOVX_PP_L_GRID_WIDTH ({})\n".format(int(input_shape[2]//params.postprocessing.network_stride[0]))) |
| f.write("#define AI_OBJDETECT_YOLOVX_PP_L_GRID_HEIGHT ({})\n".format(int(input_shape[1]//params.postprocessing.network_stride[0]))) |
| f.write("#define AI_OBJDETECT_YOLOVX_PP_L_NB_INPUT_BOXES (AI_OBJDETECT_YOLOVX_PP_L_GRID_WIDTH * AI_OBJDETECT_YOLOVX_PP_L_GRID_HEIGHT)\n") |
|
|
| f.write("#define AI_OBJDETECT_YOLOVX_PP_M_GRID_WIDTH ({})\n".format(int(input_shape[2]//params.postprocessing.network_stride[1]))) |
| f.write("#define AI_OBJDETECT_YOLOVX_PP_M_GRID_HEIGHT ({})\n".format(int(input_shape[1]//params.postprocessing.network_stride[1]))) |
| f.write("#define AI_OBJDETECT_YOLOVX_PP_M_NB_INPUT_BOXES (AI_OBJDETECT_YOLOVX_PP_M_GRID_WIDTH * AI_OBJDETECT_YOLOVX_PP_M_GRID_HEIGHT)\n") |
|
|
| f.write("#define AI_OBJDETECT_YOLOVX_PP_S_GRID_WIDTH ({})\n".format(int(input_shape[2]//params.postprocessing.network_stride[2]))) |
| f.write("#define AI_OBJDETECT_YOLOVX_PP_S_GRID_HEIGHT ({})\n".format(int(input_shape[1]//params.postprocessing.network_stride[2]))) |
| f.write("#define AI_OBJDETECT_YOLOVX_PP_S_NB_INPUT_BOXES (AI_OBJDETECT_YOLOVX_PP_S_GRID_WIDTH * AI_OBJDETECT_YOLOVX_PP_S_GRID_HEIGHT)\n") |
|
|
| f.write("#define AI_OBJDETECT_YOLOVX_PP_NB_ANCHORS ({})\n".format(int(len(yolo_anchors)/2))) |
|
|
| anchors_string = "{" + ", ".join([f"{(x*int(input_shape[2]//params.postprocessing.network_stride[0])):.6f}" for row in params.postprocessing.yolo_anchors for x in row]) + "}" |
| f.write("static const float32_t AI_OBJDETECT_YOLOVX_PP_L_ANCHORS[2*AI_OBJDETECT_YOLOVX_PP_NB_ANCHORS] ={};\n".format(anchors_string)) |
|
|
| anchors_string = "{" + ", ".join([f"{(x*int(input_shape[2]//params.postprocessing.network_stride[1])):.6f}" for row in params.postprocessing.yolo_anchors for x in row]) + "}" |
| f.write("static const float32_t AI_OBJDETECT_YOLOVX_PP_M_ANCHORS[2*AI_OBJDETECT_YOLOVX_PP_NB_ANCHORS] ={};\n".format(anchors_string)) |
|
|
| anchors_string = "{" + ", ".join([f"{(x*int(input_shape[2]//params.postprocessing.network_stride[2])):.6f}" for row in params.postprocessing.yolo_anchors for x in row]) + "}" |
| f.write("static const float32_t AI_OBJDETECT_YOLOVX_PP_S_ANCHORS[2*AI_OBJDETECT_YOLOVX_PP_NB_ANCHORS] ={};\n".format(anchors_string)) |
|
|
| f.write("#define AI_OBJDETECT_YOLOVX_PP_IOU_THRESHOLD ({})\n".format(float(params.postprocessing.NMS_thresh))) |
| f.write("#define AI_OBJDETECT_YOLOVX_PP_CONF_THRESHOLD ({})\n".format(float(params.postprocessing.confidence_thresh))) |
| f.write("#define AI_OBJDETECT_YOLOVX_PP_MAX_BOXES_LIMIT ({})\n".format(int(params.postprocessing.max_detection_boxes))) |
|
|
| f.write("\n") |
|
|
| f.write("/* Input color format configuration */\n") |
| yaml_opt = ["rgb", "bgr", "grayscale"] |
| opt = ["RGB_FORMAT", "BGR_FORMAT", "GRAYSCALE_FORMAT"] |
| f.write("#define RGB_FORMAT (1)\n") |
| f.write("#define BGR_FORMAT (2)\n") |
| f.write("#define GRAYSCALE_FORMAT (3)\n") |
| f.write("\n") |
| f.write("#define PP_COLOR_MODE {}\n".format(opt[yaml_opt.index(params.preprocessing.color_mode)])) |
| f.write("\n") |
| f.write("/* Input/Output quantization configuration */\n") |
| opt = ["UINT8_FORMAT", "INT8_FORMAT", "FLOAT32_FORMAT"] |
| f.write("#define UINT8_FORMAT (1)\n") |
| f.write("#define INT8_FORMAT (2)\n") |
| f.write("#define FLOAT32_FORMAT (3)\n") |
| f.write("\n") |
| f.write("#define QUANT_INPUT_TYPE {}\n".format( |
| opt[[np.uint8, np.int8, np.float32].index(input_details['dtype'])])) |
| f.write("#define QUANT_OUTPUT_TYPE {}\n".format( |
| opt[[np.uint8, np.int8, np.float32].index(output_details['dtype'])])) |
| f.write("\n") |
| f.write("#endif /* __AI_MODEL_CONFIG_H__ */\n") |
|
|
| return TFLite_Detection_PostProcess_id, quantized_model_path |
|
|
|
|
| def gen_h_user_file_n6(config: DictConfig = None, quantized_model_path: str = None) -> None: |
| """ |
| Generates a C header file containing user configuration for the AI model. |
| |
| Args: |
| config: A configuration object containing user configuration for the AI model. |
| quantized_model_path: The path to the quantized model file. |
| |
| """ |
| class Flags: |
| def __init__(self, **entries): |
| self.__dict__.update(entries) |
|
|
| params = Flags(**config) |
| if quantized_model_path.lower().endswith('.tflite'): |
| interpreter_quant = tf.lite.Interpreter(model_path=quantized_model_path) |
| input_details = interpreter_quant.get_input_details()[0] |
| output_details = interpreter_quant.get_output_details()[0] |
| input_shape = input_details['shape'] |
| elif quantized_model_path.lower().endswith('.onnx'): |
| import onnxruntime |
|
|
|
|
| params = config |
|
|
| model = onnxruntime.InferenceSession(quantized_model_path) |
| inputs = model.get_inputs() |
| outputs = model.get_outputs() |
| input_shape_raw = inputs[0].shape |
| input_shape = [1,input_shape_raw[2],input_shape_raw[3],input_shape_raw[1]] |
| else: |
| raise TypeError("Please provide a TFLITE or ONNX model for N6 deployment") |
|
|
| class_names = params.dataset.class_names |
|
|
| path = os.path.join(HydraConfig.get().runtime.output_dir, "C_header/") |
|
|
| try: |
| os.mkdir(path) |
| except OSError as error: |
| print(error) |
|
|
| TFLite_Detection_PostProcess_id = False |
| XY, WH = None, None |
|
|
| if params.model.model_type == "st_ssd_mobilenet_v1": |
| classes = '{\\\n"background",' |
|
|
| elif params.model.model_type =="ssd_mobilenet_v2_fpnlite": |
|
|
| name_of_post_process_layer='TFLite_Detection_PostProcess' |
|
|
| for op in interpreter_quant._get_ops_details(): |
| if op['op_name'] == name_of_post_process_layer: |
| TFLite_Detection_PostProcess_id = op['index'] |
|
|
|
|
| if TFLite_Detection_PostProcess_id: |
| print('[INFO] : This TFLITE model contains a post-processing layer') |
| anchors_path = os.path.join(path,'anchors.h') |
| path_cut_model, XY, WH = ssd_post_processing_removal(quantized_model_path, TFLite_Detection_PostProcess_id, anchors_path) |
| quantized_model_path = path_cut_model |
| else: |
| print('[INFO] : This TFLITE model doesnt contain a post-processing layer') |
|
|
| classes = '{\\\n"background",' |
|
|
| else: |
| classes = '{\\\n' |
|
|
| for i, x in enumerate(params.dataset.class_names): |
| if i == (len(class_names) - 1): |
| classes = classes + ' "' + str(x) + '"' + '}\\' |
| else: |
| classes = classes + ' "' + str(x) + '"' + ' ,' + ('\\\n' if (i % 5 == 0 and i != 0) else '') |
| |
| if params.model.model_type == "face_detect_front": |
| outs_info = interpreter_quant.get_output_details() |
| |
| output_shapes =[] |
| for buffer in outs_info: |
| output_shapes.append(buffer["shape"]) |
| sorted_shapes = sorted(output_shapes, key=lambda arr: (arr[1], arr[2]), reverse=True) |
| SSD_OPTIONS_FRONT = { |
| 'num_layers': 4, |
| 'input_size_height': 128, |
| 'input_size_width': 128, |
| 'anchor_offset_x': 0.5, |
| 'anchor_offset_y': 0.5, |
| 'strides': [8, 16, 16, 16], |
| 'interpolated_scale_aspect_ratio': 1.0} |
| from object_detection.tf.src.postprocessing import ssd_generate_anchors |
| anchors=ssd_generate_anchors(SSD_OPTIONS_FRONT) |
| anch_0_rows = int(sorted_shapes[0][1]) |
| anch_1_rows = int(sorted_shapes[2][1]) |
| anch_0 = anchors[:anch_0_rows, :] |
| anch_1 = anchors[anch_0_rows:, :] |
| anch_0_flat = anch_0.reshape(int(anch_0.shape[0] * anch_0.shape[1])) |
| anch_1_flat = anch_1.reshape(int(anch_1.shape[0] * anch_1.shape[1])) |
| |
| formatted_anch_0_flat = ", ".join(f"{x:.6f}" for x in anch_0_flat) |
| c_anch_0_str = f"const float32_t g_Anchors_0[{int(anch_0.shape[0] * anch_0.shape[1])}] = {{ {formatted_anch_0_flat} }};" |
| formatted_anch_1_flat = ", ".join(f"{x:.6f}" for x in anch_1_flat) |
| c_anch_1_str = f"const float32_t g_Anchors_1[{int(anch_1.shape[0] * anch_1.shape[1])}] = {{ {formatted_anch_1_flat} }};" |
| |
| with open(os.path.join(path, "fd_blazeface_anchors_0.h"), "wt") as f: |
| f.write("#ifndef __ANCHORS_0_H__\n") |
| f.write("#define __ANCHORS_0_H__\n\n") |
| f.write(c_anch_0_str) |
| f.write("\n") |
| f.write("#endif /* __ANCHORS_0_H__ */\n") |
|
|
| with open(os.path.join(path, "fd_blazeface_anchors_1.h"), "wt") as f: |
| f.write("#ifndef __ANCHORS_1_H__\n") |
| f.write("#define __ANCHORS_1_H__\n\n") |
| f.write(c_anch_1_str) |
| f.write("\n") |
| f.write("#endif /* __ANCHORS_1_H__ */\n") |
|
|
| |
| anchors_0_path_C = os.path.join(params.deployment.c_project_path, 'Application', params.deployment.hardware_setup.board, 'Inc', 'fd_blazeface_anchors_0.h') |
| anchors_1_path_C = os.path.join(params.deployment.c_project_path, 'Application', params.deployment.hardware_setup.board, 'Inc', 'fd_blazeface_anchors_1.h') |
| if os.path.exists(anchors_0_path_C): |
| os.remove(anchors_0_path_C) |
| if os.path.exists(anchors_1_path_C): |
| os.remove(anchors_1_path_C) |
| shutil.copy(os.path.join(path, "fd_blazeface_anchors_0.h"), anchors_0_path_C) |
| shutil.copy(os.path.join(path, "fd_blazeface_anchors_1.h"), anchors_1_path_C) |
|
|
| with open(os.path.join(path, "app_config.h"), "wt") as f: |
| f.write("/**\n") |
| f.write("******************************************************************************\n") |
| f.write("* @file app_config.h\n") |
| f.write("* @author GPM Application Team\n") |
| f.write("*\n") |
| f.write("******************************************************************************\n") |
| f.write("* @attention\n") |
| f.write("*\n") |
| f.write("* Copyright (c) 2023 STMicroelectronics.\n") |
| f.write("* All rights reserved.\n") |
| f.write("*\n") |
| f.write("* This software is licensed under terms that can be found in the LICENSE file\n") |
| f.write("* in the root directory of this software component.\n") |
| f.write("* If no LICENSE file comes with this software, it is provided AS-IS.\n") |
| f.write("*\n") |
| f.write("******************************************************************************\n") |
| f.write("*/\n\n") |
| f.write("/* --------------- Generated code ----------------- */\n") |
| f.write("#ifndef APP_CONFIG\n") |
| f.write("#define APP_CONFIG\n\n") |
| f.write('#include "arm_math.h"\n\n') |
| f.write("#define USE_DCACHE\n\n") |
| f.write("/*Defines: CMW_MIRRORFLIP_NONE; CMW_MIRRORFLIP_FLIP; CMW_MIRRORFLIP_MIRROR; CMW_MIRRORFLIP_FLIP_MIRROR;*/\n") |
| f.write("#define CAMERA_FLIP CMW_MIRRORFLIP_NONE\n\n") |
| f.write("") |
| f.write("#define ASPECT_RATIO_CROP (1) /* Crop both pipes to nn input aspect ratio; Original aspect ratio kept */\n") |
| f.write("#define ASPECT_RATIO_FIT (2) /* Resize both pipe to NN input aspect ratio; Original aspect ratio not kept */\n") |
| f.write("#define ASPECT_RATIO_FULLSCREEN (3) /* Resize camera image to NN input size and display a fullscreen image */\n") |
| f.write("#define ASPECT_RATIO_MODE {}\n".format(aspect_ratio_dict[params.preprocessing.resizing.aspect_ratio])) |
| f.write("\n") |
|
|
| f.write("/* Postprocessing type configuration */\n") |
|
|
| if (params.model.model_type == "st_ssd_mobilenet_v1" or params.model.model_type == "ssd_mobilenet_v2_fpnlite") and not TFLite_Detection_PostProcess_id: |
| f.write("#define POSTPROCESS_TYPE POSTPROCESS_OD_ST_SSD_UF\n") |
| elif TFLite_Detection_PostProcess_id: |
| raise TypeError("Not supported yet on N6") |
| elif params.model.model_type == "CENTER_NET": |
| raise TypeError("Not supported yet on N6") |
| elif (params.model.model_type == "yolov2t" or params.model.model_type == "st_yololcv1"): |
| f.write("#define POSTPROCESS_TYPE POSTPROCESS_OD_YOLO_V2_UI\n\n") |
| elif params.model.model_type in ("yolov8n", "yolov11n", "yolov5u"): |
| f.write("#define POSTPROCESS_TYPE POSTPROCESS_OD_YOLO_V8_UI\n") |
| elif params.model.model_type == "st_yoloxn": |
| f.write("#define POSTPROCESS_TYPE POSTPROCESS_OD_ST_YOLOX_UI\n") |
| elif params.model.model_type == "face_detect_front": |
| f.write("#define POSTPROCESS_TYPE POSTPROCESS_OD_BLAZEFACE_UI\n") |
| else: |
| raise TypeError("Please select one of the supported model_type") |
| f.write("\n") |
| f.write("#define COLOR_BGR (0)\n") |
| f.write("#define COLOR_RGB (1)\n") |
| f.write("#define COLOR_MODE {}\n".format(color_mode_n6_dict[params.preprocessing.color_mode])) |
|
|
| f.write("/* Classes */\n") |
| if params.model.model_type == "st_ssd_mobilenet_v1" or params.model.model_type == "ssd_mobilenet_v2_fpnlite": |
| f.write("#define NB_CLASSES ({})\n".format(len(class_names)+1)) |
| else: |
| f.write("#define NB_CLASSES ({})\n".format(len(class_names))) |
| f.write("#define CLASSES_TABLE const char* classes_table[NB_CLASSES] = {}\n".format(classes)) |
|
|
| if (params.model.model_type == "st_ssd_mobilenet_v1" or params.model.model_type == "ssd_mobilenet_v2_fpnlite") and not TFLite_Detection_PostProcess_id: |
| f.write("/* Postprocessing ST_SSD configuration */\n") |
| f.write("#define AI_OD_SSD_ST_PP_NB_CLASSES ({})\n".format(len(class_names)+1)) |
| f.write("#define AI_OD_SSD_ST_PP_IOU_THRESHOLD ({})\n".format(float(params.postprocessing.NMS_thresh))) |
| f.write("#define AI_OD_SSD_ST_PP_CONF_THRESHOLD ({})\n".format(float(params.postprocessing.confidence_thresh))) |
| f.write("#define AI_OD_SSD_ST_PP_MAX_BOXES_LIMIT ({})\n".format(int(params.postprocessing.max_detection_boxes))) |
| f.write("#define AI_OD_SSD_ST_PP_TOTAL_DETECTIONS ({})\n".format(int(output_details['shape'][1]))) |
| elif TFLite_Detection_PostProcess_id: |
| f.write("\n/* Postprocessing SSD configuration */\n") |
| f.write("#define AI_OD_SSD_PP_XY_SCALE ({})\n".format(XY)) |
| f.write("#define AI_OD_SSD_PP_WH_SCALE ({})\n".format(WH)) |
| f.write("#define AI_OD_SSD_PP_NB_CLASSES ({})\n".format(len(class_names)+1)) |
| f.write("#define AI_OD_SSD_PP_IOU_THRESHOLD ({})\n".format(float(params.postprocessing.NMS_thresh))) |
| f.write("#define AI_OD_SSD_PP_CONF_THRESHOLD ({})\n".format(float(params.postprocessing.confidence_thresh))) |
| f.write("#define AI_OD_SSD_PP_MAX_BOXES_LIMIT ({})\n".format(int(params.postprocessing.max_detection_boxes))) |
| f.write("#define AI_OD_SSD_PP_TOTAL_DETECTIONS ({})\n".format(int(output_details['shape'][1]))) |
| elif (params.model.model_type in ("yolov2t", "st_yololcv1")): |
| f.write("\n/* Postprocessing TINY_YOLO_V2 configuration */\n") |
|
|
| f.write("#define AI_OD_YOLOV2_PP_NB_CLASSES ({})\n".format(len(class_names))) |
| f.write("#define AI_OD_YOLOV2_PP_NB_ANCHORS ({})\n".format(int(len(params.postprocessing.yolo_anchors)))) |
| f.write("#define AI_OD_YOLOV2_PP_GRID_WIDTH ({})\n".format(int(input_shape[1]//params.postprocessing.network_stride))) |
| f.write("#define AI_OD_YOLOV2_PP_GRID_HEIGHT ({})\n".format(int(input_shape[1]//params.postprocessing.network_stride))) |
| f.write("#define AI_OD_YOLOV2_PP_NB_INPUT_BOXES (AI_OD_YOLOV2_PP_GRID_WIDTH * AI_OD_YOLOV2_PP_GRID_HEIGHT)\n") |
| anchors_string = "{" + ", ".join([f"{x:.6f}" for row in params.postprocessing.yolo_anchors for x in row]) + "}" |
| f.write("static const float32_t AI_OD_YOLOV2_PP_ANCHORS[2*AI_OD_YOLOV2_PP_NB_ANCHORS] ={};\n".format(anchors_string)) |
| f.write("#define AI_OD_YOLOV2_PP_CONF_THRESHOLD ({})\n".format(float(params.postprocessing.confidence_thresh))) |
| f.write("#define AI_OD_YOLOV2_PP_IOU_THRESHOLD ({})\n".format(float(params.postprocessing.NMS_thresh))) |
| f.write("#define AI_OD_YOLOV2_PP_MAX_BOXES_LIMIT ({})\n".format(int(params.postprocessing.max_detection_boxes))) |
|
|
| elif (params.model.model_type == "st_yoloxn"): |
| f.write("\n/* Postprocessing ST_YOLO_X configuration */\n") |
| yolo_anchors = np.concatenate(params.postprocessing.yolo_anchors).flatten() |
| f.write("#define AI_OD_ST_YOLOX_PP_NB_CLASSES ({})\n".format(len(class_names))) |
|
|
| f.write("#define AI_OD_ST_YOLOX_PP_L_GRID_WIDTH ({})\n".format(int(input_shape[2]//params.postprocessing.network_stride[0]))) |
| f.write("#define AI_OD_ST_YOLOX_PP_L_GRID_HEIGHT ({})\n".format(int(input_shape[1]//params.postprocessing.network_stride[0]))) |
| f.write("#define AI_OD_ST_YOLOX_PP_L_NB_INPUT_BOXES (AI_OD_ST_YOLOX_PP_L_GRID_WIDTH * AI_OD_ST_YOLOX_PP_L_GRID_HEIGHT)\n") |
|
|
| f.write("#define AI_OD_ST_YOLOX_PP_M_GRID_WIDTH ({})\n".format(int(input_shape[2]//params.postprocessing.network_stride[1]))) |
| f.write("#define AI_OD_ST_YOLOX_PP_M_GRID_HEIGHT ({})\n".format(int(input_shape[1]//params.postprocessing.network_stride[1]))) |
| f.write("#define AI_OD_ST_YOLOX_PP_M_NB_INPUT_BOXES (AI_OD_ST_YOLOX_PP_M_GRID_WIDTH * AI_OD_ST_YOLOX_PP_M_GRID_HEIGHT)\n") |
|
|
| f.write("#define AI_OD_ST_YOLOX_PP_S_GRID_WIDTH ({})\n".format(int(input_shape[2]//params.postprocessing.network_stride[2]))) |
| f.write("#define AI_OD_ST_YOLOX_PP_S_GRID_HEIGHT ({})\n".format(int(input_shape[1]//params.postprocessing.network_stride[2]))) |
| f.write("#define AI_OD_ST_YOLOX_PP_S_NB_INPUT_BOXES (AI_OD_ST_YOLOX_PP_S_GRID_WIDTH * AI_OD_ST_YOLOX_PP_S_GRID_HEIGHT)\n") |
|
|
| f.write("#define AI_OD_ST_YOLOX_PP_NB_ANCHORS ({})\n".format(int(len(yolo_anchors)/2))) |
|
|
| anchors_string = "{" + ", ".join([f"{(x*int(input_shape[2]//params.postprocessing.network_stride[0])):.6f}" for row in params.postprocessing.yolo_anchors for x in row]) + "}" |
| f.write("static const float32_t AI_OD_ST_YOLOX_PP_L_ANCHORS[2*AI_OD_ST_YOLOX_PP_NB_ANCHORS] ={};\n".format(anchors_string)) |
|
|
| anchors_string = "{" + ", ".join([f"{(x*int(input_shape[2]//params.postprocessing.network_stride[1])):.6f}" for row in params.postprocessing.yolo_anchors for x in row]) + "}" |
| f.write("static const float32_t AI_OD_ST_YOLOX_PP_M_ANCHORS[2*AI_OD_ST_YOLOX_PP_NB_ANCHORS] ={};\n".format(anchors_string)) |
|
|
| anchors_string = "{" + ", ".join([f"{(x*int(input_shape[2]//params.postprocessing.network_stride[2])):.6f}" for row in params.postprocessing.yolo_anchors for x in row]) + "}" |
| f.write("static const float32_t AI_OD_ST_YOLOX_PP_S_ANCHORS[2*AI_OD_ST_YOLOX_PP_NB_ANCHORS] ={};\n".format(anchors_string)) |
|
|
| f.write("#define AI_OD_ST_YOLOX_PP_IOU_THRESHOLD ({})\n".format(float(params.postprocessing.NMS_thresh))) |
| f.write("#define AI_OD_ST_YOLOX_PP_CONF_THRESHOLD ({})\n".format(float(params.postprocessing.confidence_thresh))) |
| f.write("#define AI_OD_ST_YOLOX_PP_MAX_BOXES_LIMIT ({})\n".format(int(params.postprocessing.max_detection_boxes))) |
|
|
| elif (params.model.model_type in ("yolov8n", "yolov11n", "yolov5u")): |
| f.write("\n/* Postprocessing YOLO_V8 configuration */\n") |
|
|
| if quantized_model_path.lower().endswith('.tflite'): |
| out_shape = output_details["shape"] |
| elif quantized_model_path.lower().endswith('.onnx'): |
| out_shape = outputs[0].shape |
| else: |
| raise TypeError("Please provide a TFLITE or ONNX model for N6 deployment") |
|
|
| f.write("#define AI_OD_YOLOV8_PP_NB_CLASSES ({})\n".format(int(out_shape[1]-4))) |
| f.write("#define AI_OD_YOLOV8_PP_TOTAL_BOXES ({})\n".format(int(out_shape[2]))) |
| f.write("#define AI_OD_YOLOV8_PP_MAX_BOXES_LIMIT ({})\n".format(int(params.postprocessing.max_detection_boxes))) |
| f.write("#define AI_OD_YOLOV8_PP_CONF_THRESHOLD ({})\n".format(float(params.postprocessing.confidence_thresh))) |
| f.write("#define AI_OD_YOLOV8_PP_IOU_THRESHOLD ({})\n".format(float(params.postprocessing.NMS_thresh))) |
|
|
| elif (params.model.model_type in ("face_detect_front")): |
| f.write("\n/* Postprocessing OD_BLAZEFACE configuration */\n") |
|
|
| outs_info = interpreter_quant.get_output_details() |
| |
| output_shapes =[] |
| for buffer in outs_info: |
| output_shapes.append(buffer["shape"]) |
| sorted_shapes = sorted(output_shapes, key=lambda arr: (arr[1], arr[2]), reverse=True) |
|
|
| f.write("#define AI_OD_BLAZEFACE_PP_NB_KEYPOINTS ({})\n".format(int((sorted_shapes[0][2]-4)/2))) |
| f.write("#define AI_OD_BLAZEFACE_PP_NB_CLASSES ({})\n".format(int(sorted_shapes[-1][-1]))) |
| f.write("#define AI_OD_BLAZEFACE_PP_IMG_SIZE ({})\n".format(int(input_shape[1]))) |
| f.write("#define AI_OD_BLAZEFACE_PP_OUT_0_NB_BOXES ({})\n".format(int(sorted_shapes[0][1]))) |
| f.write("#define AI_OD_BLAZEFACE_PP_OUT_1_NB_BOXES ({})\n".format(int(sorted_shapes[-1][1]))) |
|
|
| f.write("#define AI_OD_BLAZEFACE_PP_MAX_BOXES_LIMIT ({})\n".format(int(params.postprocessing.max_detection_boxes))) |
| f.write("#define AI_OD_BLAZEFACE_PP_CONF_THRESHOLD ({})\n".format(float(params.postprocessing.confidence_thresh))) |
| f.write("#define AI_OD_BLAZEFACE_PP_IOU_THRESHOLD ({})\n".format(float(params.postprocessing.NMS_thresh))) |
|
|
|
|
|
|
| f.write('#define WELCOME_MSG_1 "{}"\n'.format(os.path.basename(params.model.model_path))) |
| |
| if config.deployment.hardware_setup.board == 'NUCLEO-N657X0-Q': |
| f.write('#define WELCOME_MSG_2 ((char *[2]) {"Model Running in STM32 MCU", "internal memory"})') |
| else: |
| f.write('#define WELCOME_MSG_2 "{}"\n'.format("Model Running in STM32 MCU internal memory")) |
|
|
| f.write("\n") |
| f.write("#endif /* APP_CONFIG */\n") |
|
|
| return TFLite_Detection_PostProcess_id, quantized_model_path |
|
|
|
|
| def gen_h_user_file_n6_onnx_ssd(config, quantized_model_path: str = None) -> None: |
|
|
| """ |
| Generates a C header file containing user configuration for the AI model. |
| |
| Args: |
| config: A configuration object containing user configuration for the AI model. |
| quantized_model_path: The path to the quantized model file. |
| |
| """ |
|
|
| import onnxruntime |
| import sys |
|
|
| params = config |
|
|
| model = onnxruntime.InferenceSession(quantized_model_path) |
| inputs = model.get_inputs() |
| outputs = model.get_outputs() |
| input_shape_raw = inputs[0].shape |
|
|
| class_names = params.dataset.class_names |
|
|
| path = os.path.join(HydraConfig.get().runtime.output_dir, "C_header/") |
|
|
| try: |
| os.mkdir(path) |
| except OSError as error: |
| print(error) |
|
|
| classes = '{\\\n"background",' |
|
|
| for i, x in enumerate(params.dataset.class_names): |
| if i == (len(class_names) - 1): |
| classes = classes + ' "' + str(x) + '"' + '}\\' |
| else: |
| classes = classes + ' "' + str(x) + '"' + ' ,' + ('\\\n' if (i % 5 == 0 and i != 0) else '') |
| |
| if params.model.model_type == "ssd": |
| from object_detection.tf.src.postprocessing import generate_ssd_priors |
| center_variance = 0.1 |
| size_variance = 0.2 |
|
|
| image_size = (input_shape_raw[2], input_shape_raw[3], input_shape_raw[1]) |
| model_anchor_centers = generate_ssd_priors(image_size[0]) |
|
|
| anch_arr = model_anchor_centers.numpy() |
|
|
| anch_flat = anch_arr.reshape(int(anch_arr.shape[0] * anch_arr.shape[1])) |
| |
| formatted_anch_flat = ", ".join(f"{float(x)}" for x in anch_flat) |
| c_anch_str = f"const float32_t g_Anchors[{int(anch_arr.shape[0] * anch_arr.shape[1])}] = {{ {formatted_anch_flat} }};" |
|
|
| with open(os.path.join(path, "ssd_anchors.h"), "wt") as f: |
| f.write("#ifndef __ANCHORS_H__\n") |
| f.write("#define __ANCHORS_H__\n\n") |
| f.write(c_anch_str) |
| f.write("\n") |
| f.write("#endif /* __ANCHORS_H__ */\n") |
|
|
| |
| anchors_path_C = os.path.join(params.deployment.c_project_path, 'Application', params.deployment.hardware_setup.board, 'Inc', 'ssd_anchors.h') |
|
|
|
|
| if os.path.exists(anchors_path_C): |
| os.remove(anchors_path_C) |
| |
|
|
| shutil.copy(os.path.join(path, "ssd_anchors.h"), anchors_path_C) |
|
|
| with open(os.path.join(path, "app_config.h"), "wt") as f: |
| f.write("/**\n") |
| f.write("******************************************************************************\n") |
| f.write("* @file app_config.h\n") |
| f.write("* @author GPM Application Team\n") |
| f.write("*\n") |
| f.write("******************************************************************************\n") |
| f.write("* @attention\n") |
| f.write("*\n") |
| f.write("* Copyright (c) 2023 STMicroelectronics.\n") |
| f.write("* All rights reserved.\n") |
| f.write("*\n") |
| f.write("* This software is licensed under terms that can be found in the LICENSE file\n") |
| f.write("* in the root directory of this software component.\n") |
| f.write("* If no LICENSE file comes with this software, it is provided AS-IS.\n") |
| f.write("*\n") |
| f.write("******************************************************************************\n") |
| f.write("*/\n\n") |
| f.write("/* --------------- Generated code ----------------- */\n") |
| f.write("#ifndef APP_CONFIG\n") |
| f.write("#define APP_CONFIG\n\n") |
| f.write('#include "arm_math.h"\n\n') |
| f.write("#define USE_DCACHE\n\n") |
| f.write("/*Defines: CMW_MIRRORFLIP_NONE; CMW_MIRRORFLIP_FLIP; CMW_MIRRORFLIP_MIRROR; CMW_MIRRORFLIP_FLIP_MIRROR;*/\n") |
| f.write("#define CAMERA_FLIP CMW_MIRRORFLIP_NONE\n\n") |
| f.write("") |
| f.write("#define ASPECT_RATIO_CROP (1) /* Crop both pipes to nn input aspect ratio; Original aspect ratio kept */\n") |
| f.write("#define ASPECT_RATIO_FIT (2) /* Resize both pipe to NN input aspect ratio; Original aspect ratio not kept */\n") |
| f.write("#define ASPECT_RATIO_FULLSCREEN (3) /* Resize camera image to NN input size and display a fullscreen image */\n") |
| f.write("#define ASPECT_RATIO_MODE {}\n".format(aspect_ratio_dict[params.preprocessing.resizing.aspect_ratio])) |
| f.write("\n") |
|
|
| f.write("/* Postprocessing type configuration */\n") |
|
|
| if params.model.model_type == "ssd": |
| f.write("#define POSTPROCESS_TYPE POSTPROCESS_OD_SSD_UI\n") |
| else: |
| raise TypeError("Please select one of the supported model_type") |
| f.write("\n") |
| f.write("#define COLOR_BGR (0)\n") |
| f.write("#define COLOR_RGB (1)\n") |
| f.write("#define COLOR_MODE {}\n".format(color_mode_n6_dict[params.preprocessing.color_mode])) |
|
|
| f.write("/* Classes */\n") |
| f.write("#define NB_CLASSES ({})\n".format(len(class_names)+1)) |
| f.write("#define CLASSES_TABLE const char* classes_table[NB_CLASSES] = {}\n".format(classes)) |
|
|
| if params.model.model_type == "ssd": |
| f.write("\n/* Postprocessing SSD configuration */\n") |
|
|
| f.write("#define AI_OD_SSD_PP_NB_CLASSES ({})\n".format(len(class_names)+1)) |
| f.write("#define AI_OD_SSD_PP_TOTAL_DETECTIONS ({})\n".format(int(anch_arr.shape[0]))) |
| f.write("#define AI_OD_SSD_PP_XY_VARIANCE ({})\n".format(float(center_variance))) |
| f.write("#define AI_OD_SSD_PP_WH_VARIANCE ({})\n".format(float(size_variance))) |
|
|
| f.write("#define AI_OD_SSD_PP_MAX_BOXES_LIMIT ({})\n".format(int(params.postprocessing.max_detection_boxes))) |
| f.write("#define AI_OD_SSD_PP_CONF_THRESHOLD ({})\n".format(float(params.postprocessing.confidence_thresh))) |
| f.write("#define AI_OD_SSD_PP_IOU_THRESHOLD ({})\n".format(float(params.postprocessing.NMS_thresh))) |
|
|
|
|
|
|
| f.write('#define WELCOME_MSG_1 "{}"\n'.format(os.path.basename(params.model.model_path))) |
| |
| if config.deployment.hardware_setup.board == 'NUCLEO-N657X0-Q': |
| f.write('#define WELCOME_MSG_2 ((char *[2]) {"Model Running in STM32 MCU", "internal memory"})') |
| else: |
| f.write('#define WELCOME_MSG_2 "{}"\n'.format("Model Running in STM32 MCU internal memory")) |
|
|
| f.write("\n") |
| f.write("#endif /* APP_CONFIG */\n") |
|
|
| return None, quantized_model_path |
|
|
| def gen_h_user_file_n6_onnx_yolod(config, quantized_model_path: str = None) -> None: |
|
|
| """ |
| Generates a C header file containing user configuration for the AI model. |
| |
| Args: |
| config: A configuration object containing user configuration for the AI model. |
| quantized_model_path: The path to the quantized model file. |
| |
| """ |
|
|
| import onnxruntime |
| import sys |
|
|
| params = config |
|
|
| model = onnxruntime.InferenceSession(quantized_model_path) |
| inputs = model.get_inputs() |
| outputs = model.get_outputs() |
| input_shape_raw = inputs[0].shape |
|
|
| class_names = params.dataset.class_names |
|
|
| path = os.path.join(HydraConfig.get().runtime.output_dir, "C_header/") |
|
|
| try: |
| os.mkdir(path) |
| except OSError as error: |
| print(error) |
|
|
| classes = '{\\\n' |
|
|
| for i, x in enumerate(params.dataset.class_names): |
| if i == (len(class_names) - 1): |
| classes = classes + ' "' + str(x) + '"' + '}\\' |
| else: |
| classes = classes + ' "' + str(x) + '"' + ' ,' + ('\\\n' if (i % 5 == 0 and i != 0) else '') |
| |
| if params.model.model_type == "st_yolod": |
| image_size = (input_shape_raw[2], input_shape_raw[3], input_shape_raw[1]) |
|
|
| with open(os.path.join(path, "app_config.h"), "wt") as f: |
| f.write("/**\n") |
| f.write("******************************************************************************\n") |
| f.write("* @file app_config.h\n") |
| f.write("* @author GPM Application Team\n") |
| f.write("*\n") |
| f.write("******************************************************************************\n") |
| f.write("* @attention\n") |
| f.write("*\n") |
| f.write("* Copyright (c) 2023 STMicroelectronics.\n") |
| f.write("* All rights reserved.\n") |
| f.write("*\n") |
| f.write("* This software is licensed under terms that can be found in the LICENSE file\n") |
| f.write("* in the root directory of this software component.\n") |
| f.write("* If no LICENSE file comes with this software, it is provided AS-IS.\n") |
| f.write("*\n") |
| f.write("******************************************************************************\n") |
| f.write("*/\n\n") |
| f.write("/* --------------- Generated code ----------------- */\n") |
| f.write("#ifndef APP_CONFIG\n") |
| f.write("#define APP_CONFIG\n\n") |
| f.write('#include "arm_math.h"\n\n') |
| f.write("#define USE_DCACHE\n\n") |
| f.write("/*Defines: CMW_MIRRORFLIP_NONE; CMW_MIRRORFLIP_FLIP; CMW_MIRRORFLIP_MIRROR; CMW_MIRRORFLIP_FLIP_MIRROR;*/\n") |
| f.write("#define CAMERA_FLIP CMW_MIRRORFLIP_NONE\n\n") |
| f.write("") |
| f.write("#define ASPECT_RATIO_CROP (1) /* Crop both pipes to nn input aspect ratio; Original aspect ratio kept */\n") |
| f.write("#define ASPECT_RATIO_FIT (2) /* Resize both pipe to NN input aspect ratio; Original aspect ratio not kept */\n") |
| f.write("#define ASPECT_RATIO_FULLSCREEN (3) /* Resize camera image to NN input size and display a fullscreen image */\n") |
| f.write("#define ASPECT_RATIO_MODE {}\n".format(aspect_ratio_dict[params.preprocessing.resizing.aspect_ratio])) |
| f.write("\n") |
|
|
| f.write("/* Postprocessing type configuration */\n") |
|
|
| if params.model.model_type == "st_yolod": |
| f.write("#define POSTPROCESS_TYPE POSTPROCESS_OD_ST_YOLOD_UI\n") |
| else: |
| raise TypeError("Please select one of the supported model_type") |
| f.write("\n") |
| f.write("#define COLOR_BGR (0)\n") |
| f.write("#define COLOR_RGB (1)\n") |
| f.write("#define COLOR_MODE {}\n".format(color_mode_n6_dict[params.preprocessing.color_mode])) |
|
|
| f.write("/* Classes */\n") |
| f.write("#define NB_CLASSES ({})\n".format(len(class_names))) |
| f.write("#define CLASSES_TABLE const char* classes_table[NB_CLASSES] = {}\n".format(classes)) |
|
|
| if params.model.model_type == "st_yolod": |
| f.write("\n/* Postprocessing ST_YOLOD configuration */\n") |
|
|
| f.write("#define AI_OD_YOLO_D_PP_NB_CLASSES ({})\n".format(len(class_names))) |
| f.write("#define AI_OD_YOLO_D_PP_IMG_WIDTH ({})\n".format(int(image_size[0]))) |
| f.write("#define AI_OD_YOLO_D_PP_IMG_HEIGHT ({})\n".format(int(image_size[1]))) |
| f.write("#define AI_OD_YOLO_D_PP_STRIDE_0 ({})\n".format(8)) |
| f.write("#define AI_OD_YOLO_D_PP_STRIDE_1 ({})\n".format(16)) |
| f.write("#define AI_OD_YOLO_D_PP_STRIDE_2 ({})\n".format(32)) |
|
|
| f.write("#define AI_OD_YOLO_D_PP_MAX_BOXES_LIMIT ({})\n".format(int(params.postprocessing.max_detection_boxes))) |
| f.write("#define AI_OD_YOLO_D_PP_CONF_THRESHOLD ({})\n".format(float(params.postprocessing.confidence_thresh))) |
| f.write("#define AI_OD_YOLO_D_PP_IOU_THRESHOLD ({})\n".format(float(params.postprocessing.NMS_thresh))) |
|
|
|
|
|
|
| f.write('#define WELCOME_MSG_1 "{}"\n'.format(os.path.basename(params.model.model_path))) |
| |
| if config.deployment.hardware_setup.board == 'NUCLEO-N657X0-Q': |
| f.write('#define WELCOME_MSG_2 ((char *[2]) {"Model Running in STM32 MCU", "internal memory"})') |
| else: |
| f.write('#define WELCOME_MSG_2 "{}"\n'.format("Model Running in STM32 MCU internal memory")) |
|
|
| f.write("\n") |
| f.write("#endif /* APP_CONFIG */\n") |
|
|
| return None, quantized_model_path |