From: Inki Dae Date: Fri, 5 Jun 2020 04:56:08 +0000 (+0900) Subject: mv_inference: Add MLAPI backend support X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fheads%2Ftizen_ACR_MLAPI;p=platform%2Fcore%2Fapi%2Fmediavision.git mv_inference: Add MLAPI backend support This patch adds ML Single API support to MediaVision framework. On MediaVision, Vivante NPU, SRNPU and ONE will be controlled by inference-engine-mlapi backend which interfaces with ML Single API of NNStreamer. Change-Id: I89480f68a885c6ff0da13a46bc54eba6973a1431 Signed-off-by: Inki Dae --- diff --git a/include/mv_inference_type.h b/include/mv_inference_type.h index 41a9e9de..29976827 100644 --- a/include/mv_inference_type.h +++ b/include/mv_inference_type.h @@ -44,6 +44,8 @@ typedef enum { MV_INFERENCE_BACKEND_OPENCV, /**< OpenCV */ MV_INFERENCE_BACKEND_TFLITE, /**< TensorFlow-Lite */ MV_INFERENCE_BACKEND_ARMNN, /**< ARMNN (Since 6.0) */ + MV_INFERENCE_BACKEND_MLAPI, /**< ML Single API of NNStreamer (Since 6.0) */ + MV_INFERENCE_BACKEND_ONE, /**< On-device Neural Engine (Since 6.0) */ MV_INFERENCE_BACKEND_MAX /**< Backend MAX */ } mv_inference_backend_type_e; diff --git a/mv_inference/inference/src/Inference.cpp b/mv_inference/inference/src/Inference.cpp index 5a12b350..f3d0d0d2 100755 --- a/mv_inference/inference/src/Inference.cpp +++ b/mv_inference/inference/src/Inference.cpp @@ -83,6 +83,8 @@ Inference::Inference() : mSupportedInferenceBackend.insert(std::make_pair(MV_INFERENCE_BACKEND_OPENCV, std::make_pair("opencv", false))); mSupportedInferenceBackend.insert(std::make_pair(MV_INFERENCE_BACKEND_TFLITE, std::make_pair("tflite", false))); mSupportedInferenceBackend.insert(std::make_pair(MV_INFERENCE_BACKEND_ARMNN, std::make_pair("armnn", false))); + mSupportedInferenceBackend.insert(std::make_pair(MV_INFERENCE_BACKEND_MLAPI, std::make_pair("mlapi", false))); + mSupportedInferenceBackend.insert(std::make_pair(MV_INFERENCE_BACKEND_ONE, std::make_pair("mlapi", false))); CheckSupportedInferenceBackend(); @@ -98,6 +100,7 @@ Inference::Inference() : mModelFormats.insert(std::make_pair("weights", INFERENCE_MODEL_DARKNET)); mModelFormats.insert(std::make_pair("bin", INFERENCE_MODEL_DLDT)); mModelFormats.insert(std::make_pair("onnx", INFERENCE_MODEL_ONNX)); + mModelFormats.insert(std::make_pair("nb", INFERENCE_MODEL_VIVANTE)); LOGI("LEAVE"); } @@ -288,7 +291,7 @@ int Inference::Preprocess(cv::Mat cvImg, cv::Mat cvDst, int data_type) cv::subtract(sampleFloat, meanMat, sampleNormalized); - sampleNormalized /= (float)mDeviation; + sampleNormalized /= static_cast(mDeviation); sampleNormalized.convertTo(cvDst, data_type); @@ -357,7 +360,7 @@ void Inference::ConfigureInputInfo(int width, mConfig.mTensorInfo = {width, height, dim, ch}; mConfig.mStdValue = stdValue; mConfig.mMeanValue = meanValue; - mConfig.mDataType = (mv_inference_data_type_e)dataType; + mConfig.mDataType = static_cast(dataType); mConfig.mInputLayerNames = names; inference_engine_layer_property property; @@ -500,9 +503,9 @@ void Inference::CleanupTensorBuffers(void) } if (tensor_buffer.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT32) - delete[] (float *)tensor_buffer.buffer; + delete[] static_cast(tensor_buffer.buffer); else - delete[] (unsigned char *)tensor_buffer.buffer; + delete[] static_cast(tensor_buffer.buffer); } LOGI("input tensor buffers(%zu) have been released.", mInputTensorBuffers.size()); @@ -521,9 +524,9 @@ void Inference::CleanupTensorBuffers(void) } if (tensor_buffer.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT32) - delete[] (float *)tensor_buffer.buffer; + delete[] static_cast(tensor_buffer.buffer); else - delete[] (unsigned char *)tensor_buffer.buffer; + delete[] static_cast(tensor_buffer.buffer); } LOGI("output tensor buffers(%zu) have been released.", mOutputTensorBuffers.size()); @@ -571,10 +574,13 @@ int Inference::PrepareTenosrBuffers(void) inference_engine_tensor_info tensor_info = mInputLayerProperty.tensor_infos[i]; inference_engine_tensor_buffer tensor_buffer; if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT32) { - tensor_buffer.buffer = (void *)(new float[tensor_info.size]); + tensor_buffer.buffer = new float[tensor_info.size]; tensor_buffer.size = tensor_info.size * 4; } else if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_UINT8) { - tensor_buffer.buffer = (void *)(new unsigned char[tensor_info.size]); + tensor_buffer.buffer = new unsigned char[tensor_info.size]; + tensor_buffer.size = tensor_info.size; + } else if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT16) { + tensor_buffer.buffer = new short[tensor_info.size]; tensor_buffer.size = tensor_info.size; } else { LOGE("Invalid input tensor data type."); @@ -620,6 +626,9 @@ int Inference::PrepareTenosrBuffers(void) } else if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_UINT8) { tensor_buffer.buffer = new char[tensor_info.size]; tensor_buffer.size = tensor_info.size; + } else if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT16) { + tensor_buffer.buffer = new short[tensor_info.size]; + tensor_buffer.size = tensor_info.size; } else { LOGE("Invalid output tensor data type."); CleanupTensorBuffers(); @@ -651,7 +660,7 @@ int Inference::FillOutputResult(tensor_t &outputData) inference_engine_tensor_info tensor_info = mOutputLayerProperty.tensor_infos[i]; std::vector tmpDimInfo; - for (int i = 0; i < (int)tensor_info.shape.size(); i++) { + for (int i = 0; i < static_cast(tensor_info.shape.size()); i++) { tmpDimInfo.push_back(tensor_info.shape[i]); } @@ -659,23 +668,46 @@ int Inference::FillOutputResult(tensor_t &outputData) // Normalize output tensor data converting it to float type in case of quantized model. if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_UINT8) { - unsigned char *ori_buf = (unsigned char *)mOutputTensorBuffers[i].buffer; float *new_buf = new float[tensor_info.size]; if (new_buf == NULL) { LOGE("Fail to allocate a new output tensor buffer."); return MEDIA_VISION_ERROR_OUT_OF_MEMORY; } + unsigned char *ori_buf = static_cast(mOutputTensorBuffers[i].buffer); + for (int j = 0; j < tensor_info.size; j++) { - new_buf[j] = (float)ori_buf[j] / 255.0f; + new_buf[j] = static_cast(ori_buf[j]) / 255.0f; } // replace original buffer with new one, and release origin one. mOutputTensorBuffers[i].buffer = new_buf; - delete[] ori_buf; + + if (!mOutputTensorBuffers[i].owner_is_backend) + delete[] ori_buf; } - outputData.data.push_back((void *)mOutputTensorBuffers[i].buffer); + if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT16) { + float *new_buf = new float[tensor_info.size]; + if (new_buf == NULL) { + LOGE("Fail to allocate a new output tensor buffer."); + return MEDIA_VISION_ERROR_OUT_OF_MEMORY; + } + + short *ori_buf = static_cast(mOutputTensorBuffers[i].buffer); + + for (int j = 0; j < tensor_info.size; j++) { + new_buf[j] = static_cast(ori_buf[j]); + } + + // replace original buffer with new one, and release origin one. + mOutputTensorBuffers[i].buffer = new_buf; + + if (!mOutputTensorBuffers[i].owner_is_backend) + delete[] ori_buf; + } + + outputData.data.push_back(static_cast(mOutputTensorBuffers[i].buffer)); } return MEDIA_VISION_ERROR_NONE; @@ -697,6 +729,7 @@ int Inference::Bind(void) inference_engine_config config = { .backend_name = backendName, + .backend_type = mConfig.mBackedType, // As a default, Target device is CPU. If user defined desired device type in json file // then the device type will be set by Load callback. .target_devices = mConfig.mTargetTypes, @@ -806,7 +839,7 @@ int Inference::Load(void) std::vector models; - inference_model_format_e model_format = (inference_model_format_e)key->second; + inference_model_format_e model_format = static_cast(key->second); // Push model file information to models vector properly according to detected model format. switch (model_format) { @@ -815,6 +848,7 @@ int Inference::Load(void) case INFERENCE_MODEL_DARKNET: case INFERENCE_MODEL_DLDT: case INFERENCE_MODEL_ONNX: + case INFERENCE_MODEL_VIVANTE: models.push_back(mConfig.mWeightFilePath); models.push_back(mConfig.mConfigFilePath); break; @@ -1036,7 +1070,7 @@ int Inference::GetObjectDetectionResults(ObjectDetectionResults *detectionResult // indicats the image id. But it is useless if a batch mode isn't supported. // So, use the 1st of 7. - number_of_detections = (int)(*reinterpret_cast(outputData.data[0])); + number_of_detections = static_cast(*reinterpret_cast(outputData.data[0])); cv::Mat cvOutputData(number_of_detections, inferDimInfo[0][3], CV_32F, outputData.data[0]); // boxes @@ -1077,23 +1111,23 @@ int Inference::GetObjectDetectionResults(ObjectDetectionResults *detectionResult if (scores[idx] < mThreshold) continue; - left = (int)(boxes[idx*4 + 1] * mSourceSize.width); - top = (int)(boxes[idx*4 + 0] * mSourceSize.height); - right = (int)(boxes[idx*4 + 3] * mSourceSize.width); - bottom = (int)(boxes[idx*4 + 2] * mSourceSize.height); + left = static_cast(boxes[idx*4 + 1] * mSourceSize.width); + top = static_cast(boxes[idx*4 + 0] * mSourceSize.height); + right = static_cast(boxes[idx*4 + 3] * mSourceSize.width); + bottom = static_cast(boxes[idx*4 + 2] * mSourceSize.height); loc.x = left; loc.y = top; loc.width = right -left + 1; loc.height = bottom - top + 1; - results.indices.push_back((int)classes[idx]); + results.indices.push_back(static_cast(classes[idx])); results.confidences.push_back(scores[idx]); - results.names.push_back(mUserListName[(int)classes[idx]]); + results.names.push_back(mUserListName[static_cast(classes[idx])]); results.locations.push_back(loc); results.number_of_objects++; - LOGI("objectClass: %d", (int)classes[idx]); + LOGI("objectClass: %d", static_cast(classes[idx])); LOGI("confidence:%f", scores[idx]); LOGI("left:%d, top:%d, right:%d, bottom:%d", left, top, right, bottom); } @@ -1137,7 +1171,7 @@ int Inference::GetFaceDetectionResults(FaceDetectionResults *detectionResults) // indicats the image id. But it is useless if a batch mode isn't supported. // So, use the 1st of 7. - number_of_detections = (int)(*reinterpret_cast(outputData.data[0])); + number_of_detections = static_cast(*reinterpret_cast(outputData.data[0])); cv::Mat cvOutputData(number_of_detections, inferDimInfo[0][3], CV_32F, outputData.data[0]); // boxes @@ -1163,7 +1197,7 @@ int Inference::GetFaceDetectionResults(FaceDetectionResults *detectionResults) boxes = reinterpret_cast(inferResults[0]); classes = reinterpret_cast(inferResults[1]); scores = reinterpret_cast(inferResults[2]); - number_of_detections = (int)(*reinterpret_cast(inferResults[3])); + number_of_detections = static_cast(*reinterpret_cast(inferResults[3])); } int left, top, right, bottom; @@ -1175,10 +1209,10 @@ int Inference::GetFaceDetectionResults(FaceDetectionResults *detectionResults) if (scores[idx] < mThreshold) continue; - left = (int)(boxes[idx*4 + 1] * mSourceSize.width); - top = (int)(boxes[idx*4 + 0] * mSourceSize.height); - right = (int)(boxes[idx*4 + 3] * mSourceSize.width); - bottom = (int)(boxes[idx*4 + 2] * mSourceSize.height); + left = static_cast(boxes[idx*4 + 1] * mSourceSize.width); + top = static_cast(boxes[idx*4 + 0] * mSourceSize.height); + right = static_cast(boxes[idx*4 + 3] * mSourceSize.width); + bottom = static_cast(boxes[idx*4 + 2] * mSourceSize.height); loc.x = left; loc.y = top; @@ -1224,8 +1258,8 @@ int Inference::GetFacialLandMarkDetectionResults(FacialLandMarkDetectionResults results.number_of_landmarks = 0; LOGI("imgW:%d, imgH:%d", mSourceSize.width, mSourceSize.height); for (int idx = 0; idx < number_of_detections; idx+=2) { - point.x = (int)(loc[idx] * mSourceSize.width); - point.y = (int)(loc[idx+1] * mSourceSize.height); + point.x = static_cast(loc[idx] * mSourceSize.width); + point.y = static_cast(loc[idx+1] * mSourceSize.height); results.locations.push_back(point); results.number_of_landmarks++; @@ -1265,8 +1299,8 @@ int Inference::GetPoseEstimationDetectionResults(PoseEstimationResults *detectio cv::Mat multiChannels[inferDimInfo[0][3]]; split(reShapeTest, multiChannels); - float ratioX = (float)mSourceSize.width / (float)inferDimInfo[0][2]; - float ratioY = (float)mSourceSize.height / (float)inferDimInfo[0][1]; + float ratioX = static_cast(mSourceSize.width) / static_cast(inferDimInfo[0][2]); + float ratioY = static_cast(mSourceSize.height) / static_cast(inferDimInfo[0][1]); PoseEstimationResults results; results.number_of_pose_estimation = 0; @@ -1277,10 +1311,10 @@ int Inference::GetPoseEstimationDetectionResults(PoseEstimationResults *detectio cv::minMaxLoc(heatMap, NULL, &score, NULL, &loc); LOGI("PoseIdx[%2d]: x[%2d], y[%2d], score[%.3f]", poseIdx, loc.x, loc.y, score); - LOGI("PoseIdx[%2d]: x[%2d], y[%2d], score[%.3f]", poseIdx, (int)((float)(loc.x+1) * ratioX), (int)((float)(loc.y+1) * ratioY), score); + LOGI("PoseIdx[%2d]: x[%2d], y[%2d], score[%.3f]", poseIdx, static_cast(static_cast(loc.x+1) * ratioX), static_cast(static_cast(loc.y+1) * ratioY), score); - loc.x = (int)((float)(loc.x+1) * ratioX); - loc.y = (int)((float)(loc.y+1) * ratioY); + loc.x = static_cast(static_cast(loc.x+1) * ratioX); + loc.y = static_cast(static_cast(loc.y+1) * ratioY); results.locations.push_back(loc); results.number_of_pose_estimation++; } diff --git a/test/testsuites/inference/inference_test_suite.c b/test/testsuites/inference/inference_test_suite.c index 4c2885f7..11761256 100644 --- a/test/testsuites/inference/inference_test_suite.c +++ b/test/testsuites/inference/inference_test_suite.c @@ -31,12 +31,17 @@ #include #include +#define ARRAY_SIZE(x) (sizeof((x))/sizeof((x)[0])) #define FILE_PATH_SIZE 1024 //Image Classification #define IC_LABEL_PATH "/usr/share/capi-media-vision/models/IC/tflite/ic_label.txt" #define IC_TFLITE_WEIGHT_PATH "/usr/share/capi-media-vision/models/IC/tflite/ic_tflite_model.tflite" +#define IC_VIVANTE_LABEL_PATH "/usr/share/capi-media-vision/models/IC/vivante/ic_label.txt" +#define IC_VIVANTE_WEIGHT_PATH "/usr/share/capi-media-vision/models/IC/vivante/ic_vivante_model.nb" +#define IC_VIVANTE_CONFIG_PATH "/usr/share/capi-media-vision/models/IC/vivante/ic_vivante_model.so" + #define IC_OPENCV_LABEL_CAFFE_PATH "/usr/share/capi-media-vision/models/IC/caffe/ic_caffe_label_squeezenet.txt" #define IC_OPENCV_WEIGHT_CAFFE_PATH "/usr/share/capi-media-vision/models/IC/caffe/ic_caffe_model_squeezenet.caffemodel" #define IC_OPENCV_CONFIG_CAFFE_PATH "/usr/share/capi-media-vision/models/IC/caffe/ic_caffe_model_squeezenet.prototxt" @@ -507,7 +512,7 @@ int perform_configuration(mv_engine_config_h *engine_cfg) } while (sel_opt == 0) { - sel_opt = show_menu("Select Actions: ", options, names, 12); + sel_opt = show_menu("Select Actions: ", options, names, ARRAY_SIZE(options)); switch (sel_opt) { case 1: err = perform_configure_set_model_config_path(handle); @@ -727,6 +732,88 @@ int perform_armnn_mobilenetv1_config(mv_engine_config_h *engine_cfg) return err; } +int perform_vivante_inceptionv3_config(mv_engine_config_h *engine_cfg) +{ + int err = MEDIA_VISION_ERROR_NONE; + + mv_engine_config_h handle = NULL; + err = mv_create_engine_config(&handle); + if (err != MEDIA_VISION_ERROR_NONE) { + printf("Fail to create engine configuration handle.\n"); + if (handle) { + int err2 = mv_destroy_engine_config(handle); + if (err2 != MEDIA_VISION_ERROR_NONE) { + printf("Fail to destroy engine cofniguration.\n"); + } + } + return err; + } + + char *inputNodeName = "input"; + char *outputNodeName[1] = {"InceptionV3/Predictions/Peshape_1"}; + + mv_engine_config_set_string_attribute(handle, + MV_INFERENCE_MODEL_WEIGHT_FILE_PATH, + IC_VIVANTE_WEIGHT_PATH); + + mv_engine_config_set_string_attribute(handle, + MV_INFERENCE_MODEL_CONFIGURATION_FILE_PATH, + IC_VIVANTE_CONFIG_PATH); + + mv_engine_config_set_int_attribute(handle, + MV_INFERENCE_INPUT_DATA_TYPE, + MV_INFERENCE_DATA_UINT8); + + mv_engine_config_set_string_attribute(handle, + MV_INFERENCE_MODEL_USER_FILE_PATH, + IC_VIVANTE_LABEL_PATH); + + mv_engine_config_set_double_attribute(handle, + MV_INFERENCE_MODEL_MEAN_VALUE, + 0.0); + + mv_engine_config_set_double_attribute(handle, + MV_INFERENCE_MODEL_STD_VALUE, + 1.0); + + mv_engine_config_set_double_attribute(handle, + MV_INFERENCE_CONFIDENCE_THRESHOLD, + 0.6); + + mv_engine_config_set_int_attribute(handle, + MV_INFERENCE_BACKEND_TYPE, + MV_INFERENCE_BACKEND_MLAPI); + + mv_engine_config_set_int_attribute(handle, + MV_INFERENCE_TARGET_DEVICE_TYPE, + MV_INFERENCE_TARGET_DEVICE_CUSTOM); + + mv_engine_config_set_int_attribute(handle, + MV_INFERENCE_INPUT_TENSOR_WIDTH, + 299); + + mv_engine_config_set_int_attribute(handle, + MV_INFERENCE_INPUT_TENSOR_HEIGHT, + 299); + + mv_engine_config_set_int_attribute(handle, + MV_INFERENCE_INPUT_TENSOR_CHANNELS, + 3); + + mv_engine_config_set_string_attribute(handle, + MV_INFERENCE_INPUT_NODE_NAME, + inputNodeName); + + mv_engine_config_set_array_string_attribute(handle, + MV_INFERENCE_OUTPUT_NODE_NAMES, + outputNodeName, + 1); + + + *engine_cfg = handle; + return err; +} + int perform_opencv_caffe_squeezenet_config(mv_engine_config_h *engine_cfg) { int err = MEDIA_VISION_ERROR_NONE; @@ -815,11 +902,12 @@ int perform_image_classification() int err = MEDIA_VISION_ERROR_NONE; int sel_opt = 0; - const int options[7] = { 1, 2, 3, 4, 5, 6, 7}; - const char *names[7] = { "Configuration", + const int options[8] = { 1, 2, 3, 4, 5, 6, 7, 8}; + const char *names[8] = { "Configuration", "TFLite(cpu + Mobilenet)", "OpenCV(cpu + Squeezenet)", "ARMNN(cpu + Mobilenet)", + "Vivante(NPU + Inceptionv3)", "Prepare", "Run", "Back"}; @@ -829,7 +917,7 @@ int perform_image_classification() mv_source_h mvSource = NULL; while(sel_opt == 0) { - sel_opt = show_menu("Select Action:", options, names, 7); + sel_opt = show_menu("Select Action:", options, names, ARRAY_SIZE(options)); switch (sel_opt) { case 1: { @@ -884,6 +972,18 @@ int perform_image_classification() } break; case 5: + { + // perform Vivante + if (engine_cfg) { + int err2 = mv_destroy_engine_config(engine_cfg); + if (err2 != MEDIA_VISION_ERROR_NONE) + printf("Fail to destroy engine_cfg [err:%i]\n", err2); + } + + err = perform_vivante_inceptionv3_config(&engine_cfg); + } + break; + case 6: { //create - configure - prepare if (infer) { @@ -916,7 +1016,7 @@ int perform_image_classification() } } break; - case 6: + case 7: { if (mvSource) { int err2 = mv_destroy_source(mvSource); @@ -964,7 +1064,7 @@ int perform_image_classification() } break; - case 7: + case 8: { //perform destroy if (engine_cfg) { @@ -1005,7 +1105,7 @@ int perform_image_classification() const char *names_last[2] = { "Yes", "No" }; while (sel_opt == 0) { - sel_opt = show_menu("Run Image Classification again?: ", options_last, names_last, 2); + sel_opt = show_menu("Run Image Classification again?: ", options_last, names_last, ARRAY_SIZE(options_last)); switch (sel_opt) { case 1: do_another = 1; @@ -1310,7 +1410,7 @@ int perform_object_detection() mv_source_h mvSource = NULL; while(sel_opt == 0) { - sel_opt = show_menu("Select Action:", options, names, 7); + sel_opt = show_menu("Select Action:", options, names, ARRAY_SIZE(options)); switch (sel_opt) { case 1: { @@ -1486,7 +1586,7 @@ int perform_object_detection() const char *names_last[2] = { "Yes", "No" }; while (sel_opt == 0) { - sel_opt = show_menu("Run Object Detection again?:", options_last, names_last, 2); + sel_opt = show_menu("Run Object Detection again?:", options_last, names_last, ARRAY_SIZE(options_last)); switch(sel_opt) { case 1: do_another = 1; @@ -1775,7 +1875,7 @@ int perform_face_detection() mv_source_h mvSource = NULL; while(sel_opt == 0) { - sel_opt = show_menu("Select Action:", options, names, 7); + sel_opt = show_menu("Select Action:", options, names, ARRAY_SIZE(options)); switch (sel_opt) { case 1: { @@ -1948,7 +2048,7 @@ int perform_face_detection() const char *names_last[2] = { "Yes", "No" }; while (sel_opt == 0) { - sel_opt = show_menu("Run Face Detection again?:", options_last, names_last, 2); + sel_opt = show_menu("Run Face Detection again?:", options_last, names_last, ARRAY_SIZE(options_last)); switch(sel_opt) { case 1: do_another = 1; @@ -2149,7 +2249,7 @@ int perform_facial_landmark_detection() mv_source_h mvSource = NULL; while(sel_opt == 0) { - sel_opt = show_menu("Select Action:", options, names, 6); + sel_opt = show_menu("Select Action:", options, names, ARRAY_SIZE(options)); switch (sel_opt) { case 1: { @@ -2308,7 +2408,7 @@ int perform_facial_landmark_detection() const char *names_last[2] = { "Yes", "No" }; while (sel_opt == 0) { - sel_opt = show_menu("Run Facial Landmark Detection again?:", options_last, names_last, 2); + sel_opt = show_menu("Run Facial Landmark Detection again?:", options_last, names_last, ARRAY_SIZE(options_last)); switch(sel_opt) { case 1: do_another = 1; @@ -2435,7 +2535,7 @@ int perform_pose_estimation_detection() mv_source_h mvSource = NULL; while(sel_opt == 0) { - sel_opt = show_menu("Select Action:", options, names, 5); + sel_opt = show_menu("Select Action:", options, names, ARRAY_SIZE(options)); switch (sel_opt) { case 1: { @@ -2574,7 +2674,7 @@ int perform_pose_estimation_detection() const char *names_last[2] = { "Yes", "No" }; while (sel_opt == 0) { - sel_opt = show_menu("Run Pose Estimation Detection again?:", options_last, names_last, 2); + sel_opt = show_menu("Run Pose Estimation Detection again?:", options_last, names_last, ARRAY_SIZE(options_last)); switch(sel_opt) { case 1: do_another = 1; @@ -2608,7 +2708,7 @@ int main() int err = MEDIA_VISION_ERROR_NONE; while (sel_opt == 0) { - sel_opt = show_menu("Select Action:", options, names, 5); + sel_opt = show_menu("Select Action:", options, names, ARRAY_SIZE(options)); switch (sel_opt) { case 1: {