* Solve some code style issues Change-Id: I06c31ad9513463c758db96dbe33031983a8fd7a5 * Refine ov_dimension with C style structure Use C style definition to replace opaque C++ handle: 1). Improve partial shape 2). Improve dimension/rank 3). Improve shape Change-Id: I680fd3e76c63d0c06d9d8b07c67af0440fb15bb7 * Some minor update Change-Id: I237490a765e6ecd6f3896b1bd75d5f962304f43b * add partial_shape_is_dynamic and update doc Change-Id: Ief358f27de8386e35485d08847c8243d1490157f * Rename property and add basic test cases Change-Id: Ifbed0bbf7a5e836d2cab186763d7e5f8f2cb7d44 * address reviewer's comments Change-Id: I9a5d1ede6d086906f3777c3d29237986a505db52 * Fix compile error Change-Id: I72267a8dda32dd8f43c1ea1522d07b392052358f * Use ov_any_t to replace ov_property_value_t Change-Id: Ia4062d0da0941c901990bf5f16497ae3c8f2eb0f * update doc for ov_model Change-Id: I80183394f16dd1e07ff998993e26f8b903f2402e * Property key apply string variables replace enum variable Change-Id: I0e1699862de3913ccdc06ded5b8f8ac5a2bf8773 * Fix compiling error in windows Change-Id: I4f9c7c746e218db94491c5f4bc5aeda1b3fde62b * Change init/deinit method to create/free, remove unnecessary methods Change-Id: Ibc5de039da94e92db494583ab1ff1a63e0586c73 * Pass by value for single C structure data Change-Id: I289eb56e2ba1ab90942c8c801c585ab0f792952f * fix dllexport issue in windows Change-Id: I1632375e5e651fdfa076cdab2d8d1c3e83986549 * Fix static build error Change-Id: I6633fe4887edad0b3a8b7e10730fb9d36a6ac0cd * Use pass by value for all transparent structure Change-Id: I652f6e70b420ef7c5af5cff3f5d482911cf0d75a * Unify parameter order in C APIs, input first and then output parameters Change-Id: Ib89c77d81c314e3a81bfcec9917630abbc896f5e * Rename preprocess api to be more readable Change-Id: I0a8ecd005e73e4ba8e90a8f25bedf0739fe31836 * Simplfy property implement for set and get property Change-Id: Icad41606368cef9520b1623f6207784c295f1b9f * check string type property issue Change-Id: Ie8ee6995dda401f1db0cc098e061ffcfd24de92a * Fix memory leak Change-Id: Ife8980736be320314eca6fb3f3605e019663e1da * Check string property data Change-Id: I542a136ff874cb345c67f7d3c1dbc74981a909df * Fix issues caused by rebase Change-Id: I3d675a16cf76980a6414e369a83464a46dec1e49 * Remove some redundant code Change-Id: Iab6bf7f355ec7a7424d884e620319ed9db80ecf5 * Remove property type from interface ov_core_set_property will have 2 cases: 1) enum type: <const char* property_key, ov_property_xxx_e property_value> 2) other: <const char* property_key, const char* property_value> Change-Id: Id7dec1ac40948d45c4f8baee687652aee92ea75d * Remove redundant code Change-Id: I66865d3313e305b0109cb63bd049772a01c0688f * Remove exception log and update propery size argument Change-Id: Ia1a60c07c9adf08d175d94a7d5e4298adb27bf80 * Apply string for enum property Change-Id: I591b1db453a52b5ea9000e0cc3e11edf0ef5f790 * Add test case for MULTI_DEVICE_PRIORITIES Change-Id: I59e4307564a2560724b4dacdb83c3ed45ea1ce8d * Fix test issues and add more negative test case Change-Id: Ib849fb8c098e487a537c1b1ab881f5e905871f73
269 lines
9.6 KiB
C
269 lines
9.6 KiB
C
// Copyright (C) 2018-2022 Intel Corporation
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
#include <opencv_c_wrapper.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "openvino/c/openvino.h"
|
|
|
|
/**
|
|
* @brief Struct to store infer results
|
|
*/
|
|
struct infer_result {
|
|
size_t class_id;
|
|
float probability;
|
|
};
|
|
|
|
/**
|
|
* @brief Sort result by probability
|
|
* @param struct with infer results to sort
|
|
* @param result_size of the struct
|
|
* @return none
|
|
*/
|
|
int compare(const void* a, const void* b) {
|
|
const struct infer_result* sa = (const struct infer_result*)a;
|
|
const struct infer_result* sb = (const struct infer_result*)b;
|
|
if (sa->probability < sb->probability) {
|
|
return 1;
|
|
} else if ((sa->probability == sb->probability) && (sa->class_id > sb->class_id)) {
|
|
return 1;
|
|
} else if (sa->probability > sb->probability) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
void infer_result_sort(struct infer_result* results, size_t result_size) {
|
|
qsort(results, result_size, sizeof(struct infer_result), compare);
|
|
}
|
|
|
|
/**
|
|
* @brief Convert output tensor to infer result struct for processing results
|
|
* @param tensor of output tensor
|
|
* @param result_size of the infer result
|
|
* @return struct infer_result
|
|
*/
|
|
struct infer_result* tensor_to_infer_result(ov_tensor_t* tensor, size_t* result_size) {
|
|
ov_shape_t output_shape = {0};
|
|
ov_status_e status = ov_tensor_get_shape(tensor, &output_shape);
|
|
if (status != OK)
|
|
return NULL;
|
|
|
|
*result_size = output_shape.dims[1];
|
|
|
|
struct infer_result* results = (struct infer_result*)malloc(sizeof(struct infer_result) * (*result_size));
|
|
if (!results)
|
|
return NULL;
|
|
|
|
void* data = NULL;
|
|
status = ov_tensor_data(tensor, &data);
|
|
if (status != OK) {
|
|
free(results);
|
|
return NULL;
|
|
}
|
|
float* float_data = (float*)(data);
|
|
|
|
size_t i;
|
|
for (i = 0; i < *result_size; ++i) {
|
|
results[i].class_id = i;
|
|
results[i].probability = float_data[i];
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
/**
|
|
* @brief Print results of infer
|
|
* @param results of the infer results
|
|
* @param result_size of the struct of classification results
|
|
* @param img_path image path
|
|
* @return none
|
|
*/
|
|
void print_infer_result(struct infer_result* results, size_t result_size, const char* img_path) {
|
|
printf("\nImage %s\n", img_path);
|
|
printf("\nclassid probability\n");
|
|
printf("------- -----------\n");
|
|
size_t i;
|
|
for (i = 0; i < result_size; ++i) {
|
|
printf("%zu %f\n", results[i].class_id, results[i].probability);
|
|
}
|
|
}
|
|
|
|
void print_model_input_output_info(ov_model_t* model) {
|
|
char* friendly_name = NULL;
|
|
ov_model_get_friendly_name(model, &friendly_name);
|
|
printf("[INFO] model name: %s \n", friendly_name);
|
|
ov_free(friendly_name);
|
|
}
|
|
|
|
#define CHECK_STATUS(return_status) \
|
|
if (return_status != OK) { \
|
|
fprintf(stderr, "[ERROR] return status %d, line %d\n", return_status, __LINE__); \
|
|
goto err; \
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
// -------- Check input parameters --------
|
|
if (argc != 4) {
|
|
printf("Usage : ./hello_classification_c <path_to_model> <path_to_image> "
|
|
"<device_name>\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
ov_core_t* core = NULL;
|
|
ov_model_t* model = NULL;
|
|
ov_tensor_t* tensor = NULL;
|
|
ov_preprocess_prepostprocessor_t* preprocess = NULL;
|
|
ov_preprocess_input_info_t* input_info = NULL;
|
|
ov_model_t* new_model = NULL;
|
|
ov_preprocess_input_tensor_info_t* input_tensor_info = NULL;
|
|
ov_preprocess_preprocess_steps_t* input_process = NULL;
|
|
ov_preprocess_input_model_info_t* p_input_model = NULL;
|
|
ov_preprocess_output_info_t* output_info = NULL;
|
|
ov_preprocess_output_tensor_info_t* output_tensor_info = NULL;
|
|
ov_compiled_model_t* compiled_model = NULL;
|
|
ov_infer_request_t* infer_request = NULL;
|
|
ov_tensor_t* output_tensor = NULL;
|
|
struct infer_result* results = NULL;
|
|
ov_layout_t* input_layout = NULL;
|
|
ov_layout_t* model_layout = NULL;
|
|
ov_shape_t input_shape;
|
|
ov_output_const_port_t* output_port = NULL;
|
|
ov_output_const_port_t* input_port = NULL;
|
|
|
|
// -------- Get OpenVINO runtime version --------
|
|
ov_version_t version;
|
|
CHECK_STATUS(ov_get_openvino_version(&version));
|
|
printf("---- OpenVINO INFO----\n");
|
|
printf("Description : %s \n", version.description);
|
|
printf("Build number: %s \n", version.buildNumber);
|
|
ov_version_free(&version);
|
|
|
|
// -------- Parsing and validation of input arguments --------
|
|
const char* input_model = argv[1];
|
|
const char* input_image_path = argv[2];
|
|
const char* device_name = argv[3];
|
|
|
|
// -------- Step 1. Initialize OpenVINO Runtime Core --------
|
|
CHECK_STATUS(ov_core_create(&core));
|
|
|
|
// -------- Step 2. Read a model --------
|
|
printf("[INFO] Loading model files: %s\n", input_model);
|
|
CHECK_STATUS(ov_core_read_model(core, input_model, NULL, &model));
|
|
print_model_input_output_info(model);
|
|
|
|
CHECK_STATUS(ov_model_const_output(model, &output_port));
|
|
if (!output_port) {
|
|
fprintf(stderr, "[ERROR] Sample supports models with 1 output only %d\n", __LINE__);
|
|
goto err;
|
|
}
|
|
|
|
CHECK_STATUS(ov_model_const_input(model, &input_port));
|
|
if (!input_port) {
|
|
fprintf(stderr, "[ERROR] Sample supports models with 1 input only %d\n", __LINE__);
|
|
goto err;
|
|
}
|
|
|
|
// -------- Step 3. Set up input
|
|
c_mat_t img;
|
|
image_read(input_image_path, &img);
|
|
ov_element_type_e input_type = U8;
|
|
int64_t dims[4] = {1, (size_t)img.mat_height, (size_t)img.mat_width, 3};
|
|
ov_shape_create(4, dims, &input_shape);
|
|
CHECK_STATUS(ov_tensor_create_from_host_ptr(input_type, input_shape, img.mat_data, &tensor));
|
|
|
|
// -------- Step 4. Configure preprocessing --------
|
|
CHECK_STATUS(ov_preprocess_prepostprocessor_create(model, &preprocess));
|
|
CHECK_STATUS(ov_preprocess_prepostprocessor_get_input_info_by_index(preprocess, 0, &input_info));
|
|
|
|
CHECK_STATUS(ov_preprocess_input_info_get_tensor_info(input_info, &input_tensor_info));
|
|
CHECK_STATUS(ov_preprocess_input_tensor_info_set_from(input_tensor_info, tensor));
|
|
|
|
const char* input_layout_desc = "NHWC";
|
|
CHECK_STATUS(ov_layout_create(input_layout_desc, &input_layout));
|
|
CHECK_STATUS(ov_preprocess_input_tensor_info_set_layout(input_tensor_info, input_layout));
|
|
|
|
CHECK_STATUS(ov_preprocess_input_info_get_preprocess_steps(input_info, &input_process));
|
|
CHECK_STATUS(ov_preprocess_preprocess_steps_resize(input_process, RESIZE_LINEAR));
|
|
CHECK_STATUS(ov_preprocess_input_info_get_model_info(input_info, &p_input_model));
|
|
|
|
const char* model_layout_desc = "NCHW";
|
|
CHECK_STATUS(ov_layout_create(model_layout_desc, &model_layout));
|
|
CHECK_STATUS(ov_preprocess_input_model_info_set_layout(p_input_model, model_layout));
|
|
|
|
CHECK_STATUS(ov_preprocess_prepostprocessor_get_output_info_by_index(preprocess, 0, &output_info));
|
|
CHECK_STATUS(ov_preprocess_output_info_get_tensor_info(output_info, &output_tensor_info));
|
|
CHECK_STATUS(ov_preprocess_output_set_element_type(output_tensor_info, F32));
|
|
|
|
CHECK_STATUS(ov_preprocess_prepostprocessor_build(preprocess, &new_model));
|
|
|
|
// -------- Step 5. Loading a model to the device --------
|
|
CHECK_STATUS(ov_core_compile_model(core, new_model, device_name, 0, &compiled_model));
|
|
|
|
// -------- Step 6. Create an infer request --------
|
|
CHECK_STATUS(ov_compiled_model_create_infer_request(compiled_model, &infer_request));
|
|
|
|
// -------- Step 7. Prepare input --------
|
|
CHECK_STATUS(ov_infer_request_set_input_tensor_by_index(infer_request, 0, tensor));
|
|
|
|
// -------- Step 8. Do inference synchronously --------
|
|
CHECK_STATUS(ov_infer_request_infer(infer_request));
|
|
|
|
// -------- Step 9. Process output
|
|
CHECK_STATUS(ov_infer_request_get_output_tensor_by_index(infer_request, 0, &output_tensor));
|
|
// Print classification results
|
|
size_t results_num;
|
|
results = tensor_to_infer_result(output_tensor, &results_num);
|
|
infer_result_sort(results, results_num);
|
|
size_t top = 10;
|
|
if (top > results_num) {
|
|
top = results_num;
|
|
}
|
|
printf("\nTop %zu results:\n", top);
|
|
print_infer_result(results, top, input_image_path);
|
|
|
|
// -------- free allocated resources --------
|
|
err:
|
|
free(results);
|
|
image_free(&img);
|
|
ov_shape_free(&input_shape);
|
|
ov_output_const_port_free(output_port);
|
|
ov_output_const_port_free(input_port);
|
|
if (output_tensor)
|
|
ov_tensor_free(output_tensor);
|
|
if (infer_request)
|
|
ov_infer_request_free(infer_request);
|
|
if (compiled_model)
|
|
ov_compiled_model_free(compiled_model);
|
|
if (input_layout)
|
|
ov_layout_free(input_layout);
|
|
if (model_layout)
|
|
ov_layout_free(model_layout);
|
|
if (output_tensor_info)
|
|
ov_preprocess_output_tensor_info_free(output_tensor_info);
|
|
if (output_info)
|
|
ov_preprocess_output_info_free(output_info);
|
|
if (p_input_model)
|
|
ov_preprocess_input_model_info_free(p_input_model);
|
|
if (input_process)
|
|
ov_preprocess_preprocess_steps_free(input_process);
|
|
if (input_tensor_info)
|
|
ov_preprocess_input_tensor_info_free(input_tensor_info);
|
|
if (input_info)
|
|
ov_preprocess_input_info_free(input_info);
|
|
if (preprocess)
|
|
ov_preprocess_prepostprocessor_free(preprocess);
|
|
if (new_model)
|
|
ov_model_free(new_model);
|
|
if (tensor)
|
|
ov_tensor_free(tensor);
|
|
if (model)
|
|
ov_model_free(model);
|
|
if (core)
|
|
ov_core_free(core);
|
|
return EXIT_SUCCESS;
|
|
}
|