blob: e057981550c8d267c31d98957ffeb8e36f351a9f [file] [log] [blame]
Éanna Ó Catháin919c14e2020-09-14 17:36:49 +01001//
2// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include "CvVideoFrameReader.hpp"
7#include "CvWindowOutput.hpp"
8#include "CvVideoFileWriter.hpp"
Éanna Ó Catháinc6ab02a2021-04-07 14:35:25 +01009#include "ObjectDetectionPipeline.hpp"
Éanna Ó Catháin919c14e2020-09-14 17:36:49 +010010#include "CmdArgsParser.hpp"
11
12#include <fstream>
13#include <iostream>
14#include <map>
15#include <random>
16
Éanna Ó Catháinc6ab02a2021-04-07 14:35:25 +010017const std::string MODEL_NAME = "--model-name";
18const std::string VIDEO_FILE_PATH = "--video-file-path";
19const std::string MODEL_FILE_PATH = "--model-file-path";
20const std::string OUTPUT_VIDEO_FILE_PATH = "--output-video-file-path";
21const std::string LABEL_PATH = "--label-path";
22const std::string PREFERRED_BACKENDS = "--preferred-backends";
23const std::string HELP = "--help";
24
25/*
26 * The accepted options for this Object detection executable
27 */
28static std::map<std::string, std::string> CMD_OPTIONS = {
29 {VIDEO_FILE_PATH, "[REQUIRED] Path to the video file to run object detection on"},
30 {MODEL_FILE_PATH, "[REQUIRED] Path to the Object Detection model to use"},
31 {LABEL_PATH, "[REQUIRED] Path to the label set for the provided model file. "
32 "Label file is should just be an ordered list, seperated by new line."},
33 {MODEL_NAME, "[REQUIRED] The name of the model being used. Accepted options: YOLO_V3_TINY, SSD_MOBILE"},
34 {OUTPUT_VIDEO_FILE_PATH, "[OPTIONAL] Path to the output video file with detections added in. "
35 "If specified will save file to disk, else displays the output to screen"},
36 {PREFERRED_BACKENDS, "[OPTIONAL] Takes the preferred backends in preference order, separated by comma."
37 " For example: CpuAcc,GpuAcc,CpuRef. Accepted options: [CpuAcc, CpuRef, GpuAcc]."
38 " Defaults to CpuAcc,CpuRef"}
39};
40
Éanna Ó Catháin919c14e2020-09-14 17:36:49 +010041/*
42 * Reads the user supplied backend preference, splits it by comma, and returns an ordered vector
43 */
44std::vector<armnn::BackendId> GetPreferredBackendList(const std::string& preferredBackends)
45{
46 std::vector<armnn::BackendId> backends;
47 std::stringstream ss(preferredBackends);
48
49 while(ss.good())
50 {
51 std::string backend;
52 std::getline( ss, backend, ',' );
53 backends.emplace_back(backend);
54 }
55 return backends;
56}
57
58/*
59 * Assigns a color to each label in the label set
60 */
Éanna Ó Catháinc6ab02a2021-04-07 14:35:25 +010061std::vector<std::tuple<std::string, common::BBoxColor>> AssignColourToLabel(const std::string& pathToLabelFile)
Éanna Ó Catháin919c14e2020-09-14 17:36:49 +010062{
63 std::ifstream in(pathToLabelFile);
Éanna Ó Catháinc6ab02a2021-04-07 14:35:25 +010064 std::vector<std::tuple<std::string, common::BBoxColor>> labels;
Éanna Ó Catháin919c14e2020-09-14 17:36:49 +010065
66 std::string str;
67 std::default_random_engine generator;
68 std::uniform_int_distribution<int> distribution(0,255);
69
70 while (std::getline(in, str))
71 {
72 if(!str.empty())
73 {
Éanna Ó Catháinc6ab02a2021-04-07 14:35:25 +010074 common::BBoxColor c{
Éanna Ó Catháin919c14e2020-09-14 17:36:49 +010075 .colorCode = std::make_tuple(distribution(generator),
76 distribution(generator),
77 distribution(generator))
78 };
79 auto bboxInfo = std::make_tuple (str, c);
80
81 labels.emplace_back(bboxInfo);
82 }
83 }
84 return labels;
85}
86
Éanna Ó Catháinc6ab02a2021-04-07 14:35:25 +010087std::tuple<std::unique_ptr<common::IFrameReader<cv::Mat>>,
88 std::unique_ptr<common::IFrameOutput<cv::Mat>>>
Éanna Ó Catháin919c14e2020-09-14 17:36:49 +010089 GetFrameSourceAndSink(const std::map<std::string, std::string>& options) {
90
Éanna Ó Catháinc6ab02a2021-04-07 14:35:25 +010091 std::unique_ptr<common::IFrameReader<cv::Mat>> readerPtr;
Éanna Ó Catháin919c14e2020-09-14 17:36:49 +010092
Éanna Ó Catháinc6ab02a2021-04-07 14:35:25 +010093 std::unique_ptr<common::CvVideoFrameReader> reader = std::make_unique<common::CvVideoFrameReader>();
Éanna Ó Catháin919c14e2020-09-14 17:36:49 +010094 reader->Init(GetSpecifiedOption(options, VIDEO_FILE_PATH));
95
96 auto enc = reader->GetSourceEncodingInt();
97 auto fps = reader->GetSourceFps();
98 auto w = reader->GetSourceWidth();
99 auto h = reader->GetSourceHeight();
100 if (!reader->ConvertToRGB())
101 {
Éanna Ó Catháinc6ab02a2021-04-07 14:35:25 +0100102 readerPtr = std::move(std::make_unique<common::CvVideoFrameReaderRgbWrapper>(std::move(reader)));
Éanna Ó Catháin919c14e2020-09-14 17:36:49 +0100103 }
104 else
105 {
106 readerPtr = std::move(reader);
107 }
108
109 if(CheckOptionSpecified(options, OUTPUT_VIDEO_FILE_PATH))
110 {
111 std::string outputVideo = GetSpecifiedOption(options, OUTPUT_VIDEO_FILE_PATH);
Éanna Ó Catháinc6ab02a2021-04-07 14:35:25 +0100112 auto writer = std::make_unique<common::CvVideoFileWriter>();
Éanna Ó Catháin919c14e2020-09-14 17:36:49 +0100113 writer->Init(outputVideo, enc, fps, w, h);
114
115 return std::make_tuple<>(std::move(readerPtr), std::move(writer));
116 }
117 else
118 {
Éanna Ó Catháinc6ab02a2021-04-07 14:35:25 +0100119 auto writer = std::make_unique<common::CvWindowOutput>();
Éanna Ó Catháin919c14e2020-09-14 17:36:49 +0100120 writer->Init("Processed Video");
121 return std::make_tuple<>(std::move(readerPtr), std::move(writer));
122 }
123}
124
125int main(int argc, char *argv[])
126{
127 std::map<std::string, std::string> options;
128
129 int result = ParseOptions(options, CMD_OPTIONS, argv, argc);
130 if (result != 0)
131 {
132 return result;
133 }
134
135 // Create the network options
Éanna Ó Catháinc6ab02a2021-04-07 14:35:25 +0100136 common::PipelineOptions pipelineOptions;
Éanna Ó Catháin919c14e2020-09-14 17:36:49 +0100137 pipelineOptions.m_ModelFilePath = GetSpecifiedOption(options, MODEL_FILE_PATH);
138 pipelineOptions.m_ModelName = GetSpecifiedOption(options, MODEL_NAME);
139
140 if(CheckOptionSpecified(options, PREFERRED_BACKENDS))
141 {
142 pipelineOptions.m_backends = GetPreferredBackendList((GetSpecifiedOption(options, PREFERRED_BACKENDS)));
143 }
144 else
145 {
146 pipelineOptions.m_backends = {"CpuAcc", "CpuRef"};
147 }
148
149 auto labels = AssignColourToLabel(GetSpecifiedOption(options, LABEL_PATH));
150
151 od::IPipelinePtr objectDetectionPipeline = od::CreatePipeline(pipelineOptions);
152
153 auto inputAndOutput = GetFrameSourceAndSink(options);
Éanna Ó Catháinc6ab02a2021-04-07 14:35:25 +0100154 std::unique_ptr<common::IFrameReader<cv::Mat>> reader = std::move(std::get<0>(inputAndOutput));
155 std::unique_ptr<common::IFrameOutput<cv::Mat>> sink = std::move(std::get<1>(inputAndOutput));
Éanna Ó Catháin919c14e2020-09-14 17:36:49 +0100156
157 if (!sink->IsReady())
158 {
159 std::cerr << "Failed to open video writer.";
160 return 1;
161 }
162
Éanna Ó Catháinc6ab02a2021-04-07 14:35:25 +0100163 common::InferenceResults<float> results;
Éanna Ó Catháin919c14e2020-09-14 17:36:49 +0100164
165 std::shared_ptr<cv::Mat> frame = reader->ReadFrame();
166
167 //pre-allocate frames
168 cv::Mat processed;
169
170 while(!reader->IsExhausted(frame))
171 {
172 objectDetectionPipeline->PreProcessing(*frame, processed);
173 objectDetectionPipeline->Inference(processed, results);
174 objectDetectionPipeline->PostProcessing(results,
175 [&frame, &labels](od::DetectedObjects detects) -> void {
176 AddInferenceOutputToFrame(detects, *frame, labels);
177 });
178
179 sink->WriteFrame(frame);
180 frame = reader->ReadFrame();
181 }
182 sink->Close();
183 return 0;
184}