1
- // Copyright (C) 2018-2022 Intel Corporation
1
+ // Copyright (C) 2018-2019 Intel Corporation
2
2
// SPDX-License-Identifier: Apache-2.0
3
3
//
4
4
7
7
* @file mask_rcnn_demo/main.cpp
8
8
* @example mask_rcnn_demo/main.cpp
9
9
*/
10
- #include < algorithm>
11
- #include < iomanip>
10
+ #include < gflags/gflags.h>
12
11
#include < iostream>
13
12
#include < memory>
14
13
#include < map>
14
+ #include < algorithm>
15
15
#include < string>
16
16
#include < vector>
17
+ #include < iomanip>
17
18
18
- #include " openvino/openvino .hpp"
19
+ #include < inference_engine .hpp>
19
20
20
- #include " gflags/gflags.h"
21
- #include " utils/args_helper.hpp"
22
- #include " utils/ocv_common.hpp"
23
- #include " utils/performance_metrics.hpp"
24
- #include " utils/slog.hpp"
21
+ #include < utils/args_helper.hpp>
22
+ #include < utils/ocv_common.hpp>
23
+ #include < utils/performance_metrics.hpp>
24
+ #include < utils/slog.hpp>
25
25
26
26
#include " mask_rcnn_demo.h"
27
27
28
- using namespace ov ::preprocess;
29
-
30
- bool ParseAndCheckCommandLine (int argc, char * argv[]) {
31
- // Parsing and validation of input args
28
+ bool ParseAndCheckCommandLine (int argc, char *argv[]) {
29
+ // ---------------------------Parsing and validation of input args--------------------------------------
32
30
gflags::ParseCommandLineNonHelpFlags (&argc, &argv, true );
33
31
if (FLAGS_h) {
34
32
showUsage ();
@@ -47,77 +45,84 @@ bool ParseAndCheckCommandLine(int argc, char* argv[]) {
47
45
return true ;
48
46
}
49
47
50
- int main (int argc, char * argv[]) {
48
+ int main (int argc, char * argv[]) {
51
49
try {
52
50
PerformanceMetrics metrics;
53
51
54
- // Parsing and validation of input args
52
+ // ------------------------------ Parsing and validation of input args ---------------------------------
55
53
if (!ParseAndCheckCommandLine (argc, argv)) {
56
54
return 0 ;
57
55
}
58
56
59
- // This vector stores paths to the processed images
57
+ /* * This vector stores paths to the processed images * */
60
58
std::vector<std::string> imagePaths;
61
59
parseInputFilesArguments (imagePaths);
62
- if (imagePaths.empty ())
63
- throw std::logic_error (" No suitable images were found" );
60
+ if (imagePaths.empty ()) throw std::logic_error (" No suitable images were found" );
61
+ // -----------------------------------------------------------------------------------------------------
62
+
63
+ // ---------------------Load inference engine------------------------------------------------
64
+ slog::info << *InferenceEngine::GetInferenceEngineVersion () << slog::endl;
65
+ InferenceEngine::Core ie;
64
66
65
- // Load inference engine
66
- slog::info << ov::get_openvino_version () << slog::endl;
67
- ov::Core core;
67
+ if (!FLAGS_l.empty ()) {
68
+ // CPU(MKLDNN) extensions are loaded as a shared library and passed as a pointer to base extension
69
+ auto extension_ptr = std::make_shared<InferenceEngine::Extension>(FLAGS_l);
70
+ ie.AddExtension (extension_ptr, " CPU" );
71
+ }
72
+ if (!FLAGS_c.empty ()) {
73
+ // clDNN Extensions are loaded from an .xml description and OpenCL kernel files
74
+ ie.SetConfig ({{InferenceEngine::PluginConfigParams::KEY_CONFIG_FILE, FLAGS_c}}, " CPU" );
75
+ }
68
76
69
- // Load network (Generated xml/bin files)
77
+ // -----------------------------------------------------------------------------------------------------
70
78
71
- // Read network model
72
- slog::info << " Reading model: " << FLAGS_m << slog::endl;
73
- std::shared_ptr<ov::Model> model = core.read_model (FLAGS_m);
74
- logBasicModelInfo (model);
79
+ // --------------------Load network (Generated xml/bin files)-------------------------------------------
75
80
76
- // Prepare input blobs
81
+ /* * Read network model **/
82
+ auto network = ie.ReadNetwork (FLAGS_m);
77
83
78
- // Taking information about all topology inputs
79
- ov::OutputVector inputs = model-> inputs ( );
80
- ov::OutputVector outputs = model-> outputs ();
84
+ // add DetectionOutput layer as output so we can get detected boxes and their probabilities
85
+ network. addOutput (FLAGS_detection_output_name. c_str (), 0 );
86
+ // -----------------------------------------------------------------------------------------------------
81
87
82
- if (inputs.size () != 2 || outputs.size () != 2 )
83
- throw std::logic_error (" Expected network with 2 inputs and 2 outputs" );
88
+ // -----------------------------Prepare input blobs-----------------------------------------------------
84
89
85
- size_t modelBatchSize = 0 ;
86
- size_t modelInputHeight = 0 ;
87
- size_t modelInputWidth = 0 ;
90
+ /* * Taking information about all topology inputs **/
91
+ InferenceEngine::InputsDataMap inputInfo (network.getInputsInfo ());
88
92
89
- const ov::Layout layout_nchw{ " NCHW " } ;
93
+ std::string imageInputName ;
90
94
91
- // network dimensions for image input
92
- auto it = std::find_if (inputs.begin (), inputs.end (), [](const ov::Output<ov::Node>& input) {return input.get_shape ().size () == 4 ;});
93
- if (it != inputs.end ()) {
94
- // ov::set_batch() should know input layout
95
- model->get_parameters ()[it->get_index ()]->set_layout (" NCHW" );
96
- modelBatchSize = it->get_shape ()[ov::layout::batch_idx (layout_nchw)];
97
- modelInputHeight = it->get_shape ()[ov::layout::height_idx (layout_nchw)];
98
- modelInputWidth = it->get_shape ()[ov::layout::width_idx (layout_nchw)];
99
- } else {
100
- throw std::logic_error (" Couldn't find model image input" );
95
+ for (const auto & inputInfoItem : inputInfo) {
96
+ if (inputInfoItem.second ->getTensorDesc ().getDims ().size () == 4 ) { // first input contains images
97
+ imageInputName = inputInfoItem.first ;
98
+ inputInfoItem.second ->setPrecision (InferenceEngine::Precision::U8);
99
+ } else if (inputInfoItem.second ->getTensorDesc ().getDims ().size () == 2 ) { // second input contains image info
100
+ inputInfoItem.second ->setPrecision (InferenceEngine::Precision::FP32);
101
+ } else {
102
+ throw std::logic_error (" Unsupported input shape with size = " + std::to_string (inputInfoItem.second ->getTensorDesc ().getDims ().size ()));
103
+ }
101
104
}
102
105
103
- // Collect images
106
+ /* * network dimensions for image input **/
107
+ const InferenceEngine::TensorDesc& inputDesc = inputInfo[imageInputName]->getTensorDesc ();
108
+ IE_ASSERT (inputDesc.getDims ().size () == 4 );
109
+ size_t netBatchSize = getTensorBatch (inputDesc);
110
+ size_t netInputHeight = getTensorHeight (inputDesc);
111
+ size_t netInputWidth = getTensorWidth (inputDesc);
112
+
113
+ /* * Collect images **/
104
114
std::vector<cv::Mat> images;
105
115
106
- if (modelBatchSize > imagePaths.size ()) {
107
- slog::warn << " Model batch size is greater than number of images (" << imagePaths.size () <<
116
+ if (netBatchSize > imagePaths.size ()) {
117
+ slog::warn << " Network batch size is greater than number of images (" << imagePaths.size () <<
108
118
" ), some input files will be duplicated" << slog::endl;
109
- } else if (modelBatchSize < imagePaths.size ()) {
110
- modelBatchSize = imagePaths.size ();
111
- slog::warn << " Model batch size is less than number of images (" << imagePaths.size () <<
112
- " ), model will be reshaped" << slog::endl;
119
+ } else if (netBatchSize < imagePaths.size ()) {
120
+ slog::warn << " Network batch size is less than number of images (" << imagePaths.size () <<
121
+ " ), some input files will be ignored" << slog::endl;
113
122
}
114
123
115
- // set batch size
116
- ov::set_batch (model, modelBatchSize);
117
- slog::info << " \t Batch size is set to " << modelBatchSize << slog::endl;
118
-
119
124
auto startTime = std::chrono::steady_clock::now ();
120
- for (size_t i = 0 , inputIndex = 0 ; i < modelBatchSize ; i++, inputIndex++) {
125
+ for (size_t i = 0 , inputIndex = 0 ; i < netBatchSize ; i++, inputIndex++) {
121
126
if (inputIndex >= imagePaths.size ()) {
122
127
inputIndex = 0 ;
123
128
}
@@ -131,70 +136,82 @@ int main(int argc, char* argv[]) {
131
136
132
137
images.push_back (image);
133
138
}
134
- if (images.empty ())
135
- throw std::logic_error (" Valid input images were not found!" );
139
+ if (images.empty ()) throw std::logic_error (" Valid input images were not found!" );
140
+
141
+ // -----------------------------------------------------------------------------------------------------
142
+
143
+ // ---------------------------Prepare output blobs------------------------------------------------------
144
+ InferenceEngine::OutputsDataMap outputInfo (network.getOutputsInfo ());
145
+ for (auto & item : outputInfo) {
146
+ item.second ->setPrecision (InferenceEngine::Precision::FP32);
147
+ }
148
+
149
+ // -----------------------------------------------------------------------------------------------------
136
150
137
- // Load model to the device
138
- ov::CompiledModel compiled_model = core.compile_model (model, FLAGS_d);
139
- logCompiledModelInfo (compiled_model, FLAGS_m, FLAGS_d);
151
+ // -------------------------Load model to the device----------------------------------------------------
152
+ auto executableNetwork = ie.LoadNetwork (network, FLAGS_d);
153
+ logExecNetworkInfo (executableNetwork, FLAGS_m, FLAGS_d);
154
+ slog::info << " \t Batch size is set to " << netBatchSize << slog::endl;
140
155
141
- // Create Infer Request
142
- ov::InferRequest infer_request = compiled_model. create_infer_request ();
156
+ // ------------------------- Create Infer Request--------------------------------------------------------
157
+ auto infer_request = executableNetwork. CreateInferRequest ();
143
158
144
- // Set input data
145
- // Iterate over all the input blobs
146
- for (size_t idx = 0 ; idx < inputs.size (); idx++) {
147
- ov::Tensor tensor = infer_request.get_input_tensor (idx);
148
- ov::Shape shape = tensor.get_shape ();
159
+ // -----------------------------------------------------------------------------------------------------
149
160
150
- if (shape.size () == 4 ) {
161
+ // -------------------------------Set input data--------------------------------------------------------
162
+ /* * Iterate over all the input blobs **/
163
+ for (const auto & inputInfoItem : inputInfo) {
164
+ InferenceEngine::Blob::Ptr input = infer_request.GetBlob (inputInfoItem.first );
165
+
166
+ /* * Fill first input tensor with images. First b channel, then g and r channels **/
167
+ if (inputInfoItem.second ->getTensorDesc ().getDims ().size () == 4 ) {
168
+ /* * Iterate over all input images **/
151
169
for (size_t image_id = 0 ; image_id < images.size (); ++image_id)
152
- matToTensor (images[image_id], tensor , image_id);
170
+ matToBlob (images[image_id], input , image_id);
153
171
}
154
172
155
- if (shape.size () == 2 ) {
156
- float * data = tensor.data <float >();
157
- data[0 ] = static_cast <float >(modelInputHeight); // height
158
- data[1 ] = static_cast <float >(modelInputWidth); // width
173
+ /* * Fill second input tensor with image info **/
174
+ if (inputInfoItem.second ->getTensorDesc ().getDims ().size () == 2 ) {
175
+ InferenceEngine::LockedMemory<void > inputMapped =
176
+ InferenceEngine::as<InferenceEngine::MemoryBlob>(input)->wmap ();
177
+ auto data = inputMapped.as <float *>();
178
+ data[0 ] = static_cast <float >(netInputHeight); // height
179
+ data[1 ] = static_cast <float >(netInputWidth); // width
159
180
data[2 ] = 1 ;
160
181
}
161
182
}
162
183
163
- // Do inference
164
- infer_request.infer ();
184
+ // -----------------------------------------------------------------------------------------------------
165
185
166
- // Postprocess output blobs
167
- float * do_data = nullptr ;
168
- float * masks_data = nullptr ;
169
186
170
- size_t BOX_DESCRIPTION_SIZE = 0 ;
187
+ // ----------------------------Do inference-------------------------------------------------------------
188
+ infer_request.Infer ();
189
+ // -----------------------------------------------------------------------------------------------------
171
190
172
- size_t BOXES = 0 ;
173
- size_t C = 0 ;
174
- size_t H = 0 ;
175
- size_t W = 0 ;
191
+ // ---------------------------Postprocess output blobs--------------------------------------------------
192
+ const auto do_blob = infer_request.GetBlob (FLAGS_detection_output_name.c_str ());
193
+ InferenceEngine::LockedMemory<const void > doBlobMapped =
194
+ InferenceEngine::as<InferenceEngine::MemoryBlob>(do_blob)->rmap ();
195
+ const auto do_data = doBlobMapped.as <float *>();
176
196
177
- for (size_t idx = 0 ; idx < outputs.size (); idx++) {
178
- ov::Tensor tensor = infer_request.get_output_tensor (idx);
179
- ov::Shape shape = tensor.get_shape ();
180
- size_t dims = shape.size ();
181
- if (dims == 2 ) {
182
- do_data = tensor.data <float >();
183
- // amount of elements in each detected box description (batch, label, prob, x1, y1, x2, y2)
184
- BOX_DESCRIPTION_SIZE = shape[1 ];
185
- }
186
- if (dims == 4 ) {
187
- masks_data = tensor.data <float >();
188
- BOXES = shape[ov::layout::batch_idx (layout_nchw)];
189
- C = shape[ov::layout::channels_idx (layout_nchw)];
190
- H = shape[ov::layout::height_idx (layout_nchw)];
191
- W = shape[ov::layout::width_idx (layout_nchw)];
192
- }
193
- }
197
+ const auto masks_blob = infer_request.GetBlob (FLAGS_masks_name.c_str ());
198
+ InferenceEngine::LockedMemory<const void > masksBlobMapped =
199
+ InferenceEngine::as<InferenceEngine::MemoryBlob>(masks_blob)->rmap ();
200
+ const auto masks_data = masksBlobMapped.as <float *>();
194
201
195
202
const float PROBABILITY_THRESHOLD = 0 .2f ;
196
- // threshold used to determine whether mask pixel corresponds to object or to background
197
- const float MASK_THRESHOLD = 0 .5f ;
203
+ const float MASK_THRESHOLD = 0 .5f ; // threshold used to determine whether mask pixel corresponds to object or to background
204
+ // amount of elements in each detected box description (batch, label, prob, x1, y1, x2, y2)
205
+ IE_ASSERT (do_blob->getTensorDesc ().getDims ().size () == 2 );
206
+ size_t BOX_DESCRIPTION_SIZE = do_blob->getTensorDesc ().getDims ().back ();
207
+
208
+ const InferenceEngine::TensorDesc& masksDesc = masks_blob->getTensorDesc ();
209
+ IE_ASSERT (masksDesc.getDims ().size () == 4 );
210
+ size_t BOXES = getTensorBatch (masksDesc);
211
+ size_t C = getTensorChannels (masksDesc);
212
+ size_t H = getTensorHeight (masksDesc);
213
+ size_t W = getTensorWidth (masksDesc);
214
+
198
215
199
216
size_t box_stride = W * H * C;
200
217
@@ -205,28 +222,22 @@ int main(int argc, char* argv[]) {
205
222
output_images.push_back (img.clone ());
206
223
}
207
224
208
- // Iterating over all boxes
225
+ /* * Iterating over all boxes * */
209
226
for (size_t box = 0 ; box < BOXES; ++box) {
210
227
float * box_info = do_data + box * BOX_DESCRIPTION_SIZE;
211
228
auto batch = static_cast <int >(box_info[0 ]);
212
-
213
229
if (batch < 0 )
214
230
break ;
215
- if (batch >= static_cast <int >(modelBatchSize ))
231
+ if (batch >= static_cast <int >(netBatchSize ))
216
232
throw std::logic_error (" Invalid batch ID within detection output box" );
217
-
218
233
float prob = box_info[2 ];
219
-
220
234
float x1 = std::min (std::max (0 .0f , box_info[3 ] * images[batch].cols ), static_cast <float >(images[batch].cols ));
221
235
float y1 = std::min (std::max (0 .0f , box_info[4 ] * images[batch].rows ), static_cast <float >(images[batch].rows ));
222
236
float x2 = std::min (std::max (0 .0f , box_info[5 ] * images[batch].cols ), static_cast <float >(images[batch].cols ));
223
237
float y2 = std::min (std::max (0 .0f , box_info[6 ] * images[batch].rows ), static_cast <float >(images[batch].rows ));
224
-
225
238
int box_width = static_cast <int >(x2 - x1);
226
239
int box_height = static_cast <int >(y2 - y1);
227
-
228
- auto class_id = static_cast <size_t >(box_info[1 ] + 1e-6 );
229
-
240
+ auto class_id = static_cast <size_t >(box_info[1 ] + 1e-6f );
230
241
if (prob > PROBABILITY_THRESHOLD && box_width > 0 && box_height > 0 ) {
231
242
size_t color_index = class_color.emplace (class_id, class_color.size ()).first ->second ;
232
243
auto & color = CITYSCAPES_COLORS[color_index % arraySize (CITYSCAPES_COLORS)];
@@ -246,13 +257,11 @@ int main(int argc, char* argv[]) {
246
257
cv::Scalar (color.blue (), color.green (), color.red ()));
247
258
roi_input_img.copyTo (uchar_resized_mask, resized_mask_mat <= MASK_THRESHOLD);
248
259
249
- cv::addWeighted (uchar_resized_mask, alpha, roi_input_img, 1.0 - alpha, 0 .0f , roi_input_img);
260
+ cv::addWeighted (uchar_resized_mask, alpha, roi_input_img, 1 .0f - alpha, 0 .0f , roi_input_img);
250
261
cv::rectangle (output_images[batch], roi, cv::Scalar (0 , 0 , 1 ), 1 );
251
262
}
252
263
}
253
-
254
264
metrics.update (startTime);
255
-
256
265
for (size_t i = 0 ; i < output_images.size (); i++) {
257
266
std::string imgName = " out" + std::to_string (i) + " .png" ;
258
267
cv::imwrite (imgName, output_images[i]);
0 commit comments