6a195cba5eb579ed312403864065f7c768cb7eda
[platform/upstream/dldt.git] / inference-engine / samples / validation_app / ObjectDetectionProcessor.cpp
1 // Copyright (C) 2018 Intel Corporation
2 //
3 // SPDX-License-Identifier: Apache-2.0
4 //
5
6 #include <vector>
7 #include <string>
8 #include <map>
9 #include <list>
10 #include <algorithm>
11 #include <memory>
12 #include <utility>
13
14 #include "ObjectDetectionProcessor.hpp"
15 #include "Processor.hpp"
16 #include "user_exception.hpp"
17
18 #include <samples/common.hpp>
19 #include <samples/slog.hpp>
20
21 using InferenceEngine::details::InferenceEngineException;
22
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);
30     if (!clf) {
31         throw UserException(1) <<  "Classes list file \"" << classes_list_file << "\" not found or inaccessible";
32     }
33
34     while (!clf.eof()) {
35         std::string line;
36         std::getline(clf, line, '\n');
37
38         if (line != "") {
39             istringstream lss(line);
40             std::string id;
41             lss >> id;
42             int class_index = 0;
43             lss >> class_index;
44
45             classes.insert(std::pair<std::string, int>(id, class_index));
46         }
47     }
48 }
49
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;
56
57     if (annCollector.annotations().size() == 0) {
58         ObjectDetectionInferenceMetrics emptyIM(this->threshold);
59
60         return std::shared_ptr<InferenceMetrics>(new ObjectDetectionInferenceMetrics(emptyIM));
61     }
62
63     // Getting desired results from annotations
64     std::map<std::string, ImageDescription> desiredForFiles;
65
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);
71         }
72         ImageDescription id(dobList);
73         desiredForFiles.insert(std::pair<std::string, ImageDescription>(ann.folder + "/" + (!subdir.empty() ? subdir + "/" : "") + ann.filename, id));
74     }
75
76
77     ImageDecoder decoder;
78
79     const int maxProposalCount = outputDims[1];
80     const int objectSize = outputDims[0];
81
82     for (auto & item : outInfo) {
83         DataPtr outputData = item.second;
84         if (!outputData) {
85             throw std::logic_error("output data pointer is not valid");
86         }
87     }
88     // -----------------------------------------------------------------------------------------------------
89
90     // ----------------------------Do inference-------------------------------------------------------------
91     slog::info << "Starting inference" << slog::endl;
92
93     std::vector<VOCAnnotation> expected(batch);
94
95     ConsoleProgress progress(annCollector.annotations().size());
96
97     ObjectDetectionInferenceMetrics im(threshold);
98
99     vector<VOCAnnotation>::const_iterator iter = annCollector.annotations().begin();
100
101     std::map<std::string, ImageDescription> scaledDesiredForFiles;
102
103     std::string firstInputName = this->inputInfo.begin()->first;
104     auto firstInputBlob = inferRequest.GetBlob(firstInputName);
105
106     while (iter != annCollector.annotations().end()) {
107         std::vector<std::string> files;
108         int b = 0;
109
110         int filesWatched = 0;
111         for (; b < batch && iter != annCollector.annotations().end(); b++, iter++, filesWatched++) {
112             expected[b] = *iter;
113             string filename = iter->folder + "/" + (!subdir.empty() ? subdir + "/" : "") + iter->filename;
114             try {
115                 Size orig_size = decoder.insertIntoBlob(std::string(imagesPath) + "/" + filename, b, *firstInputBlob, preprocessingOptions);
116                 float scale_x, scale_y;
117
118                 scale_x = 1.0 / iter->size.width;  // orig_size.width;
119                 scale_y = 1.0 / iter->size.height;  // orig_size.height;
120
121                 if (scaleProposalToInputSize) {
122                     scale_x *= firstInputBlob->dims()[0];
123                     scale_y *= firstInputBlob->dims()[1];
124                 }
125
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)));
128
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
133                 b--;
134                 continue;
135             }
136         }
137
138         if (files.size() == batch) {
139             InferenceEngine::StatusCode sts;
140             InferenceEngine::ResponseDesc dsc;
141
142             // Infer model
143             Infer(progress, filesWatched, im);
144
145             // Processing the inference result
146             std::map<std::string, std::list<DetectedObject>> detectedObjects = processResult(files);
147
148             // Calculating similarity
149             //
150             for (int b = 0; b < files.size(); b++) {
151                 ImageDescription result(detectedObjects[files[b]]);
152                 im.apc.consumeImage(result, scaledDesiredForFiles.at(files[b]));
153             }
154         }
155     }
156     progress.finish();
157
158     // -----------------------------------------------------------------------------------------------------
159
160     // ---------------------------Postprocess output blobs--------------------------------------------------
161     slog::info << "Processing output blobs" << slog::endl;
162
163     return std::shared_ptr<InferenceMetrics>(new ObjectDetectionInferenceMetrics(im));
164 }
165
166 void ObjectDetectionProcessor::Report(const Processor::InferenceMetrics& im) {
167     const ObjectDetectionInferenceMetrics& odim = dynamic_cast<const ObjectDetectionInferenceMetrics&>(im);
168     Processor::Report(im);
169     if (im.nRuns > 0) {
170         std::map<int, double> appc = odim.apc.calculateAveragePrecisionPerClass();
171
172         std::cout << "Average precision per class table: " << std::endl << std::endl;
173         std::cout << "Class\tAP" << std::endl;
174
175         double mAP = 0;
176         for (auto i : appc) {
177             std::cout << std::fixed << std::setprecision(3) << i.first << "\t" << i.second << std::endl;
178             mAP += i.second;
179         }
180         mAP /= appc.size();
181         std::cout << std::endl << std::fixed << std::setprecision(4) << "Mean Average Precision (mAP): " << mAP << std::endl;
182     }
183 }