[Samples] Move C samples to the new samples directory (#8021)

* [Samples] Move C samples to the new samples directory

* fix samples

* [Samples] Move C samples to the new samples directory

* fix samples

* code reivew inspired fixes

* rename folder to lower case

* move ENABLE_SAMPLES cond level up, fix readmes

* fix ref in doc

* fix install path

* fix install of samples to tests

Co-authored-by: Vladimir Dudnik <vladimir.dudnik@intel.com>
This commit is contained in:
Anastasia KuporosovaandVladimir Dudnik authored and GitHub committed 2021-11-01 12:59:09 +03:00
1 parent 58d845f351
commit 3251e0cbc3
32 files changed
+107 -94

No files matched your search

+41
View File
@@ -2,6 +2,47 @@
# SPDX-License-Identifier: Apache-2.0
#
add_subdirectory(c)
# TODO: remove this
foreach(sample hello_classification_c
object_detection_sample_ssd_c hello_nv12_input_classification_c)
if(TARGET ${sample})
install(TARGETS ${sample}
RUNTIME DESTINATION tests COMPONENT tests EXCLUDE_FROM_ALL)
endif()
endforeach()
if(TARGET opencv_c_wrapper)
install(TARGETS opencv_c_wrapper
RUNTIME DESTINATION ${IE_CPACK_RUNTIME_PATH} COMPONENT tests EXCLUDE_FROM_ALL
LIBRARY DESTINATION ${IE_CPACK_LIBRARY_PATH} COMPONENT tests EXCLUDE_FROM_ALL)
endif()
# install C samples
ie_cpack_add_component(c_samples DEPENDS core_c)
if(UNIX)
install(PROGRAMS ${IE_MAIN_SOURCE_DIR}/samples/build_samples.sh
DESTINATION samples/c
COMPONENT c_samples)
elseif(WIN32)
install(PROGRAMS ${IE_MAIN_SOURCE_DIR}/samples/build_samples_msvc.bat
DESTINATION samples/c
COMPONENT c_samples)
endif()
install(DIRECTORY c
DESTINATION samples
COMPONENT c_samples
PATTERN c/CMakeLists.txt EXCLUDE
PATTERN c/.clang-format EXCLUDE)
install(FILES ${IE_MAIN_SOURCE_DIR}/samples/CMakeLists.txt
DESTINATION samples/c
COMPONENT c_samples)
# install Python samples
ie_cpack_add_component(python_samples)
+28
View File
@@ -0,0 +1,28 @@
BasedOnStyle: Google
IndentWidth: 4
UseTab: Never
ColumnLimit: 120
Language: Cpp
Standard: Cpp11
AccessModifierOffset: -4
AlignConsecutiveMacros: true
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: Empty
AllowShortLoopsOnASingleLine: false
AlwaysBreakBeforeMultilineStrings: false
BinPackArguments: false
BinPackParameters: false
CommentPragmas: '^#'
DerivePointerAlignment: false
FixNamespaceComments: true
IndentCaseLabels: false
IndentPPDirectives: AfterHash
ForEachMacros:
- foreach
- FOREACH_CHILD
+5
View File
@@ -0,0 +1,5 @@
# Copyright (C) 2018-2021 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
#
include("${InferenceEngine_SOURCE_DIR}/samples/CMakeLists.txt")
@@ -0,0 +1,30 @@
# Copyright (C) 2018-2021 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
#
project(OpenCV_C_Wrapper)
set(TARGET_NAME opencv_c_wrapper)
file(GLOB SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
file(GLOB HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
# create library
add_library(${TARGET_NAME} SHARED ${HEADERS} ${SOURCES})
# Find OpenCV components if exist
find_package(OpenCV COMPONENTS core imgproc imgcodecs QUIET)
if(NOT OpenCV_FOUND)
message(WARNING "OPENCV is disabled or not found, ${TARGET_NAME} is built without OPENCV support")
else()
add_definitions(-DUSE_OPENCV)
endif()
target_link_libraries(${TARGET_NAME} PUBLIC ${OpenCV_LIBRARIES})
target_include_directories(${TARGET_NAME} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER c_samples)
if(COMMAND add_clang_format_target AND NOT IE_SAMPLE_EXCLUDE_CLANG_FORMAT)
add_clang_format_target(${TARGET_NAME}_clang FOR_TARGETS ${TARGET_NAME})
endif()
@@ -0,0 +1,179 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "opencv_c_wrapper.h"
#ifndef USE_OPENCV
int image_read(const char* img_path, c_mat_t* img) {
return -1;
}
int image_resize(const c_mat_t* src_img, c_mat_t* dst_img, const int width, const int height) {
return -1;
}
int image_save(const char* img_path, c_mat_t* img) {
return -1;
}
int image_free(c_mat_t* img) {
return -1;
}
int image_add_rectangles(c_mat_t* img, rectangle_t rects[], int classes[], int num, int thickness) {
return -1;
}
#else
# include <algorithm>
# include <opencv2/opencv.hpp>
int image_read(const char* img_path, c_mat_t* img) {
if (img_path == nullptr || img == nullptr) {
return -1;
}
cv::Mat mat = cv::imread(img_path);
if (mat.data == NULL) {
return -1;
}
img->mat_channels = mat.channels();
img->mat_width = mat.size().width;
img->mat_height = mat.size().height;
img->mat_type = mat.type();
img->mat_data_size = mat.elemSize() * img->mat_width * img->mat_height;
img->mat_data = (unsigned char*)malloc(sizeof(unsigned char) * img->mat_data_size);
if (img->mat_data == NULL) {
return -1;
}
for (int i = 0; i < img->mat_data_size; ++i) {
img->mat_data[i] = mat.data[i];
}
return 0;
}
int image_resize(const c_mat_t* src_img, c_mat_t* dst_img, const int width, const int height) {
if (src_img == nullptr || dst_img == nullptr) {
return -1;
}
cv::Mat mat_src(cv::Size(src_img->mat_width, src_img->mat_height), src_img->mat_type, src_img->mat_data);
cv::Mat mat_dst;
cv::resize(mat_src, mat_dst, cv::Size(width, height));
if (mat_dst.data) {
dst_img->mat_channels = mat_dst.channels();
dst_img->mat_width = mat_dst.size().width;
dst_img->mat_height = mat_dst.size().height;
dst_img->mat_type = mat_dst.type();
dst_img->mat_data_size = mat_dst.elemSize() * dst_img->mat_width * dst_img->mat_height;
dst_img->mat_data = (unsigned char*)malloc(sizeof(unsigned char) * dst_img->mat_data_size);
if (dst_img->mat_data == NULL) {
return -1;
}
for (int i = 0; i < dst_img->mat_data_size; ++i) {
dst_img->mat_data[i] = mat_dst.data[i];
}
} else {
return -1;
}
return 1;
}
int image_save(const char* img_path, c_mat_t* img) {
cv::Mat mat(cv::Size(img->mat_width, img->mat_height), img->mat_type, img->mat_data);
return cv::imwrite(img_path, mat);
}
int image_free(c_mat_t* img) {
if (img) {
free(img->mat_data);
img->mat_data = NULL;
}
return -1;
}
int image_add_rectangles(c_mat_t* img, rectangle_t rects[], int classes[], int num, int thickness) {
int colors_num = 21;
color_t colors[21] = {// colors to be used for bounding boxes
{128, 64, 128}, {232, 35, 244}, {70, 70, 70}, {156, 102, 102}, {153, 153, 190},
{153, 153, 153}, {30, 170, 250}, {0, 220, 220}, {35, 142, 107}, {152, 251, 152},
{180, 130, 70}, {60, 20, 220}, {0, 0, 255}, {142, 0, 0}, {70, 0, 0},
{100, 60, 0}, {90, 0, 0}, {230, 0, 0}, {32, 11, 119}, {0, 74, 111},
{81, 0, 81}};
for (int i = 0; i < num; i++) {
int x = rects[i].x_min;
int y = rects[i].y_min;
int w = rects[i].rect_width;
int h = rects[i].rect_height;
int cls = classes[i] % colors_num; // color of a bounding box line
if (x < 0)
x = 0;
if (y < 0)
y = 0;
if (w < 0)
w = 0;
if (h < 0)
h = 0;
if (x >= img->mat_width) {
x = img->mat_width - 1;
w = 0;
thickness = 1;
}
if (y >= img->mat_height) {
y = img->mat_height - 1;
h = 0;
thickness = 1;
}
if ((x + w) >= img->mat_width) {
w = img->mat_width - x - 1;
}
if ((y + h) >= img->mat_height) {
h = img->mat_height - y - 1;
}
thickness = std::min(std::min(thickness, w / 2 + 1), h / 2 + 1);
size_t shift_first;
size_t shift_second;
for (int t = 0; t < thickness; t++) {
shift_first = (y + t) * img->mat_width * 3;
shift_second = (y + h - t) * img->mat_width * 3;
for (int ii = x; ii < x + w + 1; ii++) {
img->mat_data[shift_first + ii * 3] = colors[cls].r;
img->mat_data[shift_first + ii * 3 + 1] = colors[cls].g;
img->mat_data[shift_first + ii * 3 + 2] = colors[cls].b;
img->mat_data[shift_second + ii * 3] = colors[cls].r;
img->mat_data[shift_second + ii * 3 + 1] = colors[cls].g;
img->mat_data[shift_second + ii * 3 + 2] = colors[cls].b;
}
}
for (int t = 0; t < thickness; t++) {
shift_first = (x + t) * 3;
shift_second = (x + w - t) * 3;
for (int ii = y; ii < y + h + 1; ii++) {
img->mat_data[shift_first + ii * img->mat_width * 3] = colors[cls].r;
img->mat_data[shift_first + ii * img->mat_width * 3 + 1] = colors[cls].g;
img->mat_data[shift_first + ii * img->mat_width * 3 + 2] = colors[cls].b;
img->mat_data[shift_second + ii * img->mat_width * 3] = colors[cls].r;
img->mat_data[shift_second + ii * img->mat_width * 3 + 1] = colors[cls].g;
img->mat_data[shift_second + ii * img->mat_width * 3 + 2] = colors[cls].b;
}
}
}
return 0;
}
#endif // USE_OPENCV
@@ -0,0 +1,107 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <stdint.h>
#include <stdio.h>
#ifdef __cplusplus
# define OPENCV_C_EXTERN extern "C"
#else
# define OPENCV_C_EXTERN
#endif
#if defined(__GNUC__) && (__GNUC__ < 4)
# define OPENCV_C_WRAPPER(...) OPENCV_C_EXTERN __VA_ARGS__
#else
# if defined(_WIN32)
# ifdef opencv_c_wrapper_EXPORTS
# define OPENCV_C_WRAPPER(...) OPENCV_C_EXTERN __declspec(dllexport) __VA_ARGS__ __cdecl
# else
# define OPENCV_C_WRAPPER(...) OPENCV_C_EXTERN __declspec(dllimport) __VA_ARGS__ __cdecl
# endif
# else
# define OPENCV_C_WRAPPER(...) OPENCV_C_EXTERN __attribute__((visibility("default"))) __VA_ARGS__
# endif
#endif
/**
* @struct c_mat
* @brief OpenCV Mat Wrapper
*/
typedef struct c_mat {
unsigned char* mat_data;
int mat_data_size;
int mat_width;
int mat_height;
int mat_channels;
int mat_type;
} c_mat_t;
/**
* @struct rectangle
* @brief This structure describes rectangle data.
*/
typedef struct rectangle {
int x_min;
int y_min;
int rect_width;
int rect_height;
} rectangle_t;
/**
* @struct color
* @brief Stores channels of a given color
*/
typedef struct color {
unsigned char r;
unsigned char g;
unsigned char b;
} color_t;
/**
* @brief Load an image from a file. If the image cannot be read, the function return -1.
* @param img_path Path of file to be loaded.
* @param img A pointer to the newly created c_mat_t.
* @return Status of the operation: 0 for success, -1 for fail.
*/
OPENCV_C_WRAPPER(int) image_read(const char* img_path, c_mat_t* img);
/**
* @brief Resizes an image.
* @param src_img A pointer to the input image.
* @param dst_img A pointer to the output image.
* @param width The width of dst_img.
* @param height The height of dst_img.
* @return Status of the operation: 0 for success, -1 for fail.
*/
OPENCV_C_WRAPPER(int)
image_resize(const c_mat_t* src_img, c_mat_t* dst_img, const int width, const int height);
/**
* @brief Saves an image to a specified file.The image format is chosen based on the filename
* extension.
* @param img_path Path of the file to be saved.
* @param img Image to be saved.
* @return Status of the operation: 0 for success, -1 for fail.
*/
OPENCV_C_WRAPPER(int) image_save(const char* img_path, c_mat_t* img);
/**
* @brief Releases memory occupied by a c_mat_t instance.
* @param img A pointer to the c_mat_t instance to free memory.
* @return Status of the operation: 0 for success, -1 for fail.
*/
OPENCV_C_WRAPPER(int) image_free(c_mat_t* img);
/**
* @brief Adds colored rectangles to the image
* @param img - image where rectangles are put
* @param rects - array for the rectangle
* @param classes - array for classes
* @param num - number of the rects and classes
* @param thickness - thickness of a line (in pixels) to be used for bounding boxes
* @return Status of the operation: 0 for success, -1 for fail.
*/
OPENCV_C_WRAPPER(int)
image_add_rectangles(c_mat_t* img, rectangle_t rects[], int classes[], int num, int thickness);
@@ -0,0 +1,7 @@
# Copyright (C) 2018-2021 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
#
ie_add_sample(NAME hello_classification_c
SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.c"
DEPENDENCIES opencv_c_wrapper)
+117
View File
@@ -0,0 +1,117 @@
# Hello Classification C Sample {#openvino_inference_engine_ie_bridges_c_samples_hello_classification_README}
This sample demonstrates how to execute an inference of image classification networks like AlexNet and GoogLeNet using Synchronous Inference Request API and input auto-resize feature.
Hello Classification C sample application demonstrates how to use the following Inference Engine C API in applications:
| Feature | API | Description |
|:--- |:--- |:---
| Basic Infer Flow | [ie_core_create], [ie_core_read_network], [ie_core_load_network], [ie_exec_network_create_infer_request], [ie_infer_request_set_blob], [ie_infer_request_get_blob] | Common API to do inference: configure input and output blobs, loading model, create infer request
| Synchronous Infer | [ie_infer_request_infer] | Do synchronous inference
| Network Operations | [ie_network_get_input_name], [ie_network_get_inputs_number], [ie_network_get_outputs_number], [ie_network_set_input_precision], [ie_network_get_output_name], [ie_network_get_output_precision] | Managing of network
| Blob Operations| [ie_blob_make_memory_from_preallocated], [ie_blob_get_dims], [ie_blob_get_cbuffer] | Work with memory container for storing inputs, outputs of the network, weights and biases of the layers
| Input auto-resize | [ie_network_set_input_resize_algorithm], [ie_network_set_input_layout] | Set image of the original size as input for a network with other input size. Resize and layout conversions will be performed automatically by the corresponding plugin just before inference
| Options | Values |
|:--- |:---
| Validated Models | [alexnet](@ref omz_models_model_alexnet), [googlenet-v1](@ref omz_models_model_googlenet_v1)
| Model Format | Inference Engine Intermediate Representation (\*.xml + \*.bin), ONNX (\*.onnx)
| Validated images | The sample uses OpenCV\* to [read input image](https://docs.opencv.org/master/d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56) (\*.bmp, \*.png)
| Supported devices | [All](../../../docs/IE_DG/supported_plugins/Supported_Devices.md) |
| Other language realization | [C++](../../../inference-engine/samples/hello_classification/README.md), [Python](../../python/hello_classification/README.md) |
## How It Works
Upon the start-up, the sample application reads command line parameters, loads specified network and an image to the Inference Engine plugin.
Then, the sample creates an synchronous inference request object. When inference is done, the application outputs data to the standard output stream.
You can see the explicit description of
each sample step at [Integration Steps](../../../docs/IE_DG/Integrate_with_customer_application_new_API.md) section of "Integrate the Inference Engine with Your Application" guide.
## Building
To build the sample, please use instructions available at [Build the Sample Applications](../../../docs/IE_DG/Samples_Overview.md) section in Inference Engine Samples guide.
## Running
To run the sample, you need specify a model and image:
- you can use [public](@ref omz_models_group_public) or [Intel's](@ref omz_models_group_intel) pre-trained models from the Open Model Zoo. The models can be downloaded using the [Model Downloader](@ref omz_tools_downloader).
- you can use images from the media files collection available at https://storage.openvinotoolkit.org/data/test_data.
> **NOTES**:
>
> - By default, Inference Engine samples and demos expect input with BGR channels order. If you trained your model to work with RGB order, you need to manually rearrange the default channels order in the sample or demo application or reconvert your model using the Model Optimizer tool with `--reverse_input_channels` argument specified. For more information about the argument, refer to **When to Reverse Input Channels** section of [Converting a Model Using General Conversion Parameters](../../../docs/MO_DG/prepare_model/convert_model/Converting_Model_General.md).
>
> - Before running the sample with a trained model, make sure the model is converted to the Inference Engine format (\*.xml + \*.bin) using the [Model Optimizer tool](../../../docs/MO_DG/Deep_Learning_Model_Optimizer_DevGuide.md).
>
> - The sample accepts models in ONNX format (\*.onnx) that do not require preprocessing.
### Example
1. Download a pre-trained model using [Model Downloader](@ref omz_tools_downloader):
```
python <path_to_omz_tools>/downloader.py --name alexnet
```
2. If a model is not in the Inference Engine IR or ONNX format, it must be converted. You can do this using the model converter script:
```
python <path_to_omz_tools>/converter.py --name alexnet
```
3. Perform inference of `car.bmp` using `alexnet` model on a `GPU`, for example:
```
<path_to_sample>/hello_classification_c <path_to_model>/alexnet.xml <path_to_image>/car.bmp GPU
```
## Sample Output
The application outputs top-10 inference results.
```
Top 10 results:
Image /opt/intel/openvino/samples/scripts/car.png
classid probability
------- -----------
656 0.666479
654 0.112940
581 0.068487
874 0.033385
436 0.026132
817 0.016731
675 0.010980
511 0.010592
569 0.008178
717 0.006336
This sample is an API example, for any performance measurements please use the dedicated benchmark_app tool
```
## See Also
- [Integrate the Inference Engine with Your Application](../../../docs/IE_DG/Integrate_with_customer_application_new_API.md)
- [Using Inference Engine Samples](../../../docs/IE_DG/Samples_Overview.md)
- [Model Downloader](@ref omz_tools_downloader)
- [Model Optimizer](../../../docs/MO_DG/Deep_Learning_Model_Optimizer_DevGuide.md)
[ie_core_create]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Core.html#gaab73c7ee3704c742eaac457636259541
[ie_core_read_network]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Core.html#gaa40803295255b3926a3d1b8924f26c29
[ie_network_get_input_name]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Network.html#ga36b0c28dfab6db2bfcc2941fd57fbf6d
[ie_network_set_input_precision]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Network.html#gadd99b7cc98b3c33daa2095b8a29f66d7
[ie_network_get_output_name]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Network.html#ga1feabc49576db24d9821a150b2b50a6c
[ie_network_get_output_precision]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Network.html#gaeaa7f1fb8f56956fc492cd9207235984
[ie_core_load_network]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Core.html#ga318d4b0214b8a3fd33f9e44170befcc5
[ie_exec_network_create_infer_request]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__ExecutableNetwork.html#gae72247391c1429a18c367594a4b7db9f
[ie_blob_make_memory_from_preallocated]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Blob.html#ga7a874d46375e10fa1a7e8e3d7e1c9c9c
[ie_infer_request_set_blob]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__InferRequest.html#ga891c2d475501bba761148a0c3faca196
[ie_infer_request_infer]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__InferRequest.html#gac6c6fcb67ccb4d0ec9ad1c63a5bee7b6
[ie_infer_request_get_blob]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__InferRequest.html#ga6cd04044ea95987260037bfe17ce1a2d
[ie_blob_get_dims]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Blob.html#ga25d93efd7ec1052a8896ac61cc14c30a
[ie_blob_get_cbuffer]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Blob.html#gaf6b4a110b4c5723dcbde135328b3620a
[ie_network_set_input_resize_algorithm]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Network.html#ga46ab3b3a06359f2b77f58bdd6e8a5492
[ie_network_set_input_layout]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Network.html#ga27ea9f92290e0b2cdedbe8a85feb4c01
[ie_network_get_inputs_number]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Network.html#ga6a3349bca66c4ba8b41a434061fccf52
[ie_network_get_outputs_number]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Network.html#ga869b8c309797f1e09f73ddffd1b57509
+275
View File
@@ -0,0 +1,275 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <c_api/ie_c_api.h>
#include <opencv_c_wrapper.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/**
* @brief Struct to store classification results
*/
struct classify_res {
size_t class_id;
float probability;
};
/**
* @brief Sort result of image classification by probability
* @param struct with classification results to sort
* @param size of the struct
* @return none
*/
void classify_res_sort(struct classify_res* res, size_t n) {
size_t i, j;
for (i = 0; i < n; ++i) {
for (j = i + 1; j < n; ++j) {
if (res[i].probability < res[j].probability) {
struct classify_res temp = res[i];
res[i] = res[j];
res[j] = temp;
} else if (res[i].probability == res[j].probability && res[i].class_id > res[j].class_id) {
struct classify_res temp = res[i];
res[i] = res[j];
res[j] = temp;
}
}
}
}
/**
* @brief Convert output blob to classify struct for processing results
* @param blob of output data
* @param size of the blob
* @return struct classify_res
*/
struct classify_res* output_blob_to_classify_res(ie_blob_t* blob, size_t* n) {
dimensions_t output_dim;
IEStatusCode status = ie_blob_get_dims(blob, &output_dim);
if (status != OK)
return NULL;
*n = output_dim.dims[1];
struct classify_res* cls = (struct classify_res*)malloc(sizeof(struct classify_res) * (*n));
if (!cls) {
return NULL;
}
ie_blob_buffer_t blob_cbuffer;
status = ie_blob_get_cbuffer(blob, &blob_cbuffer);
if (status != OK) {
free(cls);
return NULL;
}
float* blob_data = (float*)(blob_cbuffer.cbuffer);
size_t i;
for (i = 0; i < *n; ++i) {
cls[i].class_id = i;
cls[i].probability = blob_data[i];
}
return cls;
}
/**
* @brief Print results of classification
* @param struct of the classification results
* @param size of the struct of classification results
* @param string image path
* @return none
*/
void print_classify_res(struct classify_res* cls, size_t n, const char* img_path) {
printf("\nImage %s\n", img_path);
printf("\nclassid probability\n");
printf("------- -----------\n");
size_t i;
for (i = 0; i < n; ++i) {
printf("%zu %f\n", cls[i].class_id, cls[i].probability);
}
printf("\nThis sample is an API example,"
" for any performance measurements please use the dedicated benchmark_"
"app tool\n");
}
int main(int argc, char** argv) {
// ------------------------------ Parsing and validation of input args
// ---------------------------------
if (argc != 4) {
printf("Usage : ./hello_classification <path_to_model> <path_to_image> "
"<device_name>\n");
return EXIT_FAILURE;
}
const char* input_model = argv[1];
const char* input_image_path = argv[2];
const char* device_name = argv[3];
ie_core_t* core = NULL;
ie_network_t* network = NULL;
ie_executable_network_t* exe_network = NULL;
ie_infer_request_t* infer_request = NULL;
char *input_name = NULL, *output_name = NULL;
ie_blob_t *imgBlob = NULL, *output_blob = NULL;
size_t network_input_size;
size_t network_output_size;
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 1. Initialize inference engine core
// -------------------------------------
IEStatusCode status = ie_core_create("", &core);
if (status != OK)
goto err;
// -----------------------------------------------------------------------------------------------------
// Step 2. Read a model in OpenVINO Intermediate Representation (.xml and .bin
// files) or ONNX (.onnx file) format
status = ie_core_read_network(core, input_model, NULL, &network);
if (status != OK)
goto err;
// check the network topology
status = ie_network_get_inputs_number(network, &network_input_size);
if (status != OK || network_input_size != 1) {
printf("Sample supports topologies with 1 input only\n");
goto err;
}
status = ie_network_get_outputs_number(network, &network_output_size);
if (status != OK || network_output_size != 1) {
printf("Sample supports topologies with 1 output only\n");
goto err;
}
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 3. Configure input & output
// ---------------------------------------------
// --------------------------- Prepare input blobs
// -----------------------------------------------------
status = ie_network_get_input_name(network, 0, &input_name);
if (status != OK)
goto err;
/* Mark input as resizable by setting of a resize algorithm.
* In this case we will be able to set an input blob of any shape to an infer
* request. Resize and layout conversions are executed automatically during
* inference */
status |= ie_network_set_input_resize_algorithm(network, input_name, RESIZE_BILINEAR);
status |= ie_network_set_input_layout(network, input_name, NHWC);
status |= ie_network_set_input_precision(network, input_name, U8);
if (status != OK)
goto err;
// --------------------------- Prepare output blobs
// ----------------------------------------------------
status |= ie_network_get_output_name(network, 0, &output_name);
status |= ie_network_set_output_precision(network, output_name, FP32);
if (status != OK)
goto err;
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 4. Loading model to the device
// ------------------------------------------
ie_config_t config = {NULL, NULL, NULL};
status = ie_core_load_network(core, network, device_name, &config, &exe_network);
if (status != OK)
goto err;
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 5. Create infer request
// -------------------------------------------------
status = ie_exec_network_create_infer_request(exe_network, &infer_request);
if (status != OK)
goto err;
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 6. Prepare input
// --------------------------------------------------------
/* Read input image to a blob and set it to an infer request without resize
* and layout conversions. */
c_mat_t img;
image_read(input_image_path, &img);
dimensions_t dimens = {4, {1, (size_t)img.mat_channels, (size_t)img.mat_height, (size_t)img.mat_width}};
tensor_desc_t tensorDesc = {NHWC, dimens, U8};
size_t size = img.mat_data_size;
// just wrap IplImage data to ie_blob_t pointer without allocating of new
// memory
status = ie_blob_make_memory_from_preallocated(&tensorDesc, img.mat_data, size, &imgBlob);
if (status != OK) {
image_free(&img);
goto err;
}
// infer_request accepts input blob of any size
status = ie_infer_request_set_blob(infer_request, input_name, imgBlob);
if (status != OK)
goto err;
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 7. Do inference
// --------------------------------------------------------
/* Running the request synchronously */
status = ie_infer_request_infer(infer_request);
if (status != OK)
goto err;
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 8. Process output
// ------------------------------------------------------
status = ie_infer_request_get_blob(infer_request, output_name, &output_blob);
if (status != OK) {
image_free(&img);
goto err;
}
size_t class_num;
struct classify_res* cls = output_blob_to_classify_res(output_blob, &class_num);
classify_res_sort(cls, class_num);
// Print classification results
size_t top = 10;
if (top > class_num) {
top = class_num;
}
printf("\nTop %zu results:\n", top);
print_classify_res(cls, top, input_image_path);
// -----------------------------------------------------------------------------------------------------
free(cls);
ie_blob_free(&output_blob);
ie_blob_free(&imgBlob);
image_free(&img);
ie_infer_request_free(&infer_request);
ie_exec_network_free(&exe_network);
ie_network_name_free(&input_name);
ie_network_name_free(&output_name);
ie_network_free(&network);
ie_core_free(&core);
return EXIT_SUCCESS;
err:
if (core)
ie_core_free(&core);
if (network)
ie_network_free(&network);
if (input_name)
ie_network_name_free(&input_name);
if (output_name)
ie_network_name_free(&output_name);
if (exe_network)
ie_exec_network_free(&exe_network);
if (infer_request)
ie_infer_request_free(&infer_request);
if (imgBlob)
ie_blob_free(&imgBlob);
if (output_blob)
ie_blob_free(&output_blob);
return EXIT_FAILURE;
}
@@ -0,0 +1,6 @@
# Copyright (C) 2018-2021 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
#
ie_add_sample(NAME hello_nv12_input_classification_c
SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.c")
@@ -0,0 +1,116 @@
# Hello NV12 Input Classification C Sample {#openvino_inference_engine_ie_bridges_c_samples_hello_nv12_input_classification_README}
This sample demonstrates how to execute an inference of image classification networks like AlexNet with images in NV12 color format using Synchronous Inference Request API.
Hello NV12 Input Classification C Sample demonstrates how to use the NV12 automatic input pre-processing API of the Inference Engine in your applications:
| Feature | API | Description |
|:--- |:--- |:---
| Blob Operations| [ie_blob_make_memory_nv12] | Create a NV12 blob
| Input in N12 color format |[ie_network_set_color_format]| Change the color format of the input data
Basic Inference Engine API is covered by [Hello Classification C sample](../hello_classification/README.md).
| Options | Values |
|:--- |:---
| Validated Models | [alexnet](@ref omz_models_model_alexnet)
| Model Format | Inference Engine Intermediate Representation (\*.xml + \*.bin), ONNX (\*.onnx)
| Validated images | An uncompressed image in the NV12 color format - \*.yuv
| Supported devices | [All](../../../docs/IE_DG/supported_plugins/Supported_Devices.md) |
| Other language realization | [C++](../../../inference-engine/samples/hello_nv12_input_classification/README.md) |
## How It Works
Upon the start-up, the sample application reads command-line parameters, loads specified network and an
image in the NV12 color format to an Inference Engine plugin. Then, the sample creates an synchronous inference request object. When inference is done, the
application outputs data to the standard output stream.
You can see the explicit description of
each sample step at [Integration Steps](https://docs.openvinotoolkit.org/latest/openvino_docs_IE_DG_Integrate_with_customer_application_new_API.html) section of "Integrate the Inference Engine with Your Application" guide.
## Building
To build the sample, please use instructions available at [Build the Sample Applications](../../../docs/IE_DG/Samples_Overview.md) section in Inference Engine Samples guide.
## Running
To run the sample, you need specify a model and image:
- you can use [public](@ref omz_models_group_public) or [Intel's](@ref omz_models_group_intel) pre-trained models from the Open Model Zoo. The models can be downloaded using the [Model Downloader](@ref omz_tools_downloader).
- you can use images from the media files collection available at https://storage.openvinotoolkit.org/data/test_data.
The sample accepts an uncompressed image in the NV12 color format. To run the sample, you need to
convert your BGR/RGB image to NV12. To do this, you can use one of the widely available tools such
as FFmpeg\* or GStreamer\*. The following command shows how to convert an ordinary image into an
uncompressed NV12 image using FFmpeg:
```sh
ffmpeg -i cat.jpg -pix_fmt nv12 cat.yuv
```
> **NOTES**:
>
> - Because the sample reads raw image files, you should provide a correct image size along with the
> image path. The sample expects the logical size of the image, not the buffer size. For example,
> for 640x480 BGR/RGB image the corresponding NV12 logical image size is also 640x480, whereas the
> buffer size is 640x720.
> - By default, this sample expects that network input has BGR channels order. If you trained your
> model to work with RGB order, you need to reconvert your model using the Model Optimizer tool
> with `--reverse_input_channels` argument specified. For more information about the argument,
> refer to **When to Reverse Input Channels** section of
> [Converting a Model Using General Conversion Parameters](../../../docs/MO_DG/prepare_model/convert_model/Converting_Model_General.md).
> - Before running the sample with a trained model, make sure the model is converted to the Inference Engine format (\*.xml + \*.bin) using the [Model Optimizer tool](../../../docs/MO_DG/Deep_Learning_Model_Optimizer_DevGuide.md).
>
> - The sample accepts models in ONNX format (.onnx) that do not require preprocessing.
### Example
1. Download a pre-trained model using [Model Downloader](@ref omz_tools_downloader):
```
python <path_to_omz_tools>/downloader.py --name alexnet
```
2. If a model is not in the Inference Engine IR or ONNX format, it must be converted. You can do this using the model converter script:
```
python <path_to_omz_tools>/converter.py --name alexnet
```
3. Perform inference of NV12 image using `alexnet` model on a `CPU`, for example:
```
<path_to_sample>/hello_nv12_input_classification_c <path_to_model>/alexnet.xml <path_to_image>/cat.yuv 300x300 CPU
```
## Sample Output
The application outputs top-10 inference results.
```
Top 10 results:
Image ./cat.yuv
classid probability
------- -----------
435 0.091733
876 0.081725
999 0.069305
587 0.043726
666 0.038957
419 0.032892
285 0.030309
700 0.029941
696 0.021628
855 0.020339
This sample is an API example, for any performance measurements please use the dedicated benchmark_app tool
```
## See Also
- [Integrate the Inference Engine with Your Application](../../../docs/IE_DG/Integrate_with_customer_application_new_API.md)
- [Using Inference Engine Samples](../../../docs/IE_DG/Samples_Overview.md)
- [Model Downloader](@ref omz_tools_downloader)
- [Model Optimizer](../../../docs/MO_DG/Deep_Learning_Model_Optimizer_DevGuide.md)
[ie_network_set_color_format]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Network.html#ga85f3251f1f7b08507c297e73baa58969
[ie_blob_make_memory_nv12]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Blob.html#ga0a2d97b0d40a53c01ead771f82ae7f4a
@@ -0,0 +1,356 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <c_api/ie_c_api.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/**
* @brief Struct to store classification results
*/
struct classify_res {
size_t class_id;
float probability;
};
/**
* @brief Sort result of image classification by probability
* @param struct with classification results to sort
* @param size of the struct
* @return none
*/
void classify_res_sort(struct classify_res* res, size_t n) {
size_t i, j;
for (i = 0; i < n; ++i) {
for (j = i + 1; j < n; ++j) {
if (res[i].probability < res[j].probability) {
struct classify_res temp = res[i];
res[i] = res[j];
res[j] = temp;
} else if (res[i].probability == res[j].probability && res[i].class_id > res[j].class_id) {
struct classify_res temp = res[i];
res[i] = res[j];
res[j] = temp;
}
}
}
}
/**
* @brief Convert output blob to classify struct for processing results
* @param blob of output data
* @param size of the blob
* @return struct classify_res
*/
struct classify_res* output_blob_to_classify_res(ie_blob_t* blob, size_t* n) {
dimensions_t output_dim;
IEStatusCode status = ie_blob_get_dims(blob, &output_dim);
if (status != OK)
return NULL;
*n = output_dim.dims[1];
struct classify_res* cls = (struct classify_res*)malloc(sizeof(struct classify_res) * (*n));
if (!cls) {
return NULL;
}
ie_blob_buffer_t blob_cbuffer;
status = ie_blob_get_cbuffer(blob, &blob_cbuffer);
if (status != OK) {
free(cls);
return NULL;
}
float* blob_data = (float*)(blob_cbuffer.cbuffer);
size_t i;
for (i = 0; i < *n; ++i) {
cls[i].class_id = i;
cls[i].probability = blob_data[i];
}
return cls;
}
/**
* @brief Print results of classification
* @param struct of the classification results
* @param size of the struct of classification results
* @param string image path
* @return none
*/
void print_classify_res(struct classify_res* cls, size_t n, const char* img_path) {
printf("\nImage %s\n", img_path);
printf("\nclassid probability\n");
printf("------- -----------\n");
size_t i;
for (i = 0; i < n; ++i) {
printf("%zu %f\n", cls[i].class_id, cls[i].probability);
}
printf("\nThis sample is an API example,"
" for any performance measurements please use the dedicated benchmark_"
"app tool\n");
}
/**
* @brief Read image data
* @param string image path
* @param pointer to store image data
* @param size bytes of image
* @return total number of elements successfully read, in case of error it
* doesn't equal to size param
*/
size_t read_image_from_file(const char* img_path, unsigned char* img_data, size_t size) {
FILE* fp = fopen(img_path, "rb+");
size_t read_size = 0;
if (fp) {
fseek(fp, 0, SEEK_END);
if (ftell(fp) >= size) {
fseek(fp, 0, SEEK_SET);
read_size = fread(img_data, 1, size, fp);
}
fclose(fp);
}
return read_size;
}
/**
* @brief Check image has supported width and height
* @param string image size in WIDTHxHEIGHT format
* @param pointer to image width
* @param pointer to image height
* @return bool status True(success) or False(fail)
*/
bool is_supported_image_size(const char* size_str, size_t* width, size_t* height) {
const char* _size = size_str;
size_t _width = 0, _height = 0;
while (_size && *_size != 'x' && *_size != '\0') {
if ((*_size <= '9') && (*_size >= '0')) {
_width = (_width * 10) + (*_size - '0');
_size++;
} else {
goto err;
}
}
if (_size)
_size++;
while (_size && *_size != '\0') {
if ((*_size <= '9') && (*_size >= '0')) {
_height = (_height * 10) + (*_size - '0');
_size++;
} else {
goto err;
}
}
if (_width > 0 && _height > 0) {
if (_width % 2 == 0 && _height % 2 == 0) {
*width = _width;
*height = _height;
return true;
} else {
printf("Unsupported image size, width and height must be even numbers \n");
return false;
}
} else {
goto err;
}
err:
printf("Incorrect format of image size parameter, expected WIDTHxHEIGHT, "
"actual: %s\n",
size_str);
return false;
}
int main(int argc, char** argv) {
// ------------------------------ Parsing and validation of input args
// ---------------------------------
if (argc != 5) {
printf("Usage : ./hello_classification <path_to_model> <path_to_image> "
"<image_size> <device_name>\n");
return EXIT_FAILURE;
}
size_t input_width = 0, input_height = 0, img_size = 0;
if (!is_supported_image_size(argv[3], &input_width, &input_height))
return EXIT_FAILURE;
const char* input_model = argv[1];
const char* input_image_path = argv[2];
const char* device_name = argv[4];
unsigned char* img_data = NULL;
ie_core_t* core = NULL;
ie_network_t* network = NULL;
ie_executable_network_t* exe_network = NULL;
ie_infer_request_t* infer_request = NULL;
char *input_name = NULL, *output_name = NULL;
ie_blob_t *y_blob = NULL, *uv_blob = NULL, *nv12_blob = NULL, *output_blob = NULL;
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 1. Initialize inference engine core
// -------------------------------------
IEStatusCode status = ie_core_create("", &core);
if (status != OK)
goto err;
// -----------------------------------------------------------------------------------------------------
// Step 2. Read a model in OpenVINO Intermediate Representation (.xml and .bin
// files) or ONNX (.onnx file) format
status = ie_core_read_network(core, input_model, NULL, &network);
if (status != OK)
goto err;
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 3. Configure input & output
// ---------------------------------------------
// --------------------------- Prepare input blobs
// -----------------------------------------------------
status = ie_network_get_input_name(network, 0, &input_name);
if (status != OK)
goto err;
/* Mark input as resizable by setting of a resize algorithm.
* In this case we will be able to set an input blob of any shape to an infer
* request. Resize and layout conversions are executed automatically during
* inference */
status |= ie_network_set_input_resize_algorithm(network, input_name, RESIZE_BILINEAR);
status |= ie_network_set_input_layout(network, input_name, NCHW);
status |= ie_network_set_input_precision(network, input_name, U8);
// set input color format to NV12 to enable automatic input color format
// pre-processing
status |= ie_network_set_color_format(network, input_name, NV12);
if (status != OK)
goto err;
// --------------------------- Prepare output blobs
// ----------------------------------------------------
status |= ie_network_get_output_name(network, 0, &output_name);
status |= ie_network_set_output_precision(network, output_name, FP32);
if (status != OK)
goto err;
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 4. Loading model to the device
// ------------------------------------------
ie_config_t config = {NULL, NULL, NULL};
status = ie_core_load_network(core, network, device_name, &config, &exe_network);
if (status != OK)
goto err;
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 5. Create infer request
// -------------------------------------------------
status = ie_exec_network_create_infer_request(exe_network, &infer_request);
if (status != OK)
goto err;
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 6. Prepare input
// -------------------------------------------------------- read image with
// size converted to NV12 data size: height(NV12) = 3 / 2 * logical height
img_size = input_width * (input_height * 3 / 2);
img_data = (unsigned char*)calloc(img_size, sizeof(unsigned char));
if (NULL == img_data)
goto err;
if (img_size != read_image_from_file(input_image_path, img_data, img_size))
goto err;
// --------------------------- Create a blob to hold the NV12 input data
// ------------------------------- Create tensor descriptors for Y and UV
// blobs
dimensions_t y_dimens = {4, {1, 1, input_height, input_width}};
dimensions_t uv_dimens = {4, {1, 2, input_height / 2, input_width / 2}};
tensor_desc_t y_tensor = {NHWC, y_dimens, U8};
tensor_desc_t uv_tensor = {NHWC, uv_dimens, U8};
size_t y_plane_size = input_height * input_width;
size_t uv_plane_size = input_width * (input_height / 2);
// Create blob for Y plane from raw data
status |= ie_blob_make_memory_from_preallocated(&y_tensor, img_data, y_plane_size, &y_blob);
// Create blob for UV plane from raw data
status |= ie_blob_make_memory_from_preallocated(&uv_tensor, img_data + y_plane_size, uv_plane_size, &uv_blob);
// Create NV12Blob from Y and UV blobs
status |= ie_blob_make_memory_nv12(y_blob, uv_blob, &nv12_blob);
if (status != OK)
goto err;
status = ie_infer_request_set_blob(infer_request, input_name, nv12_blob);
if (status != OK)
goto err;
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 7. Do inference
// --------------------------------------------------------
/* Running the request synchronously */
status = ie_infer_request_infer(infer_request);
if (status != OK)
goto err;
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 8. Process output
// ------------------------------------------------------
status = ie_infer_request_get_blob(infer_request, output_name, &output_blob);
if (status != OK)
goto err;
size_t class_num;
struct classify_res* cls = output_blob_to_classify_res(output_blob, &class_num);
classify_res_sort(cls, class_num);
// Print classification results
size_t top = 10;
if (top > class_num) {
top = class_num;
}
printf("\nTop %zu results:\n", top);
print_classify_res(cls, top, input_image_path);
// -----------------------------------------------------------------------------------------------------
free(cls);
ie_blob_free(&output_blob);
ie_blob_free(&nv12_blob);
ie_blob_free(&uv_blob);
ie_blob_free(&y_blob);
ie_infer_request_free(&infer_request);
ie_exec_network_free(&exe_network);
ie_network_name_free(&input_name);
ie_network_name_free(&output_name);
ie_network_free(&network);
ie_core_free(&core);
free(img_data);
return EXIT_SUCCESS;
err:
if (core)
ie_core_free(&core);
if (network)
ie_network_free(&network);
if (input_name)
ie_network_name_free(&input_name);
if (output_name)
ie_network_name_free(&output_name);
if (exe_network)
ie_exec_network_free(&exe_network);
if (infer_request)
ie_infer_request_free(&infer_request);
if (nv12_blob)
ie_blob_free(&nv12_blob);
if (uv_blob)
ie_blob_free(&uv_blob);
if (y_blob)
ie_blob_free(&y_blob);
if (output_blob)
ie_blob_free(&output_blob);
if (img_data)
free(img_data);
return EXIT_FAILURE;
}
@@ -0,0 +1,9 @@
# Copyright (C) 2018-2021 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
#
ie_add_sample(NAME object_detection_sample_ssd_c
SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.c"
HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/object_detection_sample_ssd.h"
"${CMAKE_CURRENT_SOURCE_DIR}/c_w_dirent.h"
DEPENDENCIES opencv_c_wrapper)
@@ -0,0 +1,171 @@
# Object Detection SSD C Sample {#openvino_inference_engine_ie_bridges_c_samples_object_detection_sample_ssd_README}
This sample demonstrates how to execute an inference of object detection networks like SSD-VGG using Asynchronous Inference Request API and [input reshape feature](../../../docs/IE_DG/ShapeInference.md).
Object Detection SSD C sample application demonstrates how to use the following Inference Engine C API in applications:
| Feature | API | Description |
|:--- |:--- |:---
|Asynchronous Infer |[ie_infer_request_infer_async][ie_infer_request_wait]| Do Asynchronous inference
|Inference Engine Version| [ie_c_api_version] | Get Inference Engine API version
|Available Devices| [ie_core_get_versions] | Get version information of the devices for inference
|Custom Extension Kernels|[ie_core_add_extension] [ie_core_set_config]| Load extension library and config to the device
|Network Operations|[ie_network_get_inputs_number] [ie_network_get_input_dims] [ie_network_get_input_shapes] [ie_network_get_outputs_number] [ie_network_get_output_dims]| Managing of network
|Blob Operations|[ie_blob_get_buffer]| Work with memory container for storing inputs, outputs of the network, weights and biases of the layers
|Input Reshape|[ie_network_reshape]| Set the batch size equal to the number of input images
Basic Inference Engine API is covered by [Hello Classification C sample](../hello_classification/README.md).
> **NOTE**: This sample uses `ie_network_reshape()` to set the batch size. While supported by SSD networks, reshape may not work with arbitrary topologies. See [Shape Inference Guide](../../../docs/IE_DG/ShapeInference.md) for more info.
| Options | Values |
|:--- |:---
| Validated Models | [person-detection-retail-0013](@ref omz_models_model_person_detection_retail_0013)
| Model Format | Inference Engine Intermediate Representation (.xml + .bin), ONNX (.onnx)
| Validated images | The sample uses OpenCV* to [read input image](https://docs.opencv.org/master/d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56) (.bmp, .png, .jpg)
| Supported devices | [All](../../../docs/IE_DG/supported_plugins/Supported_Devices.md) |
| Other language realization | [C++](../../../inference-engine/samples/object_detection_sample_ssd/README.md), [Python](../../python/object_detection_sample_ssd/README.md) |
## How It Works
Upon the start-up the sample application reads command line parameters, loads specified network and image(s) to the Inference
Engine plugin. Then, the sample creates an asynchronous inference request object. When inference is done, the application creates output image(s) and output data to the standard output stream.
You can see the explicit description of
each sample step at [Integration Steps](../../../docs/IE_DG/Integrate_with_customer_application_new_API.md) section of "Integrate the Inference Engine with Your Application" guide.
## Building
To build the sample, please use instructions available at [Build the Sample Applications](../../../docs/IE_DG/Samples_Overview.md) section in Inference Engine Samples guide.
## Running
To run the sample, you need specify a model and image:
- you can use [public](@ref omz_models_group_public) or [Intel's](@ref omz_models_group_intel) pre-trained models from the Open Model Zoo. The models can be downloaded using the [Model Downloader](@ref omz_tools_downloader).
- you can use images from the media files collection available at https://storage.openvinotoolkit.org/data/test_data.
Running the application with the `-h` option yields the following usage message:
```
<path_to_sample>/object_detection_sample_ssd_c -h
[ INFO ] InferenceEngine:
<version><number>
[ INFO ] Parsing input parameters
object_detection_sample_ssd_c [OPTION]
Options:
-h Print a usage message.
-m "<path>" Required. Path to an .xml file with a trained model.
-i "<path>" Required. Path to one or more images or folder with images.
-l "<absolute_path>" Required for CPU plugin custom layers. Absolute path to a shared library with the kernels implementations.
Or
-c "<absolute_path>" Required for GPU, MYRIAD, HDDL custom kernels. Absolute path to the .xml config file
with the kernels descriptions.
-d "<device>" Optional. Specify the target device to infer. Default value is CPU.
Use "-d HETERO:<comma-separated_devices_list>" format to specify HETERO plugin. Sample will look for a suitable plugin for device specified
-g Path to the configuration file. Default value: "config".
```
> **NOTES**:
>
> - By default, Inference Engine samples and demos expect input with BGR channels order. If you trained your model to work with RGB order, you need to manually rearrange the default channels order in the sample or demo application or reconvert your model using the Model Optimizer tool with `--reverse_input_channels` argument specified. For more information about the argument, refer to **When to Reverse Input Channels** section of [Converting a Model Using General Conversion Parameters](../../../docs/MO_DG/prepare_model/convert_model/Converting_Model_General.md).
>
> - Before running the sample with a trained model, make sure the model is converted to the Inference Engine format (\*.xml + \*.bin) using the [Model Optimizer tool](../../../docs/MO_DG/Deep_Learning_Model_Optimizer_DevGuide.md).
>
> - The sample accepts models in ONNX format (.onnx) that do not require preprocessing.
### Example
1. Download a pre-trained model using [Model Downloader](@ref omz_tools_downloader):
```
python <path_to_omz_tools>/downloader.py --name person-detection-retail-0013
```
2. `person-detection-retail-0013` model does not need to be converted, because it is already in necessary format, so you can skip this step. If you want to use a other model that is not in the Inference Engine IR or ONNX format, you can convert it using the model converter script:
```
python <path_to_omz_tools>/converter.py --name <model_name>
```
3. For example, to perform inference on a CPU with the OpenVINO&trade; toolkit person detection SSD models, run one of the following commands:
- with one image and [person-detection-retail-0013](https://docs.openvinotoolkit.org/latest/omz_models_intel_person_detection_retail_0013_description_person_detection_retail_0013.html) model
```
<path_to_sample>/object_detection_sample_ssd_c -i <path_to_image>/inputImage.bmp -m <path_to_model>/person-detection-retail-0013.xml -d CPU
```
- with some images and [person-detection-retail-0013](https://docs.openvinotoolkit.org/latest/omz_models_intel_person_detection_retail_0013_description_person_detection_retail_0013.html) model
```
<path_to_sample>/object_detection_sample_ssd_c -i <path_to_image>/inputImage1.bmp <path_to_image>/inputImage2.bmp ... -m <path_to_model>/person-detection-retail-0013.xml -d CPU
```
- with [person-detection-retail-0002](https://docs.openvinotoolkit.org/latest/omz_models_intel_person_detection_retail_0002_description_person_detection_retail_0002.html) model
```
<path_to_sample>/object_detection_sample_ssd_c -i <path_to_folder_with_images> -m <path_to_model>/person-detection-retail-0002.xml -d CPU
```
## Sample Output
The application outputs several images (`out_0.bmp`, `out_1.bmp`, ... ) with detected objects enclosed in rectangles. It outputs the list of
classes of the detected objects along with the respective confidence values and the coordinates of the rectangles to the standard output stream.
```
<path_to_sample>/object_detection_sample_ssd_c -m person-detection-retail-0013.xml -i image_1.png image_2.jpg
[ INFO ] InferenceEngine:
<version><number>
[ INFO ] Parsing input parameters
[ INFO ] Files were added: 2
[ INFO ] image_1.png
[ INFO ] image_2.jpg
[ INFO ] Loading Inference Engine
[ INFO ] Device info:
CPU
MKLDNNPlugin version ......... <version><number>
Build ......... <version><number>
[ INFO ] Loading network:
person-detection-retail-0013.xml
[ INFO ] Preparing input blobs
[ WARNING ] Image is resized from (1699, 960) to (544, 320)
[ WARNING ] Image is resized from (614, 346) to (544, 320)
[ INFO ] Batch size is 2
[ INFO ] Preparing output blobs
[ INFO ] Loading model to the device
[ INFO ] Create infer request
[ INFO ] Start inference
[ INFO ] Processing output blobs
[0, 1] element, prob = 0.999090 (370, 201)-(634, 762) batch id : 0 WILL BE PRINTED!
[1, 1] element, prob = 0.997386 (836, 192)-(999, 663) batch id : 0 WILL BE PRINTED!
[2, 1] element, prob = 0.314753 (192, 2)-(265, 172) batch id : 0
...
[ INFO ] Image out_0.bmp created!
[ INFO ] Image out_1.bmp created!
[ INFO ] Execution successful
This sample is an API example, for any performance measurements please use the dedicated benchmark_app tool
```
## See Also
- [Integrate the Inference Engine with Your Application](../../../docs/IE_DG/Integrate_with_customer_application_new_API.md)
- [Using Inference Engine Samples](../../../docs/IE_DG/Samples_Overview.md)
- [Model Downloader](@ref omz_tools_downloader)
- [Model Optimizer](../../../docs/MO_DG/Deep_Learning_Model_Optimizer_DevGuide.md)
[ie_infer_request_infer_async]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__InferRequest.html#gad2351010e292b6faec959a3d5a8fb60e
[ie_infer_request_wait]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__InferRequest.html#ga0c05e63e63c8d9cdd92900e82b0137c9
[ie_c_api_version]:https://docs.openvinotoolkit.org/latest/ie_c_api/ie__c__api_8h.html#a8fe3efe9cc606dcc7bec203102043e68
[ie_core_get_versions]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Core.html#ga2932e188a690393f5d594572ac5d237b
[ie_core_add_extension]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Core.html#gadded2444ba81d2d396516b72c2478f8e
[ie_core_set_config]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Core.html#gaf09d1e77cc264067e4e22ddf99f21ec1
[ie_network_get_inputs_number]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Network.html#ga6a3349bca66c4ba8b41a434061fccf52
[ie_network_get_input_dims]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Network.html#gac621a654b89d413041cbc2288627f6a5
[ie_network_get_input_shapes]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Network.html#ga5409734f25ffbb1379e876217c0bc6f3
[ie_network_get_outputs_number]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Network.html#ga869b8c309797f1e09f73ddffd1b57509
[ie_network_get_output_dims]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Network.html#ga8de7bf2f626f19eba08a2f043fc1b5d2
[ie_network_reshape]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Network.html#gac4f690afd0c2221f7db2ff9be4aa0637
[ie_blob_get_buffer]:https://docs.openvinotoolkit.org/latest/ie_c_api/group__Blob.html#ga948e0186cea6a393c113d5c399cfcb4c
@@ -0,0 +1,189 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#if defined(_WIN32)
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN_UNDEF
# endif
# ifndef NOMINMAX
# define NOMINMAX
# define NOMINMAX_UNDEF
# endif
# if defined(_M_IX86) && !defined(_X86_) && !defined(_AMD64_)
# define _X86_
# endif
# if defined(_M_X64) && !defined(_X86_) && !defined(_AMD64_)
# define _AMD64_
# endif
# if defined(_M_ARM) && !defined(_ARM_) && !defined(_ARM64_)
# define _ARM_
# endif
# if defined(_M_ARM64) && !defined(_ARM_) && !defined(_ARM64_)
# define _ARM64_
# endif
// clang-format off
#include <string.h>
#include <windef.h>
#include <fileapi.h>
#include <Winbase.h>
#include <sys/stat.h>
// clang-format on
// Copied from linux libc sys/stat.h:
# define S_ISREG(m) (((m)&S_IFMT) == S_IFREG)
# define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
/// @brief structure to store directory names
typedef struct dirent {
char* d_name;
} dirent;
/**
* @brief Add directory to directory names struct
* @param int argc - count of args
* @param char *argv[] - array values of args
* @param char *opts - array of options
* @return pointer to directory names struct
*/
static dirent* createDirent(const wchar_t* wsFilePath) {
dirent* d = (dirent*)malloc(sizeof(dirent));
size_t i;
size_t slen = wcslen(wsFilePath);
d->d_name = (char*)(malloc(slen + 1));
wcstombs_s(&i, d->d_name, slen + 1, wsFilePath, slen);
return d;
}
/**
* @brief Free directory names struct
* @param point to directory names structure
* @return none
*/
static void freeDirent(dirent** d) {
free((*d)->d_name);
(*d)->d_name = NULL;
free(*d);
*d = NULL;
}
/// @brief structure to store directory data (files meta)
typedef struct DIR {
WIN32_FIND_DATAA FindFileData;
HANDLE hFind;
dirent* next;
} DIR;
/**
* @brief Compare two string, second string is the end of the first
* @param string to compare
* @param end string to find
* @return status 1(success) or 0(fail)
*/
static int endsWith(const char* src, const char* with) {
int wl = (int)(strlen(with));
int so = (int)(strlen(with)) - wl;
if (so < 0)
return 0;
if (strncmp(with, &(src[so]), wl) == 0)
return 1;
else
return 0;
}
/**
* @brief Check file handler is valid
* @param struct of directory data
* @return status 1(success) or 0(fail)
*/
static int isValid(DIR* dp) {
if (dp->hFind != INVALID_HANDLE_VALUE && dp->FindFileData.dwReserved0) {
return 1;
} else {
return 0;
}
}
/**
* @brief Create directory data struct element
* @param string directory path
* @return pointer to directory data struct element
*/
static DIR* opendir(const char* dirPath) {
DIR* dp = (DIR*)malloc(sizeof(DIR));
dp->next = NULL;
char* ws = (char*)(malloc(strlen(dirPath) + 1));
strcpy(ws, dirPath);
if (endsWith(ws, "\\"))
strcat(ws, "*");
else
strcat(ws, "\\*");
dp->hFind = FindFirstFileA(ws, &dp->FindFileData);
dp->FindFileData.dwReserved0 = dp->hFind != INVALID_HANDLE_VALUE;
free(ws);
if (isValid(dp)) {
free(dp);
return NULL;
}
return dp;
}
/**
* @brief Walk throw directory data struct
* @param pointer to directory data struct
* @return pointer to directory data struct next element
*/
static struct dirent* readdir(DIR* dp) {
if (dp->next != NULL)
freeDirent(&(dp->next));
if (!dp->FindFileData.dwReserved0)
return NULL;
wchar_t wbuf[4096];
size_t outSize;
mbstowcs_s(&outSize, wbuf, 4094, dp->FindFileData.cFileName, 4094);
dp->next = createDirent(wbuf);
dp->FindFileData.dwReserved0 = FindNextFileA(dp->hFind, &(dp->FindFileData));
return dp->next;
}
/**
* @brief Remove directory data struct
* @param pointer to struct directory data
* @return none
*/
static void closedir(DIR* dp) {
if (dp->next) {
freeDirent(&(dp->next));
}
free(dp);
}
# ifdef WIN32_LEAN_AND_MEAN_UNDEF
# undef WIN32_LEAN_AND_MEAN
# undef WIN32_LEAN_AND_MEAN_UNDEF
# endif
# ifdef NOMINMAX_UNDEF
# undef NOMINMAX_UNDEF
# undef NOMINMAX
# endif
#else
# include <dirent.h>
# include <sys/types.h>
#endif
@@ -0,0 +1,810 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <c_api/ie_c_api.h>
#include <opencv_c_wrapper.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include "object_detection_sample_ssd.h"
#ifdef _WIN32
# include "c_w_dirent.h"
#else
# include <dirent.h>
#endif
#define MAX_IMAGES 20
static const char* img_msg = NULL;
static const char* input_model = NULL;
static const char* device_name = "CPU";
static const char* custom_plugin_cfg_msg = NULL;
static const char* custom_ex_library_msg = NULL;
static const char* config_msg = NULL;
static int file_num = 0;
static char** file_paths = NULL;
const char* info = "[ INFO ] ";
const char* warn = "[ WARNING ] ";
/**
* @brief Parse and check command line arguments
* @param int argc - count of args
* @param char *argv[] - array values of args
* @return int - status 1(success) or -1(fail)
*/
int ParseAndCheckCommandLine(int argc, char* argv[]) {
int opt = 0;
int help = 0;
char* string = "hi:m:d:c:l:g:";
printf("%sParsing input parameters\n", info);
while ((opt = getopt(argc, argv, string)) != -1) {
switch (opt) {
case 'h':
showUsage();
help = 1;
break;
case 'i':
img_msg = optarg;
break;
case 'm':
input_model = optarg;
break;
case 'd':
device_name = optarg;
break;
case 'c':
custom_plugin_cfg_msg = optarg;
break;
case 'l':
custom_ex_library_msg = optarg;
break;
case 'g':
config_msg = optarg;
break;
default:
return -1;
}
}
if (help)
return -1;
if (input_model == NULL) {
printf("Model is required but not set. Please set -m option.\n");
return -1;
}
if (img_msg == NULL) {
printf("Input is required but not set.Please set -i option.\n");
return -1;
}
return 1;
}
/**
* @brief This function checks input args and existence of specified files in a
* given folder. Updated the file_paths and file_num.
* @param arg path to a file to be checked for existence
* @return none.
*/
void readInputFilesArgument(const char* arg) {
struct stat sb;
int i;
if (stat(arg, &sb) != 0) {
printf("%sFile %s cannot be opened!\n", warn, arg);
return;
}
if (S_ISDIR(sb.st_mode)) {
DIR* dp;
dp = opendir(arg);
if (dp == NULL) {
printf("%sFile %s cannot be opened!\n", warn, arg);
return;
}
struct dirent* ep;
while (NULL != (ep = readdir(dp))) {
const char* fileName = ep->d_name;
if (strcmp(fileName, ".") == 0 || strcmp(fileName, "..") == 0)
continue;
char* file_path = (char*)calloc(strlen(arg) + strlen(ep->d_name) + 2, sizeof(char));
memcpy(file_path, arg, strlen(arg));
memcpy(file_path + strlen(arg), "/", strlen("/"));
memcpy(file_path + strlen(arg) + strlen("/"), ep->d_name, strlen(ep->d_name) + 1);
if (file_num == 0) {
file_paths = (char**)calloc(1, sizeof(char*));
file_paths[0] = file_path;
++file_num;
} else {
char** temp = (char**)realloc(file_paths, sizeof(char*) * (file_num + 1));
if (temp) {
file_paths = temp;
file_paths[file_num++] = file_path;
} else {
for (i = 0; i < file_num; ++i) {
free(file_paths[i]);
}
free(file_path);
free(file_paths);
file_num = 0;
}
}
}
closedir(dp);
dp = NULL;
} else {
char* file_path = (char*)calloc(strlen(arg) + 1, sizeof(char));
memcpy(file_path, arg, strlen(arg) + 1);
if (file_num == 0) {
file_paths = (char**)calloc(1, sizeof(char*));
}
file_paths[file_num++] = file_path;
}
}
/**
* @brief This function find -i key in input args. It's necessary to process
* multiple values for single key
* @return none.
*/
void parseInputFilesArguments(int argc, char** argv) {
int readArguments = 0, i;
for (i = 0; i < argc; ++i) {
if (strcmp(argv[i], "-i") == 0) {
readArguments = 1;
continue;
}
if (!readArguments) {
continue;
}
if (argv[i][0] == '-') {
break;
}
readInputFilesArgument(argv[i]);
}
if (file_num < MAX_IMAGES) {
printf("%sFiles were added: %d\n", info, file_num);
for (i = 0; i < file_num; ++i) {
printf("%s %s\n", info, file_paths[i]);
}
} else {
printf("%sFiles were added: %d. Too many to display each of them.\n", info, file_num);
}
}
/**
* @brief Convert the contents of configuration file to the ie_config_t struct.
* @param config_file File path.
* @param comment Separator symbol.
* @return A pointer to the ie_config_t instance.
*/
ie_config_t* parseConfig(const char* config_file, char comment) {
FILE* file = fopen(config_file, "r");
if (!file) {
return NULL;
}
ie_config_t* cfg = NULL;
char key[256], value[256];
if (fscanf(file, "%s", key) != EOF && fscanf(file, "%s", value) != EOF) {
char* cfg_name = (char*)calloc(strlen(key) + 1, sizeof(char));
char* cfg_value = (char*)calloc(strlen(value) + 1, sizeof(char));
memcpy(cfg_name, key, strlen(key) + 1);
memcpy(cfg_value, value, strlen(value) + 1);
ie_config_t* cfg_t = (ie_config_t*)calloc(1, sizeof(ie_config_t));
cfg_t->name = cfg_name;
cfg_t->value = cfg_value;
cfg_t->next = NULL;
cfg = cfg_t;
}
if (cfg) {
ie_config_t* cfg_temp = cfg;
while (fscanf(file, "%s", key) != EOF && fscanf(file, "%s", value) != EOF) {
if (strlen(key) == 0 || key[0] == comment) {
continue;
}
char* cfg_name = (char*)calloc(strlen(key) + 1, sizeof(char));
char* cfg_value = (char*)calloc(strlen(value) + 1, sizeof(char));
memcpy(cfg_name, key, strlen(key) + 1);
memcpy(cfg_value, value, strlen(value) + 1);
ie_config_t* cfg_t = (ie_config_t*)calloc(1, sizeof(ie_config_t));
cfg_t->name = cfg_name;
cfg_t->value = cfg_value;
cfg_t->next = NULL;
cfg_temp->next = cfg_t;
cfg_temp = cfg_temp->next;
}
}
fclose(file);
return cfg;
}
/**
* @brief Releases memory occupied by config
* @param config A pointer to the config to free memory.
* @return none
*/
void config_free(ie_config_t* config) {
while (config) {
ie_config_t* temp = config;
if (config->name) {
free((char*)config->name);
config->name = NULL;
}
if (config->value) {
free((char*)config->value);
config->value = NULL;
}
if (config->next) {
config = config->next;
}
free(temp);
temp = NULL;
}
}
/**
* @brief Convert the numbers to char *;
* @param str A pointer to the converted string.
* @param num The number to convert.
* @return none.
*/
void int2str(char* str, int num) {
int i = 0, j;
if (num == 0) {
str[0] = '0';
str[1] = '\0';
return;
}
while (num != 0) {
str[i++] = num % 10 + '0';
num = num / 10;
}
str[i] = '\0';
--i;
for (j = 0; j < i; ++j, --i) {
char temp = str[j];
str[j] = str[i];
str[i] = temp;
}
}
int main(int argc, char** argv) {
/** This sample covers certain topology and cannot be generalized for any
* object detection one **/
// ------------------------------ Get Inference Engine API version
// ---------------------------------
ie_version_t version = ie_c_api_version();
printf("%sInferenceEngine: \n", info);
printf("%s\n", version.api_version);
ie_version_free(&version);
// ------------------------------ Parsing and validation of input args
// ---------------------------------
char** argv_temp = (char**)calloc(argc, sizeof(char*));
if (!argv_temp) {
return EXIT_FAILURE;
}
int i, j;
for (i = 0; i < argc; ++i) {
argv_temp[i] = argv[i];
}
char *input_weight = NULL, *imageInputName = NULL, *imInfoInputName = NULL, *output_name = NULL;
ie_core_t* core = NULL;
ie_network_t* network = NULL;
ie_executable_network_t* exe_network = NULL;
ie_infer_request_t* infer_request = NULL;
ie_blob_t *imageInput = NULL, *output_blob = NULL;
if (ParseAndCheckCommandLine(argc, argv) < 0) {
free(argv_temp);
return EXIT_FAILURE;
}
// -----------------------------------------------------------------------------------------------------
// --------------------------- Read input
// -----------------------------------------------------------
/** This file_paths stores paths to the processed images **/
parseInputFilesArguments(argc, argv_temp);
if (!file_num) {
printf("No suitable images were found\n");
free(argv_temp);
return EXIT_FAILURE;
}
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 1. Initialize inference engine core
// -------------------------------------
printf("%sLoading Inference Engine\n", info);
IEStatusCode status = ie_core_create("", &core);
if (status != OK)
goto err;
// ------------------------------ Get Available Devices
// ------------------------------------------------------
ie_core_versions_t ver;
printf("%sDevice info: \n", info);
status = ie_core_get_versions(core, device_name, &ver);
if (status != OK)
goto err;
for (i = 0; i < ver.num_vers; ++i) {
printf(" %s\n", ver.versions[i].device_name);
printf(" %s version ......... %zu.%zu\n",
ver.versions[i].description,
ver.versions[i].major,
ver.versions[i].minor);
printf(" Build ......... %s\n", ver.versions[i].build_number);
}
ie_core_versions_free(&ver);
if (custom_ex_library_msg) {
// Custom CPU extension is loaded as a shared library and passed as a
// pointer to base extension
status = ie_core_add_extension(core, custom_ex_library_msg, "CPU");
if (status != OK)
goto err;
printf("%sCustom extension loaded: %s\n", info, custom_ex_library_msg);
}
if (custom_plugin_cfg_msg &&
(strcmp(device_name, "GPU") == 0 || strcmp(device_name, "MYRIAD") == 0 || strcmp(device_name, "HDDL") == 0)) {
// Config for device plugin custom extension is loaded from an .xml
// description
ie_config_t cfg = {"CONFIG_FILE", custom_plugin_cfg_msg, NULL};
status = ie_core_set_config(core, &cfg, device_name);
if (status != OK)
goto err;
printf("%sConfig for device plugin custom extension loaded: %s\n", info, custom_plugin_cfg_msg);
}
// -----------------------------------------------------------------------------------------------------
// Step 2. Read a model in OpenVINO Intermediate Representation (.xml and .bin
// files) or ONNX (.onnx file) format
printf("%sLoading network:\n", info);
printf("\t%s\n", input_model);
status = ie_core_read_network(core, input_model, NULL, &network);
if (status != OK)
goto err;
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 3. Configure input & output
// ---------------------------------------------
// --------------------------- Prepare input blobs
// -----------------------------------------------------
printf("%sPreparing input blobs\n", info);
/** SSD network has one input and one output **/
size_t input_num = 0;
status = ie_network_get_inputs_number(network, &input_num);
if (status != OK || (input_num != 1 && input_num != 2)) {
printf("Sample supports topologies only with 1 or 2 inputs\n");
goto err;
}
/**
* Some networks have SSD-like output format (ending with DetectionOutput
* layer), but having 2 inputs as Faster-RCNN: one for image and one for
* "image info".
*
* Although object_datection_sample_ssd's main task is to support clean SSD,
* it could score the networks with two inputs as well. For such networks
* imInfoInputName will contain the "second" input name.
*/
size_t input_width = 0, input_height = 0;
/** Stores input image **/
/** Iterating over all input blobs **/
for (i = 0; i < input_num; ++i) {
char* name = NULL;
status |= ie_network_get_input_name(network, i, &name);
dimensions_t input_dim;
status |= ie_network_get_input_dims(network, name, &input_dim);
if (status != OK)
goto err;
/** Working with first input tensor that stores image **/
if (input_dim.ranks == 4) {
imageInputName = name;
input_height = input_dim.dims[2];
input_width = input_dim.dims[3];
/** Creating first input blob **/
status = ie_network_set_input_precision(network, name, U8);
if (status != OK)
goto err;
} else if (input_dim.ranks == 2) {
imInfoInputName = name;
status = ie_network_set_input_precision(network, name, FP32);
if (status != OK || (input_dim.dims[1] != 3 && input_dim.dims[1] != 6)) {
printf("Invalid input info. Should be 3 or 6 values length\n");
goto err;
}
}
}
if (imageInputName == NULL) {
status = ie_network_get_input_name(network, 0, &imageInputName);
if (status != OK)
goto err;
dimensions_t input_dim;
status = ie_network_get_input_dims(network, imageInputName, &input_dim);
if (status != OK)
goto err;
input_height = input_dim.dims[2];
input_width = input_dim.dims[3];
}
/** Collect images data **/
c_mat_t* originalImages = (c_mat_t*)calloc(file_num, sizeof(c_mat_t));
c_mat_t* images = (c_mat_t*)calloc(file_num, sizeof(c_mat_t));
if (!originalImages || !images)
goto err;
int image_num = 0;
for (i = 0; i < file_num; ++i) {
c_mat_t img = {NULL, 0, 0, 0, 0, 0};
if (image_read(file_paths[i], &img) == -1) {
printf("%sImage %s cannot be read!\n", warn, file_paths[i]);
continue;
}
/** Store image data **/
c_mat_t resized_img = {NULL, 0, 0, 0, 0, 0};
if ((input_width == img.mat_width) && (input_height == img.mat_height)) {
resized_img.mat_data_size = img.mat_data_size;
resized_img.mat_channels = img.mat_channels;
resized_img.mat_width = img.mat_width;
resized_img.mat_height = img.mat_height;
resized_img.mat_type = img.mat_type;
resized_img.mat_data = calloc(1, resized_img.mat_data_size);
if (resized_img.mat_data == NULL) {
image_free(&img);
continue;
}
for (j = 0; j < resized_img.mat_data_size; ++j)
resized_img.mat_data[j] = img.mat_data[j];
} else {
printf("%sImage is resized from (%d, %d) to (%zu, %zu)\n",
warn,
img.mat_width,
img.mat_height,
input_width,
input_height);
if (image_resize(&img, &resized_img, (int)input_width, (int)input_height) == -1) {
printf("%sImage %s cannot be resized!\n", warn, file_paths[i]);
image_free(&img);
continue;
}
}
originalImages[image_num] = img;
images[image_num] = resized_img;
++image_num;
}
if (!image_num) {
printf("Valid input images were not found!\n");
free(originalImages);
free(images);
goto err;
}
input_shapes_t shapes;
status = ie_network_get_input_shapes(network, &shapes);
if (status != OK)
goto err;
/** Using ie_network_reshape() to set the batch size equal to the number of
* input images **/
/** For input with NCHW/NHWC layout the first dimension N is the batch size
* **/
shapes.shapes[0].shape.dims[0] = image_num;
status = ie_network_reshape(network, shapes);
if (status != OK)
goto err;
ie_network_input_shapes_free(&shapes);
input_shapes_t shapes2;
status = ie_network_get_input_shapes(network, &shapes2);
if (status != OK)
goto err;
size_t batchSize = shapes2.shapes[0].shape.dims[0];
ie_network_input_shapes_free(&shapes2);
printf("%sBatch size is %zu\n", info, batchSize);
// --------------------------- Prepare output blobs
// ----------------------------------------------------
printf("%sPreparing output blobs\n", info);
size_t output_num = 0;
status = ie_network_get_outputs_number(network, &output_num);
if (status != OK || !output_num) {
printf("Can't find a DetectionOutput layer in the topology\n");
goto err;
}
status = ie_network_get_output_name(network, output_num - 1, &output_name);
if (status != OK)
goto err;
dimensions_t output_dim;
status = ie_network_get_output_dims(network, output_name, &output_dim);
if (status != OK)
goto err;
if (output_dim.ranks != 4) {
printf("Incorrect output dimensions for SSD model\n");
goto err;
}
const int maxProposalCount = (int)output_dim.dims[2];
const int objectSize = (int)output_dim.dims[3];
if (objectSize != 7) {
printf("Output item should have 7 as a last dimension\n");
goto err;
}
/** Set the precision of output data provided by the user, should be called
* before load of the network to the device **/
status = ie_network_set_output_precision(network, output_name, FP32);
if (status != OK)
goto err;
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 4. Loading model to the device
// ------------------------------------------
printf("%sLoading model to the device\n", info);
if (config_msg) {
ie_config_t* config = parseConfig(config_msg, '#');
status = ie_core_load_network(core, network, device_name, config, &exe_network);
config_free(config);
if (status != OK) {
goto err;
}
} else {
ie_config_t cfg = {NULL, NULL, NULL};
status = ie_core_load_network(core, network, device_name, &cfg, &exe_network);
if (status != OK)
goto err;
}
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 5. Create infer request
// -------------------------------------------------
printf("%sCreate infer request\n", info);
status = ie_exec_network_create_infer_request(exe_network, &infer_request);
if (status != OK)
goto err;
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 6. Prepare input
// --------------------------------------------------------
/** Creating input blob **/
status = ie_infer_request_get_blob(infer_request, imageInputName, &imageInput);
if (status != OK)
goto err;
/** Filling input tensor with images. First b channel, then g and r channels
* **/
dimensions_t input_tensor_dims;
status = ie_blob_get_dims(imageInput, &input_tensor_dims);
if (status != OK)
goto err;
size_t num_channels = input_tensor_dims.dims[1];
size_t image_size = input_tensor_dims.dims[3] * input_tensor_dims.dims[2];
ie_blob_buffer_t blob_buffer;
status = ie_blob_get_buffer(imageInput, &blob_buffer);
if (status != OK)
goto err;
unsigned char* data = (unsigned char*)(blob_buffer.buffer);
/** Iterate over all input images **/
int image_id, pid, ch, k;
for (image_id = 0; image_id < batchSize; ++image_id) {
/** Iterate over all pixel in image (b,g,r) **/
for (pid = 0; pid < image_size; ++pid) {
/** Iterate over all channels **/
for (ch = 0; ch < num_channels; ++ch) {
/** [images stride + channels stride + pixel id ] all in bytes
* **/
data[image_id * image_size * num_channels + ch * image_size + pid] =
images[image_id].mat_data[pid * num_channels + ch];
}
}
image_free(&images[image_id]);
}
free(images);
ie_blob_free(&imageInput);
if (imInfoInputName != NULL) {
ie_blob_t* input2 = NULL;
status = ie_infer_request_get_blob(infer_request, imInfoInputName, &input2);
dimensions_t imInfoDim;
status |= ie_blob_get_dims(input2, &imInfoDim);
// Fill input tensor with values
ie_blob_buffer_t info_blob_buffer;
status |= ie_blob_get_buffer(input2, &info_blob_buffer);
if (status != OK) {
ie_blob_free(&input2);
goto err;
}
float* p = (float*)(info_blob_buffer.buffer);
for (image_id = 0; image_id < batchSize; ++image_id) {
p[image_id * imInfoDim.dims[1] + 0] = (float)input_height;
p[image_id * imInfoDim.dims[1] + 1] = (float)input_width;
for (k = 2; k < imInfoDim.dims[1]; k++) {
p[image_id * imInfoDim.dims[1] + k] = 1.0f; // all scale factors are set to 1.0
}
}
ie_blob_free(&input2);
}
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 7. Do inference
// --------------------------------------------------------
printf("%sStart inference\n", info);
status = ie_infer_request_infer_async(infer_request);
status |= ie_infer_request_wait(infer_request, -1);
if (status != OK)
goto err;
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 8. Process output
// ------------------------------------------------------
printf("%sProcessing output blobs\n", info);
status = ie_infer_request_get_blob(infer_request, output_name, &output_blob);
if (status != OK)
goto err;
ie_blob_buffer_t output_blob_buffer;
status = ie_blob_get_cbuffer(output_blob, &output_blob_buffer);
if (status != OK)
goto err;
const float* detection = (float*)(output_blob_buffer.cbuffer);
int** classes = (int**)calloc(image_num, sizeof(int*));
rectangle_t** boxes = (rectangle_t**)calloc(image_num, sizeof(rectangle_t*));
int* object_num = (int*)calloc(image_num, sizeof(int));
for (i = 0; i < image_num; ++i) {
classes[i] = (int*)calloc(maxProposalCount, sizeof(int));
boxes[i] = (rectangle_t*)calloc(maxProposalCount, sizeof(rectangle_t));
object_num[i] = 0;
}
/* Each detection has image_id that denotes processed image */
int curProposal;
for (curProposal = 0; curProposal < maxProposalCount; curProposal++) {
image_id = (int)(detection[curProposal * objectSize + 0]);
if (image_id < 0) {
break;
}
float confidence = detection[curProposal * objectSize + 2];
int label = (int)(detection[curProposal * objectSize + 1]);
int xmin = (int)(detection[curProposal * objectSize + 3] * originalImages[image_id].mat_width);
int ymin = (int)(detection[curProposal * objectSize + 4] * originalImages[image_id].mat_height);
int xmax = (int)(detection[curProposal * objectSize + 5] * originalImages[image_id].mat_width);
int ymax = (int)(detection[curProposal * objectSize + 6] * originalImages[image_id].mat_height);
printf("[%d, %d] element, prob = %f (%d, %d)-(%d, %d) batch id : %d",
curProposal,
label,
confidence,
xmin,
ymin,
xmax,
ymax,
image_id);
if (confidence > 0.5) {
/** Drawing only objects with >50% probability **/
classes[image_id][object_num[image_id]] = label;
boxes[image_id][object_num[image_id]].x_min = xmin;
boxes[image_id][object_num[image_id]].y_min = ymin;
boxes[image_id][object_num[image_id]].rect_width = xmax - xmin;
boxes[image_id][object_num[image_id]].rect_height = ymax - ymin;
printf(" WILL BE PRINTED!");
++object_num[image_id];
}
printf("\n");
}
/** Adds rectangles to the image and save **/
int batch_id;
for (batch_id = 0; batch_id < batchSize; ++batch_id) {
if (object_num[batch_id] > 0) {
image_add_rectangles(&originalImages[batch_id],
boxes[batch_id],
classes[batch_id],
object_num[batch_id],
2);
}
const char* out = "out_";
char str_num[16] = {0};
int2str(str_num, batch_id);
char* img_path = (char*)calloc(strlen(out) + strlen(str_num) + strlen(".bmp") + 1, sizeof(char));
memcpy(img_path, out, strlen(out));
memcpy(img_path + strlen(out), str_num, strlen(str_num));
memcpy(img_path + strlen(out) + strlen(str_num), ".bmp", strlen(".bmp") + 1);
image_save(img_path, &originalImages[batch_id]);
printf("%sImage %s created!\n", info, img_path);
free(img_path);
image_free(&originalImages[batch_id]);
}
free(originalImages);
// -----------------------------------------------------------------------------------------------------
printf("%sExecution successful\n", info);
printf("\nThis sample is an API example,"
" for any performance measurements please use the dedicated benchmark_"
"app tool\n");
for (i = 0; i < image_num; ++i) {
free(classes[i]);
free(boxes[i]);
}
free(classes);
free(boxes);
free(object_num);
ie_blob_free(&output_blob);
ie_infer_request_free(&infer_request);
ie_exec_network_free(&exe_network);
ie_network_free(&network);
ie_core_free(&core);
ie_network_name_free(&imageInputName);
ie_network_name_free(&imInfoInputName);
ie_network_name_free(&output_name);
free(input_weight);
free(argv_temp);
return EXIT_SUCCESS;
err:
free(argv_temp);
if (input_weight)
free(input_weight);
if (core)
ie_core_free(&core);
if (network)
ie_network_free(&network);
if (imageInputName)
ie_network_name_free(&imageInputName);
if (imInfoInputName)
ie_network_name_free(&imInfoInputName);
if (output_name)
ie_network_name_free(&output_name);
if (exe_network)
ie_exec_network_free(&exe_network);
if (imageInput)
ie_blob_free(&imageInput);
if (output_blob)
ie_blob_free(&output_blob);
return EXIT_FAILURE;
}
@@ -0,0 +1,114 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <stdlib.h>
/// @brief message for help argument
static const char* help_message = "Print a usage message.";
/// @brief message for model argument
static const char* model_message = "Required. Path to an .xml file with a trained model.";
/// @brief message for images argument
static const char* image_message = "Required. Path to one or more images or folder with images.";
/// @brief message for assigning cnn calculation to device
static const char* target_device_message =
"Optional. Specify the target device to infer. "
"Default value is CPU. Use \"-d HETERO:<comma-separated_devices_list>\" format to specify "
"HETERO plugin. "
"Sample will look for a suitable plugin for device specified.";
/// @brief message for plugin custom kernels desc
static const char* custom_plugin_config_message =
"Required for GPU, MYRIAD, HDDL custom kernels. "
"Absolute path to the .xml config file with the kernels descriptions.";
/// @brief message for user extension library argument
static const char* custom_ex_library_message = "Required for CPU plugin custom layers. "
"Absolute path to a shared library with the kernels implementations.";
/// @brief message for config argument
static const char* config_message = "Path to the configuration file. Default value: \"config\".";
/**
* \brief This function show a help message
*/
static void showUsage() {
printf("\nobject_detection_sample_ssd_c [OPTION]\n");
printf("Options:\n\n");
printf(" -h %s\n", help_message);
printf(" -m \"<path>\" %s\n", model_message);
printf(" -i \"<path>\" %s\n", image_message);
printf(" -l \"<absolute_path>\" %s\n", custom_ex_library_message);
printf(" Or\n");
printf(" -c \"<absolute_path>\" %s\n", custom_plugin_config_message);
printf(" -d \"<device>\" %s\n", target_device_message);
printf(" -g %s\n", config_message);
}
int opterr = 1;
int optind = 1;
int optopt;
char* optarg;
#define ERR(s, c) \
if (opterr) { \
fputs(argv[0], stderr); \
fputs(s, stderr); \
fputc('\'', stderr); \
fputc(c, stderr); \
fputs("\'\n", stderr); \
}
/**
* @brief Check command line arguments with available options
* @param int argc - count of args
* @param char *argv[] - array values of args
* @param char *opts - array of options
* @return option name or -1(fail)
*/
static int getopt(int argc, char** argv, char* opts) {
static int sp = 1;
register int c = 0;
register char* cp = NULL;
if (sp == 1) {
if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
return -1;
else if (strcmp(argv[optind], "--") == 0) {
optind++;
return -1;
}
optopt = c = argv[optind][sp];
if (c == ':' || (cp = strchr(opts, c)) == 0) {
ERR(": unrecognized option -- ", c);
showUsage();
if (argv[optind][++sp] == '\0') {
optind++;
sp = 1;
}
return ('?');
}
if (*++cp == ':') {
if (argv[optind][sp + 1] != '\0')
optarg = &argv[optind++][sp + 1];
else if (++optind >= argc) {
ERR(": option requires an argument -- ", c);
sp = 1;
return ('?');
} else
optarg = argv[optind++];
sp = 1;
} else {
if (argv[optind][++sp] == '\0') {
sp = 1;
optind++;
}
optarg = NULL;
}
}
return (c);
}
@@ -15,9 +15,9 @@ Basic Inference Engine API is covered by [Hello Classification Python* Sample](.
| Options | Values |
| :------------------------- | :-------------------------------------------------------------------------------------------------------- |
| Validated Models | [alexnet](@ref omz_models_model_alexnet) |
| Model Format | Inference Engine Intermediate Representation (.xml + .bin), ONNX (.onnx) |
| Supported devices | [All](../../../docs/IE_DG/supported_plugins/Supported_Devices.md) |
| Other language realization | [C++](../../../inference-engine/samples/classification_sample_async/README.md) |
| Model Format | Inference Engine Intermediate Representation (.xml + .bin), ONNX (.onnx) |
| Supported devices | [All](../../../docs/IE_DG/supported_plugins/Supported_Devices.md) |
| Other language realization | [C++](../../../inference-engine/samples/classification_sample_async/README.md) |
## How It Works
@@ -14,9 +14,9 @@ The following Inference Engine Python API is used in the application:
| Options | Values |
| :------------------------- | :-------------------------------------------------------------------------------------------------------- |
| Validated Models | [alexnet](@ref omz_models_model_alexnet), [googlenet-v1](@ref omz_models_model_googlenet_v1) |
| Model Format | Inference Engine Intermediate Representation (.xml + .bin), ONNX (.onnx) |
| Supported devices | [All](../../../docs/IE_DG/supported_plugins/Supported_Devices.md) |
| Other language realization | [C++](../../../inference-engine/samples/hello_classification/README.md), [C](../../../inference-engine/ie_bridges/c/samples/hello_classification/README.md) |
| Model Format | Inference Engine Intermediate Representation (.xml + .bin), ONNX (.onnx) |
| Supported devices | [All](../../../docs/IE_DG/supported_plugins/Supported_Devices.md) |
| Other language realization | [C++](../../../inference-engine/samples/hello_classification/README.md), [C](../../c/hello_classification/README.md) |
## How It Works
+1 -1
View File
@@ -12,7 +12,7 @@ The following Inference Engine Python API is used in the application:
| Options | Values |
| :------------------------- | :---------------------------------------------------------------------- |
| Supported devices | [All](../../../docs/IE_DG/supported_plugins/Supported_Devices.md) |
| Other language realization | [C++](../../../inference-engine/samples/hello_query_device/README.md) |
| Other language realization | [C++](../../../inference-engine/samples/hello_query_device/README.md) |
## How It Works
+3 -3
View File
@@ -15,9 +15,9 @@ Basic Inference Engine API is covered by [Hello Classification Python* Sample](.
| Options | Values |
| :------------------------- | :-------------------------------------------------------------------------------------------------------------------------- |
| Validated Models | [mobilenet-ssd](@ref omz_models_model_mobilenet_ssd) |
| Model Format | Inference Engine Intermediate Representation (.xml + .bin), ONNX (.onnx) |
| Supported devices | [All](../../../docs/IE_DG/supported_plugins/Supported_Devices.md) |
| Other language realization | [C++](../../../inference-engine/samples/hello_reshape_ssd/README.md) |
| Model Format | Inference Engine Intermediate Representation (.xml + .bin), ONNX (.onnx) |
| Supported devices | [All](../../../docs/IE_DG/supported_plugins/Supported_Devices.md) |
| Other language realization | [C++](../../../inference-engine/samples/hello_reshape_ssd/README.md) |
## How It Works
@@ -15,11 +15,11 @@ Basic Inference Engine API is covered by [Hello Classification Python* Sample](.
| Options | Values |
| :------------------------- | :---------------------------------------------------------------------- |
| Validated Models | LeNet |
| Model Format | Network weights file (\*.bin) |
| Validated images | The sample uses OpenCV\* to [read input grayscale image](https://docs.opencv.org/master/d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56) (\*.bmp, \*.png) or single-channel `ubyte` image |
| Validated Models | LeNet |
| Model Format | Network weights file (\*.bin) |
| Validated images | The sample uses OpenCV\* to [read input grayscale image](https://docs.opencv.org/master/d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56) (\*.bmp, \*.png) or single-channel `ubyte` image |
| Supported devices | [All](../../../docs/IE_DG/supported_plugins/Supported_Devices.md) |
| Other language realization | [C++](../../../inference-engine/samples/ngraph_function_creation_sample/README.md) |
| Other language realization | [C++](../../../inference-engine/samples/ngraph_function_creation_sample/README.md) |
## How It Works
@@ -15,9 +15,9 @@ Basic Inference Engine API is covered by [Hello Classification Python* Sample](.
| Options | Values |
| :------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Validated Models | [mobilenet-ssd](@ref omz_models_model_mobilenet_ssd), [face-detection-0206](@ref omz_models_model_face_detection_0206) |
| Model Format | Inference Engine Intermediate Representation (.xml + .bin), ONNX (.onnx) |
| Supported devices | [All](../../../docs/IE_DG/supported_plugins/Supported_Devices.md) |
| Other language realization | [C++](../../../inference-engine/samples/object_detection_sample_ssd/README.md), [C](../../../inference-engine/ie_bridges/c/samples/object_detection_sample_ssd/README.md) |
| Model Format | Inference Engine Intermediate Representation (.xml + .bin), ONNX (.onnx) |
| Supported devices | [All](../../../docs/IE_DG/supported_plugins/Supported_Devices.md) |
| Other language realization | [C++](../../../inference-engine/samples/object_detection_sample_ssd/README.md), [C](../../c/object_detection_sample_ssd/README.md) |
## How It Works
+3 -3
View File
@@ -18,9 +18,9 @@ Basic Inference Engine API is covered by [Hello Classification Python* Sample](.
| Options | Values |
| :------------------------- | :---------------------------------------------------------------------------------------------------- |
| Validated Models | Acoustic model based on Kaldi* neural networks (see [Model Preparation](#model-preparation) section) |
| Model Format | Inference Engine Intermediate Representation (.xml + .bin) |
| Supported devices | See [Execution Modes](#execution-modes) section below and [List Supported Devices](../../../docs/IE_DG/supported_plugins/Supported_Devices.md) |
| Other language realization | [C++](../../../inference-engine/samples/speech_sample/README.md) |
| Model Format | Inference Engine Intermediate Representation (.xml + .bin) |
| Supported devices | See [Execution Modes](#execution-modes) section below and [List Supported Devices](../../../docs/IE_DG/supported_plugins/Supported_Devices.md) |
| Other language realization | [C++](../../../inference-engine/samples/speech_sample/README.md) |
## How It Works
@@ -16,9 +16,9 @@ Basic Inference Engine API is covered by [Hello Classification Python* Sample](.
| Options | Values |
| :------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Validated Models | [fast-neural-style-mosaic-onnx](@ref omz_models_model_fast_neural_style_mosaic_onnx) |
| Model Format | Inference Engine Intermediate Representation (.xml + .bin), ONNX (.onnx) |
| Supported devices | [All](../../../docs/IE_DG/supported_plugins/Supported_Devices.md) |
| Other language realization | [C++](../../../inference-engine/samples/style_transfer_sample/README.md) |
| Model Format | Inference Engine Intermediate Representation (.xml + .bin), ONNX (.onnx) |
| Supported devices | [All](../../../docs/IE_DG/supported_plugins/Supported_Devices.md) |
| Other language realization | [C++](../../../inference-engine/samples/style_transfer_sample/README.md) |
## How It Works