1 // Copyright (C) 2018 Intel Corporation
3 // SPDX-License-Identifier: Apache-2.0
14 #include "ObjectDetectionProcessor.hpp"
15 #include "Processor.hpp"
16 #include "user_exception.hpp"
18 #include <samples/common.hpp>
19 #include <samples/slog.hpp>
21 using InferenceEngine::details::InferenceEngineException;
23 ObjectDetectionProcessor::ObjectDetectionProcessor(const std::string& flags_m, const std::string& flags_d,
24 const std::string& flags_i, const std::string& subdir, int flags_b,
25 double threshold, InferenceEngine::InferencePlugin plugin, CsvDumper& dumper,
26 const std::string& flags_a, const std::string& classes_list_file, PreprocessingOptions preprocessingOptions, bool scaleProposalToInputSize)
27 : Processor(flags_m, flags_d, flags_i, flags_b, plugin, dumper, "Object detection network", preprocessingOptions),
28 threshold(threshold), annotationsPath(flags_a), subdir(subdir), scaleProposalToInputSize(scaleProposalToInputSize) {
29 std::ifstream clf(classes_list_file);
31 throw UserException(1) << "Classes list file \"" << classes_list_file << "\" not found or inaccessible";
36 std::getline(clf, line, '\n');
39 istringstream lss(line);
45 classes.insert(std::pair<std::string, int>(id, class_index));
50 shared_ptr<Processor::InferenceMetrics> ObjectDetectionProcessor::Process() {
51 // Parsing PASCAL VOC2012 format
52 VOCAnnotationParser vocAnnParser;
53 slog::info << "Collecting VOC annotations from " << annotationsPath << slog::endl;
54 VOCAnnotationCollector annCollector(annotationsPath);
55 slog::info << annCollector.annotations().size() << " annotations collected" << slog::endl;
57 if (annCollector.annotations().size() == 0) {
58 ObjectDetectionInferenceMetrics emptyIM(this->threshold);
60 return std::shared_ptr<InferenceMetrics>(new ObjectDetectionInferenceMetrics(emptyIM));
63 // Getting desired results from annotations
64 std::map<std::string, ImageDescription> desiredForFiles;
66 for (auto& ann : annCollector.annotations()) {
67 std::list<DetectedObject> dobList;
68 for (auto& obj : ann.objects) {
69 DetectedObject dob(classes[obj.name], obj.bndbox.xmin, obj.bndbox.ymin, obj.bndbox.xmax, obj.bndbox.ymax, 1.0, obj.difficult != 0);
70 dobList.push_back(dob);
72 ImageDescription id(dobList);
73 desiredForFiles.insert(std::pair<std::string, ImageDescription>(ann.folder + "/" + (!subdir.empty() ? subdir + "/" : "") + ann.filename, id));
79 const int maxProposalCount = outputDims[1];
80 const int objectSize = outputDims[0];
82 for (auto & item : outInfo) {
83 DataPtr outputData = item.second;
85 throw std::logic_error("output data pointer is not valid");
88 // -----------------------------------------------------------------------------------------------------
90 // ----------------------------Do inference-------------------------------------------------------------
91 slog::info << "Starting inference" << slog::endl;
93 std::vector<VOCAnnotation> expected(batch);
95 ConsoleProgress progress(annCollector.annotations().size());
97 ObjectDetectionInferenceMetrics im(threshold);
99 vector<VOCAnnotation>::const_iterator iter = annCollector.annotations().begin();
101 std::map<std::string, ImageDescription> scaledDesiredForFiles;
103 std::string firstInputName = this->inputInfo.begin()->first;
104 auto firstInputBlob = inferRequest.GetBlob(firstInputName);
106 while (iter != annCollector.annotations().end()) {
107 std::vector<std::string> files;
110 int filesWatched = 0;
111 for (; b < batch && iter != annCollector.annotations().end(); b++, iter++, filesWatched++) {
113 string filename = iter->folder + "/" + (!subdir.empty() ? subdir + "/" : "") + iter->filename;
115 Size orig_size = decoder.insertIntoBlob(std::string(imagesPath) + "/" + filename, b, *firstInputBlob, preprocessingOptions);
116 float scale_x, scale_y;
118 scale_x = 1.0 / iter->size.width; // orig_size.width;
119 scale_y = 1.0 / iter->size.height; // orig_size.height;
121 if (scaleProposalToInputSize) {
122 scale_x *= firstInputBlob->dims()[0];
123 scale_y *= firstInputBlob->dims()[1];
126 // Scaling the desired result (taken from the annotation) to the network size
127 scaledDesiredForFiles.insert(std::pair<std::string, ImageDescription>(filename, desiredForFiles.at(filename).scale(scale_x, scale_y)));
129 files.push_back(filename);
130 } catch (const InferenceEngineException& iex) {
131 slog::warn << "Can't read file " << this->imagesPath + "/" + filename << slog::endl;
132 // Could be some non-image file in directory
138 if (files.size() == batch) {
139 InferenceEngine::StatusCode sts;
140 InferenceEngine::ResponseDesc dsc;
143 Infer(progress, filesWatched, im);
145 // Processing the inference result
146 std::map<std::string, std::list<DetectedObject>> detectedObjects = processResult(files);
148 // Calculating similarity
150 for (int b = 0; b < files.size(); b++) {
151 ImageDescription result(detectedObjects[files[b]]);
152 im.apc.consumeImage(result, scaledDesiredForFiles.at(files[b]));
158 // -----------------------------------------------------------------------------------------------------
160 // ---------------------------Postprocess output blobs--------------------------------------------------
161 slog::info << "Processing output blobs" << slog::endl;
163 return std::shared_ptr<InferenceMetrics>(new ObjectDetectionInferenceMetrics(im));
166 void ObjectDetectionProcessor::Report(const Processor::InferenceMetrics& im) {
167 const ObjectDetectionInferenceMetrics& odim = dynamic_cast<const ObjectDetectionInferenceMetrics&>(im);
168 Processor::Report(im);
170 std::map<int, double> appc = odim.apc.calculateAveragePrecisionPerClass();
172 std::cout << "Average precision per class table: " << std::endl << std::endl;
173 std::cout << "Class\tAP" << std::endl;
176 for (auto i : appc) {
177 std::cout << std::fixed << std::setprecision(3) << i.first << "\t" << i.second << std::endl;
181 std::cout << std::endl << std::fixed << std::setprecision(4) << "Mean Average Precision (mAP): " << mAP << std::endl;