aboutsummaryrefslogtreecommitdiff
path: root/samples/common
diff options
context:
space:
mode:
authorÉanna Ó Catháin <eanna.ocathain@arm.com>2021-04-07 14:35:25 +0100
committerJim Flynn <jim.flynn@arm.com>2021-05-07 09:11:52 +0000
commitc6ab02a626e15b4a12fc09ecd844eb8b95380c3c (patch)
tree9912ed9cdb89cdb24483b22d6621ae30049ae321 /samples/common
parente813d67f86df41a238ff79b5c554ef5027f56576 (diff)
downloadarmnn-c6ab02a626e15b4a12fc09ecd844eb8b95380c3c.tar.gz
MLECO-1252 ASR sample application using the public ArmNN C++ API.
Change-Id: I98cd505b8772a8c8fa88308121bc94135bb45068 Signed-off-by: Éanna Ó Catháin <eanna.ocathain@arm.com>
Diffstat (limited to 'samples/common')
-rw-r--r--samples/common/cmake/aarch64-toolchain.cmake20
-rw-r--r--samples/common/cmake/arm-linux-gnueabihf-toolchain.cmake20
-rw-r--r--samples/common/cmake/find_armnn.cmake35
-rw-r--r--samples/common/cmake/find_catch.cmake16
-rw-r--r--samples/common/cmake/find_opencv.cmake203
-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
-rw-r--r--samples/common/src/CVUtils/CvVideoFileWriter.cpp38
-rw-r--r--samples/common/src/CVUtils/CvVideoFrameReader.cpp98
-rw-r--r--samples/common/src/CVUtils/CvWindowOutput.cpp33
-rw-r--r--samples/common/src/Utils/CmdArgsParser.cpp70
17 files changed, 1141 insertions, 0 deletions
diff --git a/samples/common/cmake/aarch64-toolchain.cmake b/samples/common/cmake/aarch64-toolchain.cmake
new file mode 100644
index 0000000000..bdd02f88c0
--- /dev/null
+++ b/samples/common/cmake/aarch64-toolchain.cmake
@@ -0,0 +1,20 @@
+# Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+# SPDX-License-Identifier: MIT
+
+# specify the cross compiler
+set(GNU_MACHINE "aarch64-linux-gnu")
+set(CROSS_PREFIX "aarch64-linux-gnu-")
+
+set(CMAKE_C_COMPILER ${CROSS_PREFIX}gcc)
+set(CMAKE_CXX_COMPILER ${CROSS_PREFIX}g++)
+set(CMAKE_AR ${CROSS_PREFIX}ar)
+set(CMAKE_STRIP ${CROSS_PREFIX}strip)
+set(CMAKE_LINKER ${CROSS_PREFIX}ld)
+
+set(CMAKE_CROSSCOMPILING true)
+set(CMAKE_SYSTEM_NAME Linux)
+
+set(CMAKE_SYSTEM_PROCESSOR aarch64)
+
+set(OPENCV_EXTRA_ARGS "-DENABLE_NEON=ON"
+ "-DCMAKE_TOOLCHAIN_FILE=platforms/linux/aarch64-gnu.toolchain.cmake") \ No newline at end of file
diff --git a/samples/common/cmake/arm-linux-gnueabihf-toolchain.cmake b/samples/common/cmake/arm-linux-gnueabihf-toolchain.cmake
new file mode 100644
index 0000000000..f66b964c35
--- /dev/null
+++ b/samples/common/cmake/arm-linux-gnueabihf-toolchain.cmake
@@ -0,0 +1,20 @@
+# Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+# SPDX-License-Identifier: MIT
+
+# specify the cross compiler
+set(GNU_MACHINE "arm-linux-gnueabihf")
+set(CROSS_PREFIX "arm-linux-gnueabihf-")
+
+set(CMAKE_C_COMPILER ${CROSS_PREFIX}gcc)
+set(CMAKE_CXX_COMPILER ${CROSS_PREFIX}g++)
+set(CMAKE_AR ${CROSS_PREFIX}ar)
+set(CMAKE_STRIP ${CROSS_PREFIX}strip)
+set(CMAKE_LINKER ${CROSS_PREFIX}ld)
+
+set(CMAKE_CROSSCOMPILING true)
+set(CMAKE_SYSTEM_NAME Linux)
+
+set(CMAKE_SYSTEM_PROCESSOR arm)
+
+set(OPENCV_EXTRA_ARGS "-DENABLE_NEON=ON"
+ "-DCMAKE_TOOLCHAIN_FILE=platforms/linux/arm.toolchain.cmake") \ No newline at end of file
diff --git a/samples/common/cmake/find_armnn.cmake b/samples/common/cmake/find_armnn.cmake
new file mode 100644
index 0000000000..289e9127f6
--- /dev/null
+++ b/samples/common/cmake/find_armnn.cmake
@@ -0,0 +1,35 @@
+# Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+# SPDX-License-Identifier: MIT
+# Search for ArmNN built libraries in user-provided path first, then current repository, then system
+
+set(ARMNN_LIB_NAMES "libarmnn.so"
+ "libarmnnTfLiteParser.so")
+
+set(ARMNN_LIBS "")
+
+get_filename_component(PARENT_DIR ${PROJECT_SOURCE_DIR} DIRECTORY)
+get_filename_component(REPO_DIR ${PARENT_DIR} DIRECTORY)
+
+foreach(armnn_lib ${ARMNN_LIB_NAMES})
+ find_library(ARMNN_${armnn_lib}
+ NAMES
+ ${armnn_lib}
+ HINTS
+ ${ARMNN_LIB_DIR} ${REPO_DIR}
+ PATHS
+ ${ARMNN_LIB_DIR} ${REPO_DIR}
+ PATH_SUFFIXES
+ "lib"
+ "lib64")
+ if(ARMNN_${armnn_lib})
+ message("Found library ${ARMNN_${armnn_lib}}")
+ list(APPEND ARMNN_LIBS ${ARMNN_${armnn_lib}})
+ get_filename_component(LIB_DIR ${ARMNN_${armnn_lib}} DIRECTORY)
+ get_filename_component(LIB_PARENT_DIR ${LIB_DIR} DIRECTORY)
+ set(ARMNN_INCLUDE_DIR ${LIB_PARENT_DIR}/include)
+ endif()
+endforeach()
+
+if(NOT ARMNN_LIBS)
+ message(FATAL_ERROR "Could not find ArmNN libraries ${ARMNN_LIB_NAMES}")
+endif()
diff --git a/samples/common/cmake/find_catch.cmake b/samples/common/cmake/find_catch.cmake
new file mode 100644
index 0000000000..584b8073bd
--- /dev/null
+++ b/samples/common/cmake/find_catch.cmake
@@ -0,0 +1,16 @@
+# Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+# SPDX-License-Identifier: MIT
+
+#Test TPIP
+set(TEST_TPIP ${DEPENDENCIES_DIR}/test)
+file(MAKE_DIRECTORY ${TEST_TPIP})
+set(TEST_TPIP_INCLUDE ${TEST_TPIP}/include)
+file(MAKE_DIRECTORY ${TEST_TPIP_INCLUDE})
+
+ExternalProject_Add(catch2-headers
+ URL https://github.com/catchorg/Catch2/releases/download/v2.11.1/catch.hpp
+ DOWNLOAD_NO_EXTRACT 1
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ${CMAKE_COMMAND} -E copy <DOWNLOAD_DIR>/catch.hpp ${TEST_TPIP_INCLUDE}
+ INSTALL_COMMAND ""
+ ) \ No newline at end of file
diff --git a/samples/common/cmake/find_opencv.cmake b/samples/common/cmake/find_opencv.cmake
new file mode 100644
index 0000000000..92086e1316
--- /dev/null
+++ b/samples/common/cmake/find_opencv.cmake
@@ -0,0 +1,203 @@
+# Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+# SPDX-License-Identifier: MIT
+
+set(OPENCV_VERSION 4.0.0)
+set(FFMPEG_VERSION 4.2.1)
+set(LIBX264_VERSION stable)
+
+set(OPENCV_LIB OpenCV${OPENCV_VERSION})
+set(FFMPEG_LIB ffmpeg${FFMPEG_VERSION})
+set(X264_LIB x264${LIBX264_VERSION})
+
+set(OPENCV_NAMES
+ libopencv_core.so.${OPENCV_VERSION}
+ libopencv_imgproc.so.${OPENCV_VERSION}
+ libopencv_imgcodecs.so.${OPENCV_VERSION}
+ libopencv_videoio.so.${OPENCV_VERSION}
+ libopencv_video.so.${OPENCV_VERSION}
+ libopencv_highgui.so.${OPENCV_VERSION})
+
+set(OPENCV_LIBS)
+set(FFMPEG_LIBS)
+
+foreach(opencv_lib ${OPENCV_NAMES})
+ find_library(OPENCV_${opencv_lib}
+ NAMES
+ ${opencv_lib}
+ HINTS
+ ${OPENCV_LIB_DIR}
+ PATHS
+ ${OPENCV_LIB_DIR}
+ PATH_SUFFIXES
+ "lib"
+ "lib64")
+ if(OPENCV_${opencv_lib})
+ message("Found library ${OPENCV_${opencv_lib}}")
+ list(APPEND OPENCV_LIBS ${OPENCV_${opencv_lib}})
+ get_filename_component(OPENCV_LIB_DIR ${OPENCV_${opencv_lib}} DIRECTORY)
+ get_filename_component(OPENCV_ROOT_DIR ${OPENCV_LIB_DIR} DIRECTORY)
+ set(OPENCV_INCLUDE_DIR ${OPENCV_ROOT_DIR}/include/opencv4)
+ endif()
+endforeach()
+
+if(OPENCV_LIBS)
+ message("OpenCV libraries found")
+ set(OPENCV_LIBS_FOUND TRUE)
+else()
+ set(OPENCV_ROOT_DIR ${DEPENDENCIES_DIR}/opencv)
+ set(OPENCV_DEPENDENCIES_ARGS)
+ set(OPENCV_EXTRA_LINKER_ARGS)
+ set(OPENCV_PKGCONFIG)
+
+ if(CMAKE_CROSSCOMPILING)
+ set(FFMPEG_ROOT_DIR ${DEPENDENCIES_DIR}/ffmpeg)
+ set(LIBX264_ROOT_DIR ${DEPENDENCIES_DIR}/x264)
+
+ if (CMAKE_BUILD_TYPE STREQUAL Debug)
+ set(CONFIGURE_DEBUG --enable-debug)
+ set(OPENCV_DEBUG "-DBUILD_WITH_DEBUG_INFO=ON")
+ endif()
+
+
+ ExternalProject_Add(${X264_LIB}
+ URL "https://code.videolan.org/videolan/x264/-/archive/${LIBX264_VERSION}/x264-${LIBX264_VERSION}.tar.gz"
+ DOWNLOAD_DIR ${LIBX264_ROOT_DIR}
+ PREFIX ${LIBX264_ROOT_DIR}
+ CONFIGURE_COMMAND <SOURCE_DIR>/configure
+ --host=${GNU_MACHINE}
+ --enable-static
+ --enable-shared
+ --cross-prefix=${CROSS_PREFIX}
+ --prefix=${CMAKE_BINARY_DIR}
+ --extra-ldflags=-static-libstdc++
+ --extra-cflags=-fPIC
+ ${CONFIGURE_DEBUG}
+ INSTALL_DIR ${CMAKE_BINARY_DIR}
+ BUILD_COMMAND $(MAKE)
+ INSTALL_COMMAND $(MAKE) install
+ )
+
+ set(FFMPEG_Config
+ --enable-shared
+ --enable-cross-compile
+ --cross-prefix=${CROSS_PREFIX}
+ --arch=${CMAKE_SYSTEM_PROCESSOR}
+ --target-os=linux
+ --prefix=${CMAKE_BINARY_DIR}
+ --enable-gpl
+ --enable-nonfree
+ --enable-libx264
+ --extra-cflags=-I${CMAKE_BINARY_DIR}/include
+ --extra-cflags=-fPIC
+ --extra-ldflags=-L${CMAKE_BINARY_DIR}/lib
+ --extra-libs=-ldl
+ --extra-libs=-static-libstdc++
+ )
+
+ ExternalProject_Add(${FFMPEG_LIB}
+ URL "https://github.com/FFmpeg/FFmpeg/archive/n${FFMPEG_VERSION}.tar.gz"
+ URL_HASH MD5=05792c611d1e3ebdf2c7003ff4467390
+ DOWNLOAD_DIR ${FFMPEG_ROOT_DIR}
+ PREFIX ${FFMPEG_ROOT_DIR}
+ CONFIGURE_COMMAND <SOURCE_DIR>/configure ${FFMPEG_Config} ${CONFIGURE_DEBUG}
+ INSTALL_DIR ${CMAKE_BINARY_DIR}
+ BUILD_COMMAND $(MAKE) VERBOSE=1
+ INSTALL_COMMAND $(MAKE) install
+ )
+
+ set(OPENCV_DEPENDENCIES_ARGS "-static-libstdc++ -Wl,-rpath,${CMAKE_BINARY_DIR}/lib")
+ set(OPENCV_EXTRA_LINKER_ARGS "-DOPENCV_EXTRA_EXE_LINKER_FLAGS=${OPENCV_DEPENDENCIES_ARGS}")
+
+ set(OPENCV_PKGCONFIG "PKG_CONFIG_LIBDIR=${CMAKE_BINARY_DIR}/lib/pkgconfig")
+
+ set(FFMPEG_NAMES
+ libavcodec.so
+ libavformat.so
+ libavutil.so
+ libswscale.so
+ )
+
+ foreach(ffmpeg_lib ${FFMPEG_NAMES})
+ add_library(FFMPEG_${ffmpeg_lib} SHARED IMPORTED)
+ set_target_properties(FFMPEG_${ffmpeg_lib} PROPERTIES IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/${ffmpeg_lib})
+ list(APPEND OPENCV_LIBS FFMPEG_${ffmpeg_lib})
+ endforeach()
+
+ add_library(X264_lib264.so SHARED IMPORTED)
+ set_target_properties(X264_lib264.so PROPERTIES IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/libx264.so)
+ list(APPEND OPENCV_LIBS X264_lib264.so)
+ endif()
+
+ set(OPENCV_CMAKE_ARGS
+ -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
+ -DCMAKE_C_FLAGS=-fPIC
+ -DCMAKE_CXX_FLAGS=-fPIC
+ -DWITH_GTK=OFF
+ -DWITH_JPEG=ON
+ -DWITH_IPP=OFF
+ -DBUILD_opencv_java_bindings_generator=OFF
+ -DBUILD_opencv_ml=OFF
+ -DBUILD_opencv_objdetect=OFF
+ -DBUILD_opencv_photo=OFF
+ -DBUILD_opencv_python_bindings_generator=OFF
+ -DBUILD_opencv_stitching=OFF
+ -DBUILD_opencv_gapi=OFF
+ -DBUILD_opencv_features2d=OFF
+ -DBUILD_opencv_dnn=OFF
+ -DBUILD_opencv_flann=OFF
+ -DBUILD_opencv_calib3d=OFF
+ -DBUILD_opencv_python2=OFF
+ -DBUILD_opencv_python3=OFF
+ -DBUILD_opencv_java=OFF
+ -DBUILD_opencv_js=OFF
+ -DBUILD_opencv_ts=OFF
+ -DBUILD_JPEG=ON
+ -DBUILD_JPEG_TURBO_DISABLE=ON
+ -DBUILD_PNG=ON
+ -DBUILD_TIFF=ON
+ -DZLIB_FOUND=OFF
+ -DBUILD_ZLIB=ON
+ -DBUILD_PERF_TESTS=OFF
+ -DBUILD_TESTS=OFF
+ -DBUILD_DOCS=OFF
+ -DBUILD_opencv_apps=OFF
+ -DBUILD_EXAMPLES=OFF
+ -DWITH_V4L=ON
+ -DWITH_LIBV4L=OFF
+ -DWITH_FFMPEG=ON
+ -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}
+ -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
+ -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
+ -DCMAKE_INSTALL_RPATH=\$ORIGIN:\$ORIGIN/lib:\$ORIGIN/../lib
+ -DCMAKE_SHARED_LINKER_FLAGS=-static-libstdc++
+ ${OPENCV_DEBUG}
+ )
+
+ ExternalProject_Add(${OPENCV_LIB}
+ URL "https://codeload.github.com/opencv/opencv/tar.gz/${OPENCV_VERSION}"
+ URL_HASH MD5=f051c1ff7b327b60123d71b53801b316
+ DOWNLOAD_DIR ${OPENCV_ROOT_DIR}
+ PREFIX ${OPENCV_ROOT_DIR}
+ CONFIGURE_COMMAND ${OPENCV_PKGCONFIG}
+ ${CMAKE_COMMAND} ${OPENCV_CMAKE_ARGS} ${OPENCV_EXTRA_ARGS}
+ ${OPENCV_EXTRA_LINKER_ARGS} ${OPENCV_ROOT_DIR}/src/${OPENCV_LIB}
+ INSTALL_DIR ${CMAKE_BINARY_DIR}
+ BUILD_COMMAND $(MAKE)
+ INSTALL_COMMAND $(MAKE) install
+ )
+
+ if(CMAKE_CROSSCOMPILING)
+ ExternalProject_Add_StepDependencies(${FFMPEG_LIB} build ${X264_LIB})
+ ExternalProject_Add_StepDependencies(${OPENCV_LIB} build ${FFMPEG_LIB})
+ endif()
+
+ set(OPENCV_INCLUDE_DIR ${CMAKE_BINARY_DIR}/include/opencv4)
+ set(OPENCV_LIB_DIR ${CMAKE_BINARY_DIR}/lib)
+
+ foreach(opencv_lib ${OPENCV_NAMES})
+ add_library(OPENCV_${opencv_lib} SHARED IMPORTED)
+ set_target_properties(OPENCV_${opencv_lib} PROPERTIES IMPORTED_LOCATION ${OPENCV_LIB_DIR}/${opencv_lib})
+ list(APPEND OPENCV_LIBS OPENCV_${opencv_lib})
+ endforeach()
+
+endif() \ No newline at end of file
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
diff --git a/samples/common/src/CVUtils/CvVideoFileWriter.cpp b/samples/common/src/CVUtils/CvVideoFileWriter.cpp
new file mode 100644
index 0000000000..b76630049a
--- /dev/null
+++ b/samples/common/src/CVUtils/CvVideoFileWriter.cpp
@@ -0,0 +1,38 @@
+//
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "CvVideoFileWriter.hpp"
+
+namespace common
+{
+
+void CvVideoFileWriter::Init(const std::string& outputVideo, int encoding, double fps, int width, int height)
+{
+ m_ready = m_cvWriter.open(outputVideo, cv::CAP_FFMPEG,
+ encoding,
+ fps,
+ cv::Size(width, height), true);
+}
+
+
+void CvVideoFileWriter::WriteFrame(std::shared_ptr<cv::Mat>& frame)
+{
+ if(m_cvWriter.isOpened())
+ {
+ cv::cvtColor(*frame, *frame, cv::COLOR_RGB2BGR);
+ m_cvWriter.write(*frame);
+ }
+}
+
+bool CvVideoFileWriter::IsReady() const
+{
+ return m_ready;
+}
+
+void CvVideoFileWriter::Close()
+{
+ m_cvWriter.release();
+}
+}// namespace common
diff --git a/samples/common/src/CVUtils/CvVideoFrameReader.cpp b/samples/common/src/CVUtils/CvVideoFrameReader.cpp
new file mode 100644
index 0000000000..2bd92d2d81
--- /dev/null
+++ b/samples/common/src/CVUtils/CvVideoFrameReader.cpp
@@ -0,0 +1,98 @@
+//
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+
+#include "CvVideoFrameReader.hpp"
+
+namespace common
+{
+
+std::shared_ptr<cv::Mat> CvVideoFrameReader::ReadFrame()
+{
+ // opencv copies data anyway
+ cv::Mat captureFrame;
+ m_capture.read(captureFrame);
+ return std::make_shared<cv::Mat>(std::move(captureFrame));
+}
+
+bool CvVideoFrameReader::IsExhausted(const std::shared_ptr<cv::Mat>& frame) const
+{
+ assert(frame!=nullptr);
+ return frame->empty();
+}
+
+void CvVideoFrameReader::CheckIsOpen(const std::string& source)
+{
+ if (!m_capture.isOpened())
+ {
+ throw std::runtime_error("Failed to open video capture for the source = " + source);
+ }
+}
+
+void CvVideoFrameReader::Init(const std::string& source)
+{
+ m_capture.open(source);
+ CheckIsOpen(source);
+}
+
+int CvVideoFrameReader::GetSourceWidth() const
+{
+ return static_cast<int>(lround(m_capture.get(cv::CAP_PROP_FRAME_WIDTH)));
+}
+
+int CvVideoFrameReader::GetSourceHeight() const
+{
+ return static_cast<int>(lround(m_capture.get(cv::CAP_PROP_FRAME_HEIGHT)));
+}
+
+double CvVideoFrameReader::GetSourceFps() const
+{
+ return m_capture.get(cv::CAP_PROP_FPS);
+}
+
+bool CvVideoFrameReader::ConvertToRGB()
+{
+ m_capture.set(cv::CAP_PROP_CONVERT_RGB, 1.0);
+ return static_cast<bool>(m_capture.get(cv::CAP_PROP_CONVERT_RGB));
+}
+
+std::string CvVideoFrameReader::GetSourceEncoding() const
+{
+ char fourccStr[5];
+ auto fourcc = (int)m_capture.get(cv::CAP_PROP_FOURCC);
+ sprintf(fourccStr,"%c%c%c%c",fourcc & 0xFF, (fourcc >> 8) & 0xFF, (fourcc >> 16) & 0xFF, (fourcc >> 24) & 0xFF);
+ return fourccStr;
+}
+
+int CvVideoFrameReader::GetSourceEncodingInt() const
+{
+ return (int)m_capture.get(cv::CAP_PROP_FOURCC);
+}
+
+int CvVideoFrameReader::GetFrameCount() const
+{
+ return static_cast<int>(lround(m_capture.get(cv::CAP_PROP_FRAME_COUNT)));
+};
+
+std::shared_ptr<cv::Mat> CvVideoFrameReaderRgbWrapper::ReadFrame()
+{
+ auto framePtr = m_reader->ReadFrame();
+ if (!IsExhausted(framePtr))
+ {
+ cv::cvtColor(*framePtr, *framePtr, cv::COLOR_BGR2RGB);
+ }
+ return framePtr;
+}
+
+bool CvVideoFrameReaderRgbWrapper::IsExhausted(const std::shared_ptr<cv::Mat>& frame) const
+{
+ return m_reader->IsExhausted(frame);
+}
+
+CvVideoFrameReaderRgbWrapper::CvVideoFrameReaderRgbWrapper(std::unique_ptr<common::CvVideoFrameReader> reader):
+ m_reader(std::move(reader))
+{}
+
+}// namespace common \ No newline at end of file
diff --git a/samples/common/src/CVUtils/CvWindowOutput.cpp b/samples/common/src/CVUtils/CvWindowOutput.cpp
new file mode 100644
index 0000000000..190a7602e2
--- /dev/null
+++ b/samples/common/src/CVUtils/CvWindowOutput.cpp
@@ -0,0 +1,33 @@
+//
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "CvWindowOutput.hpp"
+
+namespace common
+{
+
+void CvWindowOutput::Init(const std::string& windowName)
+{
+ m_windowName = windowName;
+ cv::namedWindow(m_windowName, cv::WINDOW_AUTOSIZE);
+}
+
+void CvWindowOutput::WriteFrame(std::shared_ptr<cv::Mat>& frame)
+{
+ cv::cvtColor(*frame, *frame, cv::COLOR_RGB2BGR);
+ cv::imshow( m_windowName, *frame);
+ cv::waitKey(30);
+}
+
+void CvWindowOutput::Close()
+{
+ cv::destroyWindow(m_windowName);
+}
+
+bool CvWindowOutput::IsReady() const
+{
+ return true;
+}
+}// namespace common \ No newline at end of file
diff --git a/samples/common/src/Utils/CmdArgsParser.cpp b/samples/common/src/Utils/CmdArgsParser.cpp
new file mode 100644
index 0000000000..1f09826a8b
--- /dev/null
+++ b/samples/common/src/Utils/CmdArgsParser.cpp
@@ -0,0 +1,70 @@
+//
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "CmdArgsParser.hpp"
+#include <iostream>
+/*
+ * Checks that a particular option was specified by the user
+ */
+bool CheckOptionSpecified(const std::map<std::string, std::string>& options, const std::string& option)
+{
+ auto it = options.find(option);
+ return it!=options.end();
+}
+
+/*
+ * Retrieves the user provided option
+ */
+std::string GetSpecifiedOption(const std::map<std::string, std::string>& options, const std::string& option)
+{
+ if (CheckOptionSpecified(options, option)){
+ return options.at(option);
+ }
+ else
+ {
+ throw std::invalid_argument("Required option: " + option + " not defined.");
+ }
+}
+
+/*
+ * 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)
+{
+ for (int i = 1; i < argc; ++i)
+ {
+ std::string currentOption = std::string(argv[i]);
+ auto it = acceptedOptions.find(currentOption);
+ if (it != acceptedOptions.end())
+ {
+ if (i + 1 < argc && std::string(argv[i + 1]).rfind("--", 0) != 0)
+ {
+ std::string value = argv[++i];
+ options.insert({it->first, value});
+ }
+ else if (std::string(argv[i]) == "HELP")
+ {
+ std::cout << "Available options" << std::endl;
+ for (auto & acceptedOption : acceptedOptions)
+ {
+ std::cout << acceptedOption.first << " : " << acceptedOption.second << std::endl;
+ }
+ return 2;
+ }
+ else
+ {
+ std::cerr << std::string(argv[i]) << " option requires one argument." << std::endl;
+ return 1;
+ }
+ }
+ else
+ {
+ std::cerr << "Unrecognised option: " << std::string(argv[i]) << std::endl;
+ return 1;
+ }
+ }
+ return 0;
+}