diff options
Diffstat (limited to 'python/openvino/runtime/common/demo_utils/src')
7 files changed, 1045 insertions, 0 deletions
diff --git a/python/openvino/runtime/common/demo_utils/src/args_helper.cpp b/python/openvino/runtime/common/demo_utils/src/args_helper.cpp new file mode 100644 index 0000000..8f4bc35 --- /dev/null +++ b/python/openvino/runtime/common/demo_utils/src/args_helper.cpp @@ -0,0 +1,155 @@ +// Copyright (C) 2018-2022 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "utils/args_helper.hpp" +#include "utils/slog.hpp" + +#ifdef _WIN32 +#include "w_dirent.hpp" +#else +#include <dirent.h> +#endif + +#include <gflags/gflags.h> + +#include <sys/stat.h> +#include <map> + +#include <algorithm> +#include <cctype> +#include <sstream> + +void readInputFilesArguments(std::vector<std::string>& files, const std::string& arg) { + struct stat sb; + if (stat(arg.c_str(), &sb) != 0) { + if (arg.compare(0, 5, "rtsp:") != 0) { + slog::warn << "File " << arg << " cannot be opened!" << slog::endl; + return; + } + } + if (S_ISDIR(sb.st_mode)) { + DIR *dp; + dp = opendir(arg.c_str()); + if (dp == nullptr) { + slog::warn << "Directory " << arg << " cannot be opened!" << slog::endl; + return; + } + + struct dirent *ep; + while (nullptr != (ep = readdir(dp))) { + std::string fileName = ep->d_name; + if (fileName == "." || fileName == "..") continue; + files.push_back(arg + "/" + ep->d_name); + } + closedir(dp); + } else { + files.push_back(arg); + } +} + +void parseInputFilesArguments(std::vector<std::string>& files) { + std::vector<std::string> args = gflags::GetArgvs(); + bool readArguments = false; + for (size_t i = 0; i < args.size(); i++) { + if (args.at(i) == "-i" || args.at(i) == "--i") { + readArguments = true; + continue; + } + if (!readArguments) { + continue; + } + if (args.at(i).c_str()[0] == '-') { + break; + } + readInputFilesArguments(files, args.at(i)); + } +} + +std::vector<std::string> split(const std::string& s, char delim) { + std::vector<std::string> result; + std::stringstream ss(s); + std::string item; + + while (getline(ss, item, delim)) { + result.push_back(item); + } + return result; +} + +std::vector<std::string> parseDevices(const std::string& device_string) { + const std::string::size_type colon_position = device_string.find(":"); + if (colon_position != std::string::npos) { + std::string device_type = device_string.substr(0, colon_position); + if (device_type == "HETERO" || device_type == "MULTI") { + std::string comma_separated_devices = device_string.substr(colon_position + 1); + std::vector<std::string> devices = split(comma_separated_devices, ','); + for (auto& device : devices) + device = device.substr(0, device.find("(")); + return devices; + } + } + return {device_string}; +} + +// Format: <device1>:<value1>,<device2>:<value2> or just <value> +std::map<std::string, int32_t> parseValuePerDevice(const std::set<std::string>& devices, + const std::string& values_string) { + auto values_string_upper = values_string; + std::transform(values_string_upper.begin(), + values_string_upper.end(), + values_string_upper.begin(), + [](unsigned char c){ return std::toupper(c); }); + std::map<std::string, int32_t> result; + auto device_value_strings = split(values_string_upper, ','); + for (auto& device_value_string : device_value_strings) { + auto device_value_vec = split(device_value_string, ':'); + if (device_value_vec.size() == 2) { + auto it = std::find(devices.begin(), devices.end(), device_value_vec.at(0)); + if (it != devices.end()) { + result[device_value_vec.at(0)] = std::stoi(device_value_vec.at(1)); + } + } else if (device_value_vec.size() == 1) { + uint32_t value = std::stoi(device_value_vec.at(0)); + for (const auto& device : devices) { + result[device] = value; + } + } else if (device_value_vec.size() != 0) { + throw std::runtime_error("Unknown string format: " + values_string); + } + } + return result; +} + +cv::Size stringToSize(const std::string& str) { + std::vector<std::string> strings = split(str, 'x'); + if (strings.size() != 2) { + throw std::invalid_argument("Can't convert std::string to cv::Size. The string must contain exactly one x"); + } + return {std::stoi(strings[0]), std::stoi(strings[1])}; +} + +std::map<std::string, ov::Layout> parseLayoutString(const std::string& layout_string) { + // Parse parameter string like "input0:NCHW,input1:NC" or "NCHW" (applied to all + // inputs) + std::map<std::string, ov::Layout> layouts; + std::string searchStr = (layout_string.find_last_of(':') == std::string::npos && !layout_string.empty() ? + ":" : "") + layout_string; + auto colonPos = searchStr.find_last_of(':'); + while (colonPos != std::string::npos) { + auto startPos = searchStr.find_last_of(','); + auto inputName = searchStr.substr(startPos + 1, colonPos - startPos - 1); + auto inputLayout = searchStr.substr(colonPos + 1); + layouts[inputName] = ov::Layout(inputLayout); + searchStr = searchStr.substr(0, startPos + 1); + if (searchStr.empty() || searchStr.back() != ',') { + break; + } + searchStr.pop_back(); + colonPos = searchStr.find_last_of(':'); + } + if (!searchStr.empty()) { + throw std::invalid_argument("Can't parse input layout string: " + layout_string); + } + return layouts; +} diff --git a/python/openvino/runtime/common/demo_utils/src/config_factory.cpp b/python/openvino/runtime/common/demo_utils/src/config_factory.cpp new file mode 100644 index 0000000..2e9a442 --- /dev/null +++ b/python/openvino/runtime/common/demo_utils/src/config_factory.cpp @@ -0,0 +1,111 @@ +/* +// Copyright (C) 2020-2022 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +*/ + +#include "utils/config_factory.h" + +#include <set> +#include <string> +#include <utility> +#include <vector> + +#include <openvino/runtime/intel_gpu/properties.hpp> +#include "dla_plugin_config.hpp" +#include "utils/args_helper.hpp" +#include <sys/stat.h> + +std::set<std::string> ModelConfig::getDevices() { + if (devices.empty()) { + for (const std::string& device : parseDevices(deviceName)) { + devices.insert(device); + } + } + + return devices; +} + +ModelConfig ConfigFactory::getUserConfig(const std::string& flags_d, + uint32_t flags_nireq, + const std::string& flags_nstreams, + uint32_t flags_nthreads, + const std::string &flags_arch) { + auto config = getCommonConfig(flags_d, flags_nireq); + + std::map<std::string, int> deviceNstreams = parseValuePerDevice(config.getDevices(), flags_nstreams); + for (const auto& device : config.getDevices()) { + if (flags_arch != "" && device == "FPGA") { + struct stat buffer; + if (stat(flags_arch.c_str(), &buffer) != 0) { + std::cout << "Error: architecture file: " << flags_arch << " doesn't exist. Please provide a valid path." << std::endl; + throw std::logic_error("architecture file path does not exist."); + } + config.compiledModelConfig.emplace(DLIAPlugin::properties::arch_path.name(), flags_arch); + } else if (device == "CPU") { // CPU supports a few special performance-oriented keys + // limit threading for CPU portion of inference + if (flags_nthreads != 0) + config.compiledModelConfig.emplace(ov::inference_num_threads.name(), flags_nthreads); + + config.compiledModelConfig.emplace(ov::affinity.name(), ov::Affinity::NONE); + + ov::streams::Num nstreams = + deviceNstreams.count(device) > 0 ? ov::streams::Num(deviceNstreams[device]) : ov::streams::AUTO; + config.compiledModelConfig.emplace(ov::streams::num.name(), nstreams); + } else if (device == "GPU") { + ov::streams::Num nstreams = + deviceNstreams.count(device) > 0 ? ov::streams::Num(deviceNstreams[device]) : ov::streams::AUTO; + config.compiledModelConfig.emplace(ov::streams::num.name(), nstreams); + if (flags_d.find("MULTI") != std::string::npos && + config.getDevices().find("CPU") != config.getDevices().end()) { + // multi-device execution with the CPU + GPU performs best with GPU throttling hint, + // which releases another CPU thread (that is otherwise used by the GPU driver for active polling) + config.compiledModelConfig.emplace(ov::intel_gpu::hint::queue_throttle.name(), + ov::intel_gpu::hint::ThrottleLevel(1)); + } + } + } + return config; +} + +ModelConfig ConfigFactory::getMinLatencyConfig(const std::string& flags_d, uint32_t flags_nireq) { + auto config = getCommonConfig(flags_d, flags_nireq); + for (const auto& device : config.getDevices()) { + if (device == "CPU") { // CPU supports a few special performance-oriented keys + config.compiledModelConfig.emplace(ov::streams::num.name(), 1); + } else if (device == "GPU") { + config.compiledModelConfig.emplace(ov::streams::num.name(), 1); + } + } + return config; +} + +ModelConfig ConfigFactory::getCommonConfig(const std::string& flags_d, uint32_t flags_nireq) { + ModelConfig config; + + if (!flags_d.empty()) { + config.deviceName = flags_d; + } + + config.maxAsyncRequests = flags_nireq; + + return config; +} + +std::map<std::string, std::string> ModelConfig::getLegacyConfig() { + std::map<std::string, std::string> config; + for (const auto& item : compiledModelConfig) { + config[item.first] = item.second.as<std::string>(); + } + return config; +} diff --git a/python/openvino/runtime/common/demo_utils/src/image_utils.cpp b/python/openvino/runtime/common/demo_utils/src/image_utils.cpp new file mode 100644 index 0000000..039dd66 --- /dev/null +++ b/python/openvino/runtime/common/demo_utils/src/image_utils.cpp @@ -0,0 +1,55 @@ +/* +// Copyright (C) 2021-2022 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +*/ + +#include "utils/image_utils.h" + +cv::Mat resizeImageExt(const cv::Mat& mat, int width, int height, RESIZE_MODE resizeMode, + cv::InterpolationFlags interpolationMode, cv::Rect* roi, cv::Scalar BorderConstant) { + if (width == mat.cols && height == mat.rows) { + return mat; + } + + cv::Mat dst; + + switch (resizeMode) { + case RESIZE_FILL: + { + cv::resize(mat, dst, cv::Size(width, height), interpolationMode); + if (roi) { + *roi = cv::Rect(0, 0, width, height); + } + break; + } + case RESIZE_KEEP_ASPECT: + case RESIZE_KEEP_ASPECT_LETTERBOX: + { + double scale = std::min(static_cast<double>(width) / mat.cols, static_cast<double>(height) / mat.rows); + cv::Mat resizedImage; + cv::resize(mat, resizedImage, cv::Size(0, 0), scale, scale, interpolationMode); + + int dx = resizeMode == RESIZE_KEEP_ASPECT ? 0 : (width - resizedImage.cols) / 2; + int dy = resizeMode == RESIZE_KEEP_ASPECT ? 0 : (height - resizedImage.rows) / 2; + + cv::copyMakeBorder(resizedImage, dst, dy, height - resizedImage.rows - dy, + dx, width - resizedImage.cols - dx, cv::BORDER_CONSTANT, BorderConstant); + if (roi) { + *roi = cv::Rect(dx, dy, resizedImage.cols, resizedImage.rows); + } + break; + } + } + return dst; +} diff --git a/python/openvino/runtime/common/demo_utils/src/images_capture.cpp b/python/openvino/runtime/common/demo_utils/src/images_capture.cpp new file mode 100644 index 0000000..febcdd7 --- /dev/null +++ b/python/openvino/runtime/common/demo_utils/src/images_capture.cpp @@ -0,0 +1,327 @@ +// Copyright (C) 2020-2022 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// +#include "utils/images_capture.h" + +#include <string.h> + +#ifdef _WIN32 +# include "w_dirent.hpp" +#else +# include <dirent.h> // for closedir, dirent, opendir, readdir, DIR +#endif + +#include <algorithm> +#include <chrono> +#include <fstream> +#include <memory> +#include <stdexcept> +#include <string> +#include <vector> + +#include <opencv2/imgcodecs.hpp> +#include <opencv2/videoio.hpp> + +class InvalidInput : public std::runtime_error { +public: + explicit InvalidInput(const std::string& message) noexcept : std::runtime_error(message) {} +}; + +class OpenError : public std::runtime_error { +public: + explicit OpenError(const std::string& message) noexcept : std::runtime_error(message) {} +}; + +class ImreadWrapper : public ImagesCapture { + cv::Mat img; + bool canRead; + +public: + ImreadWrapper(const std::string& input, bool loop) : ImagesCapture{loop}, canRead{true} { + auto startTime = std::chrono::steady_clock::now(); + + std::ifstream file(input.c_str()); + if (!file.good()) + throw InvalidInput("Can't find the image by " + input); + + img = cv::imread(input); + if (!img.data) + throw OpenError("Can't open the image from " + input); + else + readerMetrics.update(startTime); + } + + double fps() const override { + return 1.0; + } + + std::string getType() const override { + return "IMAGE"; + } + + cv::Mat read() override { + if (loop) + return img.clone(); + if (canRead) { + canRead = false; + return img.clone(); + } + return cv::Mat{}; + } +}; + +class DirReader : public ImagesCapture { + std::vector<std::string> names; + size_t fileId; + size_t nextImgId; + const size_t initialImageId; + const size_t readLengthLimit; + const std::string input; + +public: + DirReader(const std::string& input, bool loop, size_t initialImageId, size_t readLengthLimit) + : ImagesCapture{loop}, + fileId{0}, + nextImgId{0}, + initialImageId{initialImageId}, + readLengthLimit{readLengthLimit}, + input{input} { + DIR* dir = opendir(input.c_str()); + if (!dir) + throw InvalidInput("Can't find the dir by " + input); + while (struct dirent* ent = readdir(dir)) + if (strcmp(ent->d_name, ".") && strcmp(ent->d_name, "..")) + names.emplace_back(ent->d_name); + closedir(dir); + if (names.empty()) + throw OpenError("The dir " + input + " is empty"); + sort(names.begin(), names.end()); + size_t readImgs = 0; + while (fileId < names.size()) { + cv::Mat img = cv::imread(input + '/' + names[fileId]); + if (img.data) { + ++readImgs; + if (readImgs - 1 >= initialImageId) + return; + } + ++fileId; + } + throw OpenError("Can't read the first image from " + input); + } + + double fps() const override { + return 1.0; + } + + std::string getType() const override { + return "DIR"; + } + + cv::Mat read() override { + auto startTime = std::chrono::steady_clock::now(); + + while (fileId < names.size() && nextImgId < readLengthLimit) { + cv::Mat img = cv::imread(input + '/' + names[fileId]); + ++fileId; + if (img.data) { + ++nextImgId; + readerMetrics.update(startTime); + return img; + } + } + + if (loop) { + fileId = 0; + size_t readImgs = 0; + while (fileId < names.size()) { + cv::Mat img = cv::imread(input + '/' + names[fileId]); + ++fileId; + if (img.data) { + ++readImgs; + if (readImgs - 1 >= initialImageId) { + nextImgId = 1; + readerMetrics.update(startTime); + return img; + } + } + } + } + return cv::Mat{}; + } +}; + +class VideoCapWrapper : public ImagesCapture { + cv::VideoCapture cap; + bool first_read; + const read_type type; + size_t nextImgId; + const double initialImageId; + size_t readLengthLimit; + +public: + VideoCapWrapper(const std::string& input, bool loop, read_type type, size_t initialImageId, size_t readLengthLimit) + : ImagesCapture{loop}, + first_read{true}, + type{type}, + nextImgId{0}, + initialImageId{static_cast<double>(initialImageId)} { + if (0 == readLengthLimit) { + throw std::runtime_error("readLengthLimit must be positive"); + } + if (cap.open(input)) { + this->readLengthLimit = readLengthLimit; + if (!cap.set(cv::CAP_PROP_POS_FRAMES, this->initialImageId)) + throw OpenError("Can't set the frame to begin with"); + return; + } + throw InvalidInput("Can't open the video from " + input); + } + + double fps() const override { + return cap.get(cv::CAP_PROP_FPS); + } + + std::string getType() const override { + return "VIDEO"; + } + + cv::Mat read() override { + auto startTime = std::chrono::steady_clock::now(); + + if (nextImgId >= readLengthLimit) { + if (loop && cap.set(cv::CAP_PROP_POS_FRAMES, initialImageId)) { + nextImgId = 1; + cv::Mat img; + cap.read(img); + if (type == read_type::safe) { + img = img.clone(); + } + readerMetrics.update(startTime); + return img; + } + return cv::Mat{}; + } + cv::Mat img; + bool success = cap.read(img); + if (!success && first_read) { + throw std::runtime_error("The first image can't be read"); + } + first_read = false; + if (!success && loop && cap.set(cv::CAP_PROP_POS_FRAMES, initialImageId)) { + nextImgId = 1; + cap.read(img); + } else { + ++nextImgId; + } + if (type == read_type::safe) { + img = img.clone(); + } + readerMetrics.update(startTime); + return img; + } +}; + +class CameraCapWrapper : public ImagesCapture { + cv::VideoCapture cap; + const read_type type; + size_t nextImgId; + size_t readLengthLimit; + +public: + CameraCapWrapper(const std::string& input, + bool loop, + read_type type, + size_t readLengthLimit, + cv::Size cameraResolution) + : ImagesCapture{loop}, + type{type}, + nextImgId{0} { + if (0 == readLengthLimit) { + throw std::runtime_error("readLengthLimit must be positive"); + } + try { + if (cap.open(std::stoi(input))) { + this->readLengthLimit = loop ? std::numeric_limits<size_t>::max() : readLengthLimit; + cap.set(cv::CAP_PROP_BUFFERSIZE, 1); + cap.set(cv::CAP_PROP_FRAME_WIDTH, cameraResolution.width); + cap.set(cv::CAP_PROP_FRAME_HEIGHT, cameraResolution.height); + cap.set(cv::CAP_PROP_AUTOFOCUS, true); + cap.set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('M', 'J', 'P', 'G')); + return; + } + throw OpenError("Can't open the camera from " + input); + } catch (const std::invalid_argument&) { + throw InvalidInput("Can't find the camera " + input); + } catch (const std::out_of_range&) { throw InvalidInput("Can't find the camera " + input); } + } + + double fps() const override { + return cap.get(cv::CAP_PROP_FPS) > 0 ? cap.get(cv::CAP_PROP_FPS) : 30; + } + + std::string getType() const override { + return "CAMERA"; + } + + cv::Mat read() override { + auto startTime = std::chrono::steady_clock::now(); + + if (nextImgId >= readLengthLimit) { + return cv::Mat{}; + } + cv::Mat img; + if (!cap.read(img)) { + throw std::runtime_error("The image can't be captured from the camera"); + } + if (type == read_type::safe) { + img = img.clone(); + } + ++nextImgId; + + readerMetrics.update(startTime); + return img; + } +}; + +std::unique_ptr<ImagesCapture> openImagesCapture(const std::string& input, + bool loop, + read_type type, + size_t initialImageId, + size_t readLengthLimit, + cv::Size cameraResolution + ) { + if (readLengthLimit == 0) + throw std::runtime_error{"Read length limit must be positive"}; + std::vector<std::string> invalidInputs, openErrors; + try { + return std::unique_ptr<ImagesCapture>(new ImreadWrapper{input, loop}); + } catch (const InvalidInput& e) { invalidInputs.push_back(e.what()); } catch (const OpenError& e) { + openErrors.push_back(e.what()); + } + + try { + return std::unique_ptr<ImagesCapture>(new DirReader{input, loop, initialImageId, readLengthLimit}); + } catch (const InvalidInput& e) { invalidInputs.push_back(e.what()); } catch (const OpenError& e) { + openErrors.push_back(e.what()); + } + + try { + return std::unique_ptr<ImagesCapture>(new VideoCapWrapper{input, loop, type, initialImageId, readLengthLimit}); + } catch (const InvalidInput& e) { invalidInputs.push_back(e.what()); } catch (const OpenError& e) { + openErrors.push_back(e.what()); + } + + try { + return std::unique_ptr<ImagesCapture>( + new CameraCapWrapper{input, loop, type, readLengthLimit, cameraResolution}); + } catch (const InvalidInput& e) { invalidInputs.push_back(e.what()); } catch (const OpenError& e) { + openErrors.push_back(e.what()); + } + + std::vector<std::string> errorMessages = openErrors.empty() ? invalidInputs : openErrors; + std::string errorsInfo; + for (const auto& message : errorMessages) { + errorsInfo.append(message + "\n"); + } + throw std::runtime_error(errorsInfo); +} diff --git a/python/openvino/runtime/common/demo_utils/src/kuhn_munkres.cpp b/python/openvino/runtime/common/demo_utils/src/kuhn_munkres.cpp new file mode 100644 index 0000000..7d612c1 --- /dev/null +++ b/python/openvino/runtime/common/demo_utils/src/kuhn_munkres.cpp @@ -0,0 +1,169 @@ +// Copyright (C) 2018-2019 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include <algorithm> +#include <limits> +#include <vector> + +#include <utils/kuhn_munkres.hpp> + +KuhnMunkres::KuhnMunkres(bool greedy) : n_(), greedy_(greedy) {} + +std::vector<size_t> KuhnMunkres::Solve(const cv::Mat& dissimilarity_matrix) { + CV_Assert(dissimilarity_matrix.type() == CV_32F); + double min_val; + cv::minMaxLoc(dissimilarity_matrix, &min_val); + + n_ = std::max(dissimilarity_matrix.rows, dissimilarity_matrix.cols); + dm_ = cv::Mat(n_, n_, CV_32F, cv::Scalar(0)); + marked_ = cv::Mat(n_, n_, CV_8S, cv::Scalar(0)); + points_ = std::vector<cv::Point>(n_ * 2); + + dissimilarity_matrix.copyTo(dm_( + cv::Rect(0, 0, dissimilarity_matrix.cols, dissimilarity_matrix.rows))); + + is_row_visited_ = std::vector<int>(n_, 0); + is_col_visited_ = std::vector<int>(n_, 0); + + Run(); + + std::vector<size_t> results(dissimilarity_matrix.rows, -1); + for (int i = 0; i < dissimilarity_matrix.rows; i++) { + const auto ptr = marked_.ptr<char>(i); + for (int j = 0; j < dissimilarity_matrix.cols; j++) { + if (ptr[j] == kStar) { + results[i] = (size_t)j; + } + } + } + return results; +} + +void KuhnMunkres::TrySimpleCase() { + auto is_row_visited = std::vector<int>(n_, 0); + auto is_col_visited = std::vector<int>(n_, 0); + + for (int row = 0; row < n_; row++) { + auto ptr = dm_.ptr<float>(row); + auto marked_ptr = marked_.ptr<char>(row); + auto min_val = *std::min_element(ptr, ptr + n_); + for (int col = 0; col < n_; col++) { + ptr[col] -= min_val; + if (ptr[col] == 0 && !is_col_visited[col] && !is_row_visited[row]) { + marked_ptr[col] = kStar; + is_col_visited[col] = 1; + is_row_visited[row] = 1; + } + } + } +} + +bool KuhnMunkres::CheckIfOptimumIsFound() { + int count = 0; + for (int i = 0; i < n_; i++) { + const auto marked_ptr = marked_.ptr<char>(i); + for (int j = 0; j < n_; j++) { + if (marked_ptr[j] == kStar) { + is_col_visited_[j] = 1; + count++; + } + } + } + + return count >= n_; +} + +cv::Point KuhnMunkres::FindUncoveredMinValPos() { + auto min_val = std::numeric_limits<float>::max(); + cv::Point min_val_pos(-1, -1); + for (int i = 0; i < n_; i++) { + if (!is_row_visited_[i]) { + auto dm_ptr = dm_.ptr<float>(i); + for (int j = 0; j < n_; j++) { + if (!is_col_visited_[j] && dm_ptr[j] < min_val) { + min_val = dm_ptr[j]; + min_val_pos = cv::Point(j, i); + } + } + } + } + return min_val_pos; +} + +void KuhnMunkres::UpdateDissimilarityMatrix(float val) { + for (int i = 0; i < n_; i++) { + auto dm_ptr = dm_.ptr<float>(i); + for (int j = 0; j < n_; j++) { + if (is_row_visited_[i]) dm_ptr[j] += val; + if (!is_col_visited_[j]) dm_ptr[j] -= val; + } + } +} + +int KuhnMunkres::FindInRow(int row, int what) { + for (int j = 0; j < n_; j++) { + if (marked_.at<char>(row, j) == what) { + return j; + } + } + return -1; +} + +int KuhnMunkres::FindInCol(int col, int what) { + for (int i = 0; i < n_; i++) { + if (marked_.at<char>(i, col) == what) { + return i; + } + } + return -1; +} + +void KuhnMunkres::Run() { + TrySimpleCase(); + if (greedy_) + return; + while (!CheckIfOptimumIsFound()) { + while (true) { + auto point = FindUncoveredMinValPos(); + auto min_val = dm_.at<float>(point.y, point.x); + if (min_val > 0) { + UpdateDissimilarityMatrix(min_val); + } else { + marked_.at<char>(point.y, point.x) = kPrime; + int col = FindInRow(point.y, kStar); + if (col >= 0) { + is_row_visited_[point.y] = 1; + is_col_visited_[col] = 0; + } else { + int count = 0; + points_[count] = point; + + while (true) { + int row = FindInCol(points_[count].x, kStar); + if (row >= 0) { + count++; + points_[count] = cv::Point(points_[count - 1].x, row); + int col = FindInRow(points_[count].y, kPrime); + count++; + points_[count] = cv::Point(col, points_[count - 1].y); + } else { + break; + } + } + + for (int i = 0; i < count + 1; i++) { + auto& mark = marked_.at<char>(points_[i].y, points_[i].x); + mark = mark == kStar ? 0 : kStar; + } + + is_row_visited_ = std::vector<int>(n_, 0); + is_col_visited_ = std::vector<int>(n_, 0); + + marked_.setTo(0, marked_ == kPrime); + break; + } + } + } + } +} diff --git a/python/openvino/runtime/common/demo_utils/src/performance_metrics.cpp b/python/openvino/runtime/common/demo_utils/src/performance_metrics.cpp new file mode 100644 index 0000000..d1e494e --- /dev/null +++ b/python/openvino/runtime/common/demo_utils/src/performance_metrics.cpp @@ -0,0 +1,114 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include <limits> +#include "utils/performance_metrics.hpp" +#include "utils/slog.hpp" + +// timeWindow defines the length of the timespan over which the 'current fps' value is calculated +PerformanceMetrics::PerformanceMetrics(Duration timeWindow) + : timeWindowSize(timeWindow) + , firstFrameProcessed(false) +{} + +void PerformanceMetrics::update(TimePoint lastRequestStartTime, + const cv::Mat& frame, + cv::Point position, + int fontFace, + double fontScale, + cv::Scalar color, + int thickness, + MetricTypes metricType) { + update(lastRequestStartTime); + paintMetrics(frame, position, fontFace, fontScale, color, thickness, metricType); +} + +void PerformanceMetrics::update(TimePoint lastRequestStartTime) { + TimePoint currentTime = Clock::now(); + + if (!firstFrameProcessed) { + lastUpdateTime = lastRequestStartTime; + firstFrameProcessed = true; + } + + currentMovingStatistic.latency += currentTime - lastRequestStartTime; + currentMovingStatistic.period = currentTime - lastUpdateTime; + currentMovingStatistic.frameCount++; + + if (currentTime - lastUpdateTime > timeWindowSize) { + lastMovingStatistic = currentMovingStatistic; + totalStatistic.combine(lastMovingStatistic); + currentMovingStatistic = Statistic(); + + lastUpdateTime = currentTime; + } +} + +void PerformanceMetrics::paintMetrics(const cv::Mat& frame, cv::Point position, int fontFace, + double fontScale, cv::Scalar color, int thickness, MetricTypes metricType) const { + // Draw performance stats over frame + Metrics metrics = getLast(); + + std::ostringstream out; + if (!std::isnan(metrics.latency) && + (metricType == PerformanceMetrics::MetricTypes::LATENCY || metricType == PerformanceMetrics::MetricTypes::ALL)) { + out << "Latency: " << std::fixed << std::setprecision(1) << metrics.latency << " ms"; + putHighlightedText(frame, out.str(), position, fontFace, fontScale, color, thickness); + } + if (!std::isnan(metrics.fps) && + (metricType == PerformanceMetrics::MetricTypes::FPS || metricType == PerformanceMetrics::MetricTypes::ALL)) { + out.str(""); + out << "FPS: " << std::fixed << std::setprecision(1) << metrics.fps; + int offset = metricType == PerformanceMetrics::MetricTypes::ALL ? 30 : 0; + putHighlightedText(frame, out.str(), {position.x, position.y + offset}, fontFace, fontScale, color, thickness); + } +} + +PerformanceMetrics::Metrics PerformanceMetrics::getLast() const { + Metrics metrics; + + metrics.latency = lastMovingStatistic.frameCount != 0 + ? std::chrono::duration_cast<Ms>(lastMovingStatistic.latency).count() + / lastMovingStatistic.frameCount + : std::numeric_limits<double>::signaling_NaN(); + metrics.fps = lastMovingStatistic.period != Duration::zero() + ? lastMovingStatistic.frameCount + / std::chrono::duration_cast<Sec>(lastMovingStatistic.period).count() + : std::numeric_limits<double>::signaling_NaN(); + + return metrics; +} + +PerformanceMetrics::Metrics PerformanceMetrics::getTotal() const { + Metrics metrics; + + int frameCount = totalStatistic.frameCount + currentMovingStatistic.frameCount; + if (frameCount != 0) { + metrics.latency = std::chrono::duration_cast<Ms>( + totalStatistic.latency + currentMovingStatistic.latency).count() / frameCount; + metrics.fps = frameCount / std::chrono::duration_cast<Sec>( + totalStatistic.period + currentMovingStatistic.period).count(); + } else { + metrics.latency = std::numeric_limits<double>::signaling_NaN(); + metrics.fps = std::numeric_limits<double>::signaling_NaN(); + } + + return metrics; +} + +void PerformanceMetrics::logTotal() const { + Metrics metrics = getTotal(); + + slog::info << "\tLatency: " << std::fixed << std::setprecision(1) << metrics.latency << " ms" << slog::endl; + slog::info << "\tFPS: " << metrics.fps << slog::endl; +} + +void logLatencyPerStage(double readLat, double preprocLat, double inferLat, double postprocLat, double renderLat) { + slog::info << "\tDecoding:\t" << std::fixed << std::setprecision(1) << + readLat << " ms" << slog::endl; + slog::info << "\tPreprocessing:\t" << preprocLat << " ms" << slog::endl; + slog::info << "\tInference:\t" << inferLat << " ms" << slog::endl; + slog::info << "\tPostprocessing:\t" << postprocLat << " ms" << slog::endl; + slog::info << "\tRendering:\t" << renderLat << " ms" << slog::endl; +} diff --git a/python/openvino/runtime/common/demo_utils/src/w_dirent.hpp b/python/openvino/runtime/common/demo_utils/src/w_dirent.hpp new file mode 100644 index 0000000..0df8636 --- /dev/null +++ b/python/openvino/runtime/common/demo_utils/src/w_dirent.hpp @@ -0,0 +1,114 @@ +// Copyright (C) 2018-2019 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#if defined(_WIN32) + +#ifndef NOMINMAX +# define NOMINMAX +#endif + +#include <WinSock2.h> +#include <Windows.h> +#include <stdlib.h> + +#else + +#include <unistd.h> +#include <cstdlib> +#include <string.h> + +#endif + +#include <string> + +#include <sys/stat.h> + +#if defined(WIN32) + // Copied from linux libc sys/stat.h: + #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) + #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif + +struct dirent { + char *d_name; + + explicit dirent(const wchar_t *wsFilePath) { + size_t i; + auto slen = wcslen(wsFilePath); + d_name = static_cast<char*>(malloc(slen + 1)); + wcstombs_s(&i, d_name, slen + 1, wsFilePath, slen); + } + + ~dirent() { + free(d_name); + } +}; + +class DIR { + WIN32_FIND_DATAA FindFileData; + HANDLE hFind; + dirent *next; + + static inline bool endsWith(const std::string &src, const char *with) { + int wl = static_cast<int>(strlen(with)); + int so = static_cast<int>(src.length()) - wl; + if (so < 0) return false; + return 0 == strncmp(with, &src[so], wl); + } + +public: + explicit DIR(const char *dirPath) : next(nullptr) { + std::string ws = dirPath; + if (endsWith(ws, "\\")) + ws += "*"; + else + ws += "\\*"; + hFind = FindFirstFileA(ws.c_str(), &FindFileData); + FindFileData.dwReserved0 = hFind != INVALID_HANDLE_VALUE; + } + + ~DIR() { + if (!next) delete next; + FindClose(hFind); + } + + bool isValid() const { + return (hFind != INVALID_HANDLE_VALUE && FindFileData.dwReserved0); + } + + dirent* nextEnt() { + if (next != nullptr) delete next; + next = nullptr; + + if (!FindFileData.dwReserved0) return nullptr; + + wchar_t wbuf[4096]; + + size_t outSize; + mbstowcs_s(&outSize, wbuf, 4094, FindFileData.cFileName, 4094); + next = new dirent(wbuf); + FindFileData.dwReserved0 = FindNextFileA(hFind, &FindFileData); + return next; + } +}; + + +static DIR *opendir(const char* dirPath) { + auto dp = new DIR(dirPath); + if (!dp->isValid()) { + delete dp; + return nullptr; + } + return dp; +} + +static struct dirent *readdir(DIR *dp) { + return dp->nextEnt(); +} + +static void closedir(DIR *dp) { + delete dp; +} |
