aboutsummaryrefslogtreecommitdiff
path: root/samples/common/include
diff options
context:
space:
mode:
Diffstat (limited to 'samples/common/include')
-rw-r--r--samples/common/include/ArmnnUtils/ArmnnNetworkExecutor.hpp214
-rw-r--r--samples/common/include/CVUtils/CvVideoFileWriter.hpp61
-rw-r--r--samples/common/include/CVUtils/CvVideoFrameReader.hpp108
-rw-r--r--samples/common/include/CVUtils/CvWindowOutput.hpp53
-rw-r--r--samples/common/include/CVUtils/IFrameOutput.hpp48
-rw-r--r--samples/common/include/CVUtils/IFrameReader.hpp45
-rw-r--r--samples/common/include/Utils/CmdArgsParser.hpp25
-rw-r--r--samples/common/include/Utils/Types.hpp54
8 files changed, 608 insertions, 0 deletions
diff --git a/samples/common/include/ArmnnUtils/ArmnnNetworkExecutor.hpp b/samples/common/include/ArmnnUtils/ArmnnNetworkExecutor.hpp
new file mode 100644
index 0000000000..96cc1d0184
--- /dev/null
+++ b/samples/common/include/ArmnnUtils/ArmnnNetworkExecutor.hpp
@@ -0,0 +1,214 @@
+//
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include "Types.hpp"
+
+#include "armnn/ArmNN.hpp"
+#include "armnnTfLiteParser/ITfLiteParser.hpp"
+#include "armnnUtils/DataLayoutIndexed.hpp"
+#include <armnn/Logging.hpp>
+
+#include <string>
+#include <vector>
+
+namespace common
+{
+/**
+* @brief Used to load in a network through ArmNN and run inference on it against a given backend.
+*
+*/
+template <class Tout>
+class ArmnnNetworkExecutor
+{
+private:
+ armnn::IRuntimePtr m_Runtime;
+ armnn::NetworkId m_NetId{};
+ mutable InferenceResults<Tout> m_OutputBuffer;
+ armnn::InputTensors m_InputTensors;
+ armnn::OutputTensors m_OutputTensors;
+ std::vector<armnnTfLiteParser::BindingPointInfo> m_outputBindingInfo;
+
+ std::vector<std::string> m_outputLayerNamesList;
+
+ armnnTfLiteParser::BindingPointInfo m_inputBindingInfo;
+
+ void PrepareTensors(const void* inputData, const size_t dataBytes);
+
+ template <typename Enumeration>
+ auto log_as_int(Enumeration value)
+ -> typename std::underlying_type<Enumeration>::type
+ {
+ return static_cast<typename std::underlying_type<Enumeration>::type>(value);
+ }
+
+public:
+ ArmnnNetworkExecutor() = delete;
+
+ /**
+ * @brief Initializes the network with the given input data. Parsed through TfLiteParser and optimized for a
+ * given backend.
+ *
+ * Note that the output layers names order in m_outputLayerNamesList affects the order of the feature vectors
+ * in output of the Run method.
+ *
+ * * @param[in] modelPath - Relative path to the model file
+ * * @param[in] backends - The list of preferred backends to run inference on
+ */
+ ArmnnNetworkExecutor(std::string& modelPath,
+ std::vector<armnn::BackendId>& backends);
+
+ /**
+ * @brief Returns the aspect ratio of the associated model in the order of width, height.
+ */
+ Size GetImageAspectRatio();
+
+ armnn::DataType GetInputDataType() const;
+
+ float GetQuantizationScale();
+
+ int GetQuantizationOffset();
+
+ /**
+ * @brief Runs inference on the provided input data, and stores the results in the provided InferenceResults object.
+ *
+ * @param[in] inputData - input frame data
+ * @param[in] dataBytes - input data size in bytes
+ * @param[out] results - Vector of DetectionResult objects used to store the output result.
+ */
+ bool Run(const void* inputData, const size_t dataBytes, common::InferenceResults<Tout>& outResults);
+
+};
+
+template <class Tout>
+ArmnnNetworkExecutor<Tout>::ArmnnNetworkExecutor(std::string& modelPath,
+ std::vector<armnn::BackendId>& preferredBackends)
+ : m_Runtime(armnn::IRuntime::Create(armnn::IRuntime::CreationOptions()))
+{
+ // Import the TensorFlow lite model.
+ armnnTfLiteParser::ITfLiteParserPtr parser = armnnTfLiteParser::ITfLiteParser::Create();
+ armnn::INetworkPtr network = parser->CreateNetworkFromBinaryFile(modelPath.c_str());
+
+ std::vector<std::string> inputNames = parser->GetSubgraphInputTensorNames(0);
+
+ m_inputBindingInfo = parser->GetNetworkInputBindingInfo(0, inputNames[0]);
+
+ m_outputLayerNamesList = parser->GetSubgraphOutputTensorNames(0);
+
+ std::vector<armnn::BindingPointInfo> outputBindings;
+ for(const std::string& name : m_outputLayerNamesList)
+ {
+ m_outputBindingInfo.push_back(std::move(parser->GetNetworkOutputBindingInfo(0, name)));
+ }
+ std::vector<std::string> errorMessages;
+ // optimize the network.
+ armnn::IOptimizedNetworkPtr optNet = Optimize(*network,
+ preferredBackends,
+ m_Runtime->GetDeviceSpec(),
+ armnn::OptimizerOptions(),
+ armnn::Optional<std::vector<std::string>&>(errorMessages));
+
+ if (!optNet)
+ {
+ const std::string errorMessage{"ArmnnNetworkExecutor: Failed to optimize network"};
+ ARMNN_LOG(error) << errorMessage;
+ throw armnn::Exception(errorMessage);
+ }
+
+ // Load the optimized network onto the m_Runtime device
+ std::string errorMessage;
+ if (armnn::Status::Success != m_Runtime->LoadNetwork(m_NetId, std::move(optNet), errorMessage))
+ {
+ ARMNN_LOG(error) << errorMessage;
+ throw armnn::Exception(errorMessage);
+ }
+
+ //pre-allocate memory for output (the size of it never changes)
+ for (int it = 0; it < m_outputLayerNamesList.size(); ++it)
+ {
+ const armnn::DataType dataType = m_outputBindingInfo[it].second.GetDataType();
+ const armnn::TensorShape& tensorShape = m_outputBindingInfo[it].second.GetShape();
+
+ std::vector<Tout> oneLayerOutResult;
+ oneLayerOutResult.resize(tensorShape.GetNumElements(), 0);
+ m_OutputBuffer.emplace_back(oneLayerOutResult);
+
+ // Make ArmNN output tensors
+ m_OutputTensors.reserve(m_OutputBuffer.size());
+ for (size_t it = 0; it < m_OutputBuffer.size(); ++it)
+ {
+ m_OutputTensors.emplace_back(std::make_pair(
+ m_outputBindingInfo[it].first,
+ armnn::Tensor(m_outputBindingInfo[it].second,
+ m_OutputBuffer.at(it).data())
+ ));
+ }
+ }
+
+}
+
+template <class Tout>
+armnn::DataType ArmnnNetworkExecutor<Tout>::GetInputDataType() const
+{
+ return m_inputBindingInfo.second.GetDataType();
+}
+
+template <class Tout>
+void ArmnnNetworkExecutor<Tout>::PrepareTensors(const void* inputData, const size_t dataBytes)
+{
+ assert(m_inputBindingInfo.second.GetNumBytes() >= dataBytes);
+ m_InputTensors.clear();
+ m_InputTensors = {{ m_inputBindingInfo.first, armnn::ConstTensor(m_inputBindingInfo.second, inputData)}};
+}
+
+template <class Tout>
+bool ArmnnNetworkExecutor<Tout>::Run(const void* inputData, const size_t dataBytes, InferenceResults<Tout>& outResults)
+{
+ /* Prepare tensors if they are not ready */
+ ARMNN_LOG(debug) << "Preparing tensors...";
+ this->PrepareTensors(inputData, dataBytes);
+ ARMNN_LOG(trace) << "Running inference...";
+
+ armnn::Status ret = m_Runtime->EnqueueWorkload(m_NetId, m_InputTensors, m_OutputTensors);
+
+ std::stringstream inferenceFinished;
+ inferenceFinished << "Inference finished with code {" << log_as_int(ret) << "}\n";
+
+ ARMNN_LOG(trace) << inferenceFinished.str();
+
+ if (ret == armnn::Status::Failure)
+ {
+ ARMNN_LOG(error) << "Failed to perform inference.";
+ }
+
+ outResults.reserve(m_outputLayerNamesList.size());
+ outResults = m_OutputBuffer;
+
+ return (armnn::Status::Success == ret);
+}
+
+template <class Tout>
+float ArmnnNetworkExecutor<Tout>::GetQuantizationScale()
+{
+ return this->m_inputBindingInfo.second.GetQuantizationScale();
+}
+
+template <class Tout>
+int ArmnnNetworkExecutor<Tout>::GetQuantizationOffset()
+{
+ return this->m_inputBindingInfo.second.GetQuantizationOffset();
+}
+
+template <class Tout>
+Size ArmnnNetworkExecutor<Tout>::GetImageAspectRatio()
+{
+ const auto shape = m_inputBindingInfo.second.GetShape();
+ assert(shape.GetNumDimensions() == 4);
+ armnnUtils::DataLayoutIndexed nhwc(armnn::DataLayout::NHWC);
+ return Size(shape[nhwc.GetWidthIndex()],
+ shape[nhwc.GetHeightIndex()]);
+}
+}// namespace common \ No newline at end of file
diff --git a/samples/common/include/CVUtils/CvVideoFileWriter.hpp b/samples/common/include/CVUtils/CvVideoFileWriter.hpp
new file mode 100644
index 0000000000..30348f09cc
--- /dev/null
+++ b/samples/common/include/CVUtils/CvVideoFileWriter.hpp
@@ -0,0 +1,61 @@
+//
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include "IFrameOutput.hpp"
+#include <opencv2/opencv.hpp>
+
+namespace common
+{
+
+class CvVideoFileWriter : public IFrameOutput<cv::Mat> {
+public:
+ /**
+ * @brief Default constructor.
+ *
+ * Underlying open cv video writer object will be instantiated.
+ */
+ CvVideoFileWriter() = default;
+
+ ~CvVideoFileWriter() override = default;
+
+ /**
+ * @brief Initialises video file writer.
+ *
+ * Opens opencv writer with given params. FFMPEG backend is used.
+ *
+ * @param outputVideo path to the video file.
+ * @param encoding cv::CAP_PROP_FOURCC code.
+ * @param fps target frame rate.
+ * @param width target frame width.
+ * @param height target frame height.
+ *
+ */
+ void Init(const std::string& outputVideo, int encoding, double fps, int width, int height);
+
+ /**
+ * Writes frame to the file using opencv writer.
+ *
+ * @param frame data to write.
+ */
+ void WriteFrame(std::shared_ptr<cv::Mat>& frame) override;
+
+ /**
+ * Releases opencv writer.
+ */
+ void Close() override;
+
+ /**
+ * Checks if opencv writer was successfully opened.
+ * @return true is underlying writer is ready to be used, false otherwise.
+ */
+ bool IsReady() const override;
+
+private:
+ cv::VideoWriter m_cvWriter{};
+ bool m_ready = false;
+};
+}// namespace common \ No newline at end of file
diff --git a/samples/common/include/CVUtils/CvVideoFrameReader.hpp b/samples/common/include/CVUtils/CvVideoFrameReader.hpp
new file mode 100644
index 0000000000..96d94f4079
--- /dev/null
+++ b/samples/common/include/CVUtils/CvVideoFrameReader.hpp
@@ -0,0 +1,108 @@
+//
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+
+#include "IFrameReader.hpp"
+#include <opencv2/opencv.hpp>
+
+namespace common
+{
+
+class CvVideoFrameReader :
+ public IFrameReader<cv::Mat>
+{
+public:
+ /**
+ * @brief Default constructor.
+ *
+ * Underlying open cv video capture object will be instantiated.
+ */
+ CvVideoFrameReader() = default;
+
+ ~CvVideoFrameReader() override = default;
+
+ /**
+ *@brief Initialises reader to capture frames from video file.
+ *
+ * @param source path to the video file or image sequence.
+ *
+ * @throws std::runtime_error if init failed
+ */
+ void Init(const std::string& source);
+
+ std::shared_ptr <cv::Mat> ReadFrame() override;
+
+ bool IsExhausted(const std::shared_ptr <cv::Mat>& frame) const override;
+
+ /**
+ * Returns effective video frame width supported by the source/set by the user.
+ * Must be called after Init method.
+ * @return frame width
+ */
+ int GetSourceWidth() const;
+
+ /**
+ * Returns effective video frame height supported by the source/set by the user.
+ * Must be called after Init method.
+ * @return frame height
+ */
+ int GetSourceHeight() const;
+
+ /**
+ * Returns effective fps value supported by the source/set by the user.
+ * @return fps value
+ */
+ double GetSourceFps() const;
+
+ /**
+ * Will query OpenCV to convert images to RGB
+ * Copy is actually default behaviour, but the set function needs to be called
+ * in order to know whether OpenCV supports conversion from our source format.
+ * @return boolean,
+ * true: OpenCV returns RGB
+ * false: OpenCV returns the fourcc format from GetSourceEncoding
+ */
+ bool ConvertToRGB();
+
+ /**
+ * Returns 4-character code of codec.
+ * @return codec name
+ */
+ std::string GetSourceEncoding() const;
+
+ /**
+ * Get the fourcc int from its string name.
+ * @return codec int
+ */
+ int GetSourceEncodingInt() const;
+
+ int GetFrameCount() const;
+
+private:
+ cv::VideoCapture m_capture;
+
+ void CheckIsOpen(const std::string& source);
+};
+
+class CvVideoFrameReaderRgbWrapper :
+ public IFrameReader<cv::Mat>
+{
+public:
+ CvVideoFrameReaderRgbWrapper() = delete;
+ CvVideoFrameReaderRgbWrapper(const CvVideoFrameReaderRgbWrapper& o) = delete;
+ CvVideoFrameReaderRgbWrapper(CvVideoFrameReaderRgbWrapper&& o) = delete;
+
+ CvVideoFrameReaderRgbWrapper(std::unique_ptr<common::CvVideoFrameReader> reader);
+
+ std::shared_ptr<cv::Mat> ReadFrame() override;
+
+ bool IsExhausted(const std::shared_ptr<cv::Mat>& frame) const override;
+
+private:
+ std::unique_ptr<common::CvVideoFrameReader> m_reader;
+};
+
+}// namespace common \ No newline at end of file
diff --git a/samples/common/include/CVUtils/CvWindowOutput.hpp b/samples/common/include/CVUtils/CvWindowOutput.hpp
new file mode 100644
index 0000000000..4b9ae3b743
--- /dev/null
+++ b/samples/common/include/CVUtils/CvWindowOutput.hpp
@@ -0,0 +1,53 @@
+//
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include "IFrameOutput.hpp"
+#include <opencv2/opencv.hpp>
+
+namespace common
+{
+
+class CvWindowOutput : public IFrameOutput<cv::Mat> {
+public:
+
+ CvWindowOutput() = default;
+
+ ~CvWindowOutput() override = default;
+
+ /**
+ * @brief Creates a named window.
+ *
+ * Uses opencv to create a window with given name.
+ *
+ * @param windowName opencv window name.
+ *
+ */
+ void Init(const std::string& windowName);
+
+ /**
+ * Writes frame to the window.
+ *
+ * @param frame data to write.
+ */
+ void WriteFrame(std::shared_ptr<cv::Mat>& frame) override;
+
+ /**
+ * Releases all windows.
+ */
+ void Close() override;
+
+ /**
+ * Always true.
+ * @return true.
+ */
+ bool IsReady() const override;
+
+private:
+ std::string m_windowName;
+
+};
+}// namespace common \ No newline at end of file
diff --git a/samples/common/include/CVUtils/IFrameOutput.hpp b/samples/common/include/CVUtils/IFrameOutput.hpp
new file mode 100644
index 0000000000..6f7ca0b574
--- /dev/null
+++ b/samples/common/include/CVUtils/IFrameOutput.hpp
@@ -0,0 +1,48 @@
+//
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include <cstddef>
+#include <memory>
+
+namespace common
+{
+/**
+ * @brief Frames output interface
+ *
+ * @tparam FrameDataT frame container data type
+ */
+ template<typename FrameDataT> class IFrameOutput
+ {
+
+ public:
+ /**
+ * @brief Writes frame to the selected output
+ *
+ * @param frame container
+ */
+ virtual void WriteFrame(std::shared_ptr <FrameDataT>& frame) = 0;
+
+ /**
+ * @brief Closes the frame output
+ */
+ virtual void Close() = 0;
+
+ /**
+ * @brief Checks if the frame sink is ready to write.
+ *
+ * @return True if frame sink is ready, False otherwise
+ */
+ virtual bool IsReady() const = 0;
+
+ /**
+ * @brief Default destructor
+ */
+ virtual ~IFrameOutput() = default;
+
+ };
+
+}// namespace common
diff --git a/samples/common/include/CVUtils/IFrameReader.hpp b/samples/common/include/CVUtils/IFrameReader.hpp
new file mode 100644
index 0000000000..e171b3bb94
--- /dev/null
+++ b/samples/common/include/CVUtils/IFrameReader.hpp
@@ -0,0 +1,45 @@
+//
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include <cstddef>
+#include <memory>
+
+namespace common
+{
+/**
+ * @brief Frame source reader interface
+ *
+ * @tparam FrameDataT frame container data type
+ */
+template<typename FrameDataT> class IFrameReader
+{
+
+public:
+ /**
+ * @brief Reads the next frame from the source
+ *
+ * @return pointer to the frame container
+ */
+ virtual std::shared_ptr <FrameDataT> ReadFrame() = 0;
+
+ /**
+ * @brief Checks if the frame source has more frames to read.
+ *
+ * @param[in] frame the pointer to the last frame captured with the ReadFrame method could be used in
+ * implementation specific logic to check frames source state.
+ * @return True if frame source was exhausted, False otherwise
+ */
+ virtual bool IsExhausted(const std::shared_ptr <FrameDataT>& frame) const = 0;
+
+ /**
+ * @brief Default destructor
+ */
+ virtual ~IFrameReader() = default;
+
+};
+
+}// namespace common \ No newline at end of file
diff --git a/samples/common/include/Utils/CmdArgsParser.hpp b/samples/common/include/Utils/CmdArgsParser.hpp
new file mode 100644
index 0000000000..710a33df93
--- /dev/null
+++ b/samples/common/include/Utils/CmdArgsParser.hpp
@@ -0,0 +1,25 @@
+//
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+#include <string>
+#include <map>
+
+/*
+ * Checks that a particular option was specified by the user
+ */
+bool CheckOptionSpecified(const std::map<std::string, std::string>& options, const std::string& option);
+
+
+/*
+ * Retrieves the user provided option
+ */
+std::string GetSpecifiedOption(const std::map<std::string, std::string>& options, const std::string& option);
+
+
+/*
+ * Parses all the command line options provided by the user and stores in a map.
+ */
+int ParseOptions(std::map<std::string, std::string>& options, std::map<std::string, std::string>& acceptedOptions,
+ char *argv[], int argc); \ No newline at end of file
diff --git a/samples/common/include/Utils/Types.hpp b/samples/common/include/Utils/Types.hpp
new file mode 100644
index 0000000000..4d1f708844
--- /dev/null
+++ b/samples/common/include/Utils/Types.hpp
@@ -0,0 +1,54 @@
+//
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include <cstddef>
+#include <cstdint>
+#include <vector>
+#include <tuple>
+
+#include <armnn/BackendId.hpp>
+
+namespace common
+{
+
+struct Size
+{
+
+ uint32_t m_Width;
+ uint32_t m_Height;
+
+ Size() : Size(0, 0) {}
+
+ Size(uint32_t width, uint32_t height) :
+ m_Width{width}, m_Height{height} {}
+
+ Size(const Size& other)
+ : Size(other.m_Width, other.m_Height) {}
+
+ ~Size() = default;
+
+ Size &operator=(const Size& other) = default;
+};
+
+struct BBoxColor
+{
+ std::tuple<int, int, int> colorCode;
+};
+
+struct PipelineOptions
+{
+ std::string m_ModelName;
+ std::string m_ModelFilePath;
+ std::vector<armnn::BackendId> m_backends;
+};
+
+template<typename T>
+using InferenceResult = std::vector<T>;
+
+template<typename T>
+using InferenceResults = std::vector<InferenceResult<T>>;
+} // namespace common \ No newline at end of file