Initial setup for CLion
This commit is contained in:
46
engines/OpenVINOEngine/include/utils/args_helper.hpp
Normal file
46
engines/OpenVINOEngine/include/utils/args_helper.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright (C) 2018-2024 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
/**
|
||||
* @brief a header file with common samples functionality
|
||||
* @file args_helper.hpp
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <opencv2/core/types.hpp>
|
||||
#include <openvino/openvino.hpp>
|
||||
|
||||
/**
|
||||
* @brief This function checks input args and existence of specified files in a given folder
|
||||
* @param arg path to a file to be checked for existence
|
||||
* @return files updated vector of verified input files
|
||||
*/
|
||||
void readInputFilesArguments(std::vector<std::string>& files, const std::string& arg);
|
||||
|
||||
/**
|
||||
* @brief This function finds -i/--i key in input args
|
||||
* It's necessary to process multiple values for single key
|
||||
* @return files updated vector of verified input files
|
||||
*/
|
||||
void parseInputFilesArguments(std::vector<std::string>& files);
|
||||
|
||||
std::vector<std::string> split(const std::string& s, char delim);
|
||||
void split(const std::string& s, char delim, std::vector<float> &out);
|
||||
std::string merge(std::initializer_list<std::string> list, const char *delim);
|
||||
std::string merge(const std::vector<std::string> &list, const char *delim);
|
||||
|
||||
std::vector<std::string> parseDevices(const std::string& device_string);
|
||||
|
||||
std::map<std::string, int32_t> parseValuePerDevice(const std::set<std::string>& devices,
|
||||
const std::string& values_string);
|
||||
|
||||
cv::Size stringToSize(const std::string& str);
|
||||
|
||||
std::map<std::string, ov::Layout> parseLayoutString(const std::string& layout_string);
|
||||
155
engines/OpenVINOEngine/include/utils/classification_grid_mat.hpp
Normal file
155
engines/OpenVINOEngine/include/utils/classification_grid_mat.hpp
Normal file
@@ -0,0 +1,155 @@
|
||||
// Copyright (C) 2018-2024 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <opencv2/core.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
|
||||
#include <monitors/presenter.h>
|
||||
#include <utils/ocv_common.hpp>
|
||||
|
||||
#include "utils/performance_metrics.hpp"
|
||||
|
||||
enum class PredictionResult { Correct, Incorrect, Unknown };
|
||||
|
||||
class ClassificationGridMat {
|
||||
public:
|
||||
cv::Mat outImg;
|
||||
|
||||
explicit ClassificationGridMat(Presenter& presenter,
|
||||
const cv::Size maxDisp = cv::Size{1920, 1080},
|
||||
const cv::Size aspectRatio = cv::Size{16, 9},
|
||||
double targetFPS = 60)
|
||||
: currSourceId{0} {
|
||||
cv::Size size(static_cast<int>(std::round(sqrt(1. * targetFPS * aspectRatio.width / aspectRatio.height))),
|
||||
static_cast<int>(std::round(sqrt(1. * targetFPS * aspectRatio.height / aspectRatio.width))));
|
||||
if (size.width == 0 || size.height == 0) {
|
||||
size = {1, 1}; // set minimum possible grid size
|
||||
}
|
||||
int minCellSize = std::min(maxDisp.width / size.width, maxDisp.height / size.height);
|
||||
cellSize = cv::Size(minCellSize, minCellSize);
|
||||
|
||||
for (int i = 0; i < size.height; i++) {
|
||||
for (int j = 0; j < size.width; j++) {
|
||||
points.emplace_back(cellSize.width * j, presenter.graphSize.height + cellSize.height * i);
|
||||
}
|
||||
}
|
||||
|
||||
outImg.create((cellSize.height * size.height) + presenter.graphSize.height,
|
||||
cellSize.width * size.width,
|
||||
CV_8UC3);
|
||||
outImg.setTo(0);
|
||||
|
||||
textSize = cv::getTextSize("", fontType, fontScale, thickness, &baseline);
|
||||
accuracyMessageSize = cv::getTextSize("Accuracy (top 0): 0.000", fontType, fontScale, thickness, &baseline);
|
||||
testMessageSize = cv::getTextSize(ClassificationGridMat::testMessage, fontType, fontScale, thickness, &baseline);
|
||||
}
|
||||
|
||||
void textUpdate(PerformanceMetrics& metrics,
|
||||
PerformanceMetrics::TimePoint lastRequestStartTime,
|
||||
double accuracy,
|
||||
unsigned int nTop,
|
||||
bool isFpsTest,
|
||||
bool showAccuracy,
|
||||
Presenter& presenter) {
|
||||
rectangle(outImg, {0, 0}, {outImg.cols, presenter.graphSize.height}, cv::Scalar(0, 0, 0), cv::FILLED);
|
||||
|
||||
presenter.drawGraphs(outImg);
|
||||
|
||||
metrics.update(lastRequestStartTime,
|
||||
outImg,
|
||||
cv::Point(textPadding, textSize.height + textPadding),
|
||||
fontType,
|
||||
fontScale,
|
||||
cv::Scalar(255, 100, 100),
|
||||
thickness);
|
||||
|
||||
if (showAccuracy) {
|
||||
cv::putText(outImg,
|
||||
cv::format("Accuracy (top %d): %.3f", nTop, accuracy),
|
||||
cv::Point(outImg.cols - accuracyMessageSize.width - textPadding, textSize.height + textPadding),
|
||||
fontType,
|
||||
fontScale,
|
||||
cv::Scalar(255, 255, 255),
|
||||
thickness);
|
||||
}
|
||||
|
||||
if (isFpsTest) {
|
||||
cv::putText(
|
||||
outImg,
|
||||
ClassificationGridMat::testMessage,
|
||||
cv::Point(outImg.cols - testMessageSize.width - textPadding, (textSize.height + textPadding) * 2),
|
||||
fontType,
|
||||
fontScale,
|
||||
cv::Scalar(50, 50, 255),
|
||||
thickness);
|
||||
}
|
||||
}
|
||||
|
||||
void updateMat(const cv::Mat& mat, const std::string& label, PredictionResult predictionResul) {
|
||||
if (!prevImg.empty()) {
|
||||
size_t prevSourceId = currSourceId - 1;
|
||||
prevSourceId = std::min(prevSourceId, points.size() - 1);
|
||||
prevImg.copyTo(outImg(cv::Rect(points[prevSourceId], cellSize)));
|
||||
}
|
||||
cv::Scalar textColor;
|
||||
switch (predictionResul) {
|
||||
case PredictionResult::Correct:
|
||||
textColor = cv::Scalar(75, 255, 75); // green
|
||||
break;
|
||||
case PredictionResult::Incorrect:
|
||||
textColor = cv::Scalar(50, 50, 255); // red
|
||||
break;
|
||||
case PredictionResult::Unknown:
|
||||
textColor = cv::Scalar(200, 10, 10); // blue
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Undefined type of prediction result");
|
||||
}
|
||||
int labelThickness = cellSize.width / 20;
|
||||
cv::Size labelTextSize = cv::getTextSize(label, fontType, 1, 2, &baseline);
|
||||
double labelFontScale = static_cast<double>(cellSize.width - 2 * labelThickness) / labelTextSize.width;
|
||||
cv::resize(mat, prevImg, cellSize);
|
||||
putHighlightedText(prevImg,
|
||||
label,
|
||||
cv::Point(labelThickness, cellSize.height - labelThickness - labelTextSize.height),
|
||||
fontType,
|
||||
labelFontScale,
|
||||
textColor,
|
||||
2);
|
||||
cv::Mat cell = outImg(cv::Rect(points[currSourceId], cellSize));
|
||||
prevImg.copyTo(cell);
|
||||
cv::rectangle(cell, {0, 0}, {cell.cols, cell.rows}, {255, 50, 50}, labelThickness); // draw a border
|
||||
|
||||
if (currSourceId == points.size() - 1) {
|
||||
currSourceId = 0;
|
||||
} else {
|
||||
currSourceId++;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
cv::Mat prevImg;
|
||||
cv::Size cellSize;
|
||||
size_t currSourceId;
|
||||
std::vector<cv::Point> points;
|
||||
static const int fontType = cv::FONT_HERSHEY_PLAIN;
|
||||
static constexpr double fontScale = 1.5;
|
||||
static const int thickness = 2;
|
||||
static const int textPadding = 10;
|
||||
static constexpr const char testMessage[] = "Testing, please wait...";
|
||||
int baseline;
|
||||
cv::Size textSize;
|
||||
cv::Size accuracyMessageSize;
|
||||
cv::Size testMessageSize;
|
||||
};
|
||||
|
||||
constexpr const char ClassificationGridMat::testMessage[];
|
||||
193
engines/OpenVINOEngine/include/utils/common.hpp
Normal file
193
engines/OpenVINOEngine/include/utils/common.hpp
Normal file
@@ -0,0 +1,193 @@
|
||||
// Copyright (C) 2018-2024 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
/**
|
||||
* @brief a header file with common samples functionality
|
||||
* @file common.hpp
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <openvino/openvino.hpp>
|
||||
#include "utils/slog.hpp"
|
||||
#include "utils/args_helper.hpp"
|
||||
|
||||
#ifndef UNUSED
|
||||
#ifdef _WIN32
|
||||
#define UNUSED
|
||||
#else
|
||||
#define UNUSED __attribute__((unused))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
constexpr std::size_t arraySize(const T(&)[N]) noexcept {
|
||||
return N;
|
||||
}
|
||||
|
||||
static inline void catcher() noexcept {
|
||||
if (std::current_exception()) {
|
||||
try {
|
||||
std::rethrow_exception(std::current_exception());
|
||||
} catch (const std::exception& error) {
|
||||
slog::err << error.what() << slog::endl;
|
||||
} catch (...) {
|
||||
slog::err << "Non-exception object thrown" << slog::endl;
|
||||
}
|
||||
std::exit(1);
|
||||
}
|
||||
std::abort();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T clamp(T value, T low, T high) {
|
||||
return value < low ? low : (value > high ? high : value);
|
||||
}
|
||||
|
||||
inline slog::LogStream& operator<<(slog::LogStream& os, const ov::Version& version) {
|
||||
return os << "OpenVINO" << slog::endl
|
||||
<< "\tversion: " << OPENVINO_VERSION_MAJOR << "." << OPENVINO_VERSION_MINOR << "." << OPENVINO_VERSION_PATCH << slog::endl
|
||||
<< "\tbuild: " << version.buildNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* @class Color
|
||||
* @brief A Color class stores channels of a given color
|
||||
*/
|
||||
class Color {
|
||||
private:
|
||||
unsigned char _r;
|
||||
unsigned char _g;
|
||||
unsigned char _b;
|
||||
|
||||
public:
|
||||
/**
|
||||
* A default constructor.
|
||||
* @param r - value for red channel
|
||||
* @param g - value for green channel
|
||||
* @param b - value for blue channel
|
||||
*/
|
||||
Color(unsigned char r,
|
||||
unsigned char g,
|
||||
unsigned char b) : _r(r), _g(g), _b(b) {}
|
||||
|
||||
inline unsigned char red() const {
|
||||
return _r;
|
||||
}
|
||||
|
||||
inline unsigned char blue() const {
|
||||
return _b;
|
||||
}
|
||||
|
||||
inline unsigned char green() const {
|
||||
return _g;
|
||||
}
|
||||
};
|
||||
|
||||
// Known colors for training classes from the Cityscapes dataset
|
||||
static UNUSED const Color CITYSCAPES_COLORS[] = {
|
||||
{ 128, 64, 128 },
|
||||
{ 232, 35, 244 },
|
||||
{ 70, 70, 70 },
|
||||
{ 156, 102, 102 },
|
||||
{ 153, 153, 190 },
|
||||
{ 153, 153, 153 },
|
||||
{ 30, 170, 250 },
|
||||
{ 0, 220, 220 },
|
||||
{ 35, 142, 107 },
|
||||
{ 152, 251, 152 },
|
||||
{ 180, 130, 70 },
|
||||
{ 60, 20, 220 },
|
||||
{ 0, 0, 255 },
|
||||
{ 142, 0, 0 },
|
||||
{ 70, 0, 0 },
|
||||
{ 100, 60, 0 },
|
||||
{ 90, 0, 0 },
|
||||
{ 230, 0, 0 },
|
||||
{ 32, 11, 119 },
|
||||
{ 0, 74, 111 },
|
||||
{ 81, 0, 81 }
|
||||
};
|
||||
|
||||
inline void showAvailableDevices() {
|
||||
ov::Core core;
|
||||
std::vector<std::string> devices = core.get_available_devices();
|
||||
|
||||
std::cout << "Available devices:";
|
||||
for (const auto& device : devices) {
|
||||
std::cout << ' ' << device;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
inline std::string fileNameNoExt(const std::string& filepath) {
|
||||
auto pos = filepath.rfind('.');
|
||||
if (pos == std::string::npos) return filepath;
|
||||
return filepath.substr(0, pos);
|
||||
}
|
||||
|
||||
inline void logCompiledModelInfo(
|
||||
const ov::CompiledModel& compiledModel,
|
||||
const std::string& modelName,
|
||||
const std::string& deviceName,
|
||||
const std::string& modelType = "") {
|
||||
slog::info << "The " << modelType << (modelType.empty() ? "" : " ") << "model " << modelName << " is loaded to " << deviceName << slog::endl;
|
||||
std::set<std::string> devices;
|
||||
for (const std::string& device : parseDevices(deviceName)) {
|
||||
devices.insert(device);
|
||||
}
|
||||
|
||||
if (devices.find("AUTO") == devices.end()) { // do not print info for AUTO device
|
||||
for (const auto& device : devices) {
|
||||
try {
|
||||
slog::info << "\tDevice: " << device << slog::endl;
|
||||
int32_t nstreams = compiledModel.get_property(ov::streams::num);
|
||||
slog::info << "\t\tNumber of streams: " << nstreams << slog::endl;
|
||||
if (device == "CPU") {
|
||||
int32_t nthreads = compiledModel.get_property(ov::inference_num_threads);
|
||||
slog::info << "\t\tNumber of threads: " << (nthreads == 0 ? "AUTO" : std::to_string(nthreads)) << slog::endl;
|
||||
}
|
||||
}
|
||||
catch (const ov::Exception&) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void logBasicModelInfo(const std::shared_ptr<ov::Model>& model) {
|
||||
slog::info << "Model name: " << model->get_friendly_name() << slog::endl;
|
||||
|
||||
// Dump information about model inputs/outputs
|
||||
ov::OutputVector inputs = model->inputs();
|
||||
ov::OutputVector outputs = model->outputs();
|
||||
|
||||
slog::info << "\tInputs: " << slog::endl;
|
||||
for (const ov::Output<ov::Node>& input : inputs) {
|
||||
const std::string name = input.get_any_name();
|
||||
const ov::element::Type type = input.get_element_type();
|
||||
const ov::PartialShape shape = input.get_partial_shape();
|
||||
const ov::Layout layout = ov::layout::get_layout(input);
|
||||
|
||||
slog::info << "\t\t" << name << ", " << type << ", " << shape << ", " << layout.to_string() << slog::endl;
|
||||
}
|
||||
|
||||
slog::info << "\tOutputs: " << slog::endl;
|
||||
for (const ov::Output<ov::Node>& output : outputs) {
|
||||
const std::string name = output.get_any_name();
|
||||
const ov::element::Type type = output.get_element_type();
|
||||
const ov::PartialShape shape = output.get_partial_shape();
|
||||
const ov::Layout layout = ov::layout::get_layout(output);
|
||||
|
||||
slog::info << "\t\t" << name << ", " << type << ", " << shape << ", " << layout.to_string() << slog::endl;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<unsigned> loadClassIndices(const std::string &groundtruth_filepath,
|
||||
const std::vector<std::string> &imageNames);
|
||||
50
engines/OpenVINOEngine/include/utils/config_factory.h
Normal file
50
engines/OpenVINOEngine/include/utils/config_factory.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
// Copyright (C) 2020-2024 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include <openvino/openvino.hpp>
|
||||
|
||||
struct ModelConfig {
|
||||
std::string deviceName;
|
||||
std::string cpuExtensionsPath;
|
||||
std::string clKernelsConfigPath;
|
||||
unsigned int maxAsyncRequests;
|
||||
ov::AnyMap compiledModelConfig;
|
||||
|
||||
std::set<std::string> getDevices();
|
||||
std::map<std::string, std::string> getLegacyConfig() const;
|
||||
|
||||
protected:
|
||||
std::set<std::string> devices;
|
||||
};
|
||||
|
||||
class ConfigFactory {
|
||||
public:
|
||||
static ModelConfig getUserConfig(const std::string& flags_d,
|
||||
uint32_t flags_nireq,
|
||||
const std::string& flags_nstreams,
|
||||
uint32_t flags_nthreads);
|
||||
static ModelConfig getMinLatencyConfig(const std::string& flags_d, uint32_t flags_nireq);
|
||||
|
||||
protected:
|
||||
static ModelConfig getCommonConfig(const std::string& flags_d, uint32_t flags_nireq);
|
||||
};
|
||||
21
engines/OpenVINOEngine/include/utils/default_flags.hpp
Normal file
21
engines/OpenVINOEngine/include/utils/default_flags.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright (C) 2020-2024 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
|
||||
#define DEFINE_INPUT_FLAGS \
|
||||
DEFINE_string(i, "", input_message); \
|
||||
DEFINE_bool(loop, false, loop_message);
|
||||
|
||||
#define DEFINE_OUTPUT_FLAGS \
|
||||
DEFINE_string(o, "", output_message); \
|
||||
DEFINE_uint32(limit, 1000, limit_message);
|
||||
|
||||
static const char input_message[] = "Required. An input to process. The input must be a single image, a folder of "
|
||||
"images, video file or camera id.";
|
||||
static const char loop_message[] = "Optional. Enable reading the input in a loop.";
|
||||
static const char output_message[] = "Optional. Name of the output file(s) to save. Frames of odd width or height can be truncated. See https://github.com/opencv/opencv/pull/24086";
|
||||
static const char limit_message[] = "Optional. Number of frames to store in output. If 0 is set, all frames are stored.";
|
||||
127
engines/OpenVINOEngine/include/utils/grid_mat.hpp
Normal file
127
engines/OpenVINOEngine/include/utils/grid_mat.hpp
Normal file
@@ -0,0 +1,127 @@
|
||||
// Copyright (C) 2018-2024 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <opencv2/core/core.hpp>
|
||||
|
||||
class GridMat {
|
||||
public:
|
||||
cv::Mat outimg;
|
||||
|
||||
explicit GridMat(const std::vector<cv::Size>& sizes, const cv::Size maxDisp = cv::Size{1920, 1080}) {
|
||||
size_t maxWidth = 0;
|
||||
size_t maxHeight = 0;
|
||||
for (size_t i = 0; i < sizes.size(); i++) {
|
||||
maxWidth = std::max(maxWidth, static_cast<size_t>(sizes[i].width));
|
||||
maxHeight = std::max(maxHeight, static_cast<size_t>(sizes[i].height));
|
||||
}
|
||||
if (0 == maxWidth || 0 == maxHeight) {
|
||||
throw std::invalid_argument("Input resolution must not be zero.");
|
||||
}
|
||||
|
||||
size_t nGridCols = static_cast<size_t>(ceil(sqrt(static_cast<float>(sizes.size()))));
|
||||
size_t nGridRows = (sizes.size() - 1) / nGridCols + 1;
|
||||
size_t gridMaxWidth = static_cast<size_t>(maxDisp.width/nGridCols);
|
||||
size_t gridMaxHeight = static_cast<size_t>(maxDisp.height/nGridRows);
|
||||
|
||||
float scaleWidth = static_cast<float>(gridMaxWidth) / maxWidth;
|
||||
float scaleHeight = static_cast<float>(gridMaxHeight) / maxHeight;
|
||||
float scaleFactor = std::min(1.f, std::min(scaleWidth, scaleHeight));
|
||||
|
||||
cellSize.width = static_cast<int>(maxWidth * scaleFactor);
|
||||
cellSize.height = static_cast<int>(maxHeight * scaleFactor);
|
||||
|
||||
for (size_t i = 0; i < sizes.size(); i++) {
|
||||
cv::Point p;
|
||||
p.x = cellSize.width * (i % nGridCols);
|
||||
p.y = cellSize.height * (i / nGridCols);
|
||||
points.push_back(p);
|
||||
}
|
||||
|
||||
outimg.create(cellSize.height * nGridRows, cellSize.width * nGridCols, CV_8UC3);
|
||||
outimg.setTo(0);
|
||||
clear();
|
||||
}
|
||||
|
||||
cv::Size getCellSize() {
|
||||
return cellSize;
|
||||
}
|
||||
|
||||
void fill(std::vector<cv::Mat>& frames) {
|
||||
if (frames.size() > points.size()) {
|
||||
throw std::logic_error("Cannot display " + std::to_string(frames.size()) + " channels in a grid with " + std::to_string(points.size()) + " cells");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < frames.size(); i++) {
|
||||
cv::Mat cell = outimg(cv::Rect(points[i].x, points[i].y, cellSize.width, cellSize.height));
|
||||
|
||||
if ((cellSize.width == frames[i].cols) && (cellSize.height == frames[i].rows)) {
|
||||
frames[i].copyTo(cell);
|
||||
} else if ((cellSize.width > frames[i].cols) && (cellSize.height > frames[i].rows)) {
|
||||
frames[i].copyTo(cell(cv::Rect(0, 0, frames[i].cols, frames[i].rows)));
|
||||
} else {
|
||||
cv::resize(frames[i], cell, cellSize);
|
||||
}
|
||||
}
|
||||
unupdatedSourceIDs.clear();
|
||||
}
|
||||
|
||||
void update(const cv::Mat& frame, const size_t sourceID) {
|
||||
const cv::Mat& cell = outimg(cv::Rect(points[sourceID], cellSize));
|
||||
|
||||
if ((cellSize.width == frame.cols) && (cellSize.height == frame.rows)) {
|
||||
frame.copyTo(cell);
|
||||
} else if ((cellSize.width > frame.cols) && (cellSize.height > frame.rows)) {
|
||||
frame.copyTo(cell(cv::Rect(0, 0, frame.cols, frame.rows)));
|
||||
} else {
|
||||
cv::resize(frame, cell, cellSize);
|
||||
}
|
||||
unupdatedSourceIDs.erase(unupdatedSourceIDs.find(sourceID));
|
||||
}
|
||||
|
||||
bool isFilled() const noexcept {
|
||||
return unupdatedSourceIDs.empty();
|
||||
}
|
||||
void clear() {
|
||||
size_t counter = 0;
|
||||
std::generate_n(std::inserter(unupdatedSourceIDs, unupdatedSourceIDs.end()), points.size(), [&counter]{return counter++;});
|
||||
}
|
||||
std::set<size_t> getUnupdatedSourceIDs() const noexcept {
|
||||
return unupdatedSourceIDs;
|
||||
}
|
||||
cv::Mat getMat() const noexcept {
|
||||
return outimg;
|
||||
}
|
||||
|
||||
private:
|
||||
cv::Size cellSize;
|
||||
std::set<size_t> unupdatedSourceIDs;
|
||||
std::vector<cv::Point> points;
|
||||
};
|
||||
|
||||
//void fillROIColor(cv::Mat& displayImage, cv::Rect roi, cv::Scalar color, double opacity) {
|
||||
// if (opacity > 0) {
|
||||
// roi = roi & cv::Rect(0, 0, displayImage.cols, displayImage.rows);
|
||||
// cv::Mat textROI = displayImage(roi);
|
||||
// cv::addWeighted(color, opacity, textROI, 1.0 - opacity , 0.0, textROI);
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//void putTextOnImage(cv::Mat& displayImage, std::string str, cv::Point p,
|
||||
// cv::HersheyFonts font, double fontScale, cv::Scalar color,
|
||||
// int thickness = 1, cv::Scalar bgcolor = cv::Scalar(),
|
||||
// double opacity = 0) {
|
||||
// int baseline = 0;
|
||||
// cv::Size textSize = cv::getTextSize(str, font, 0.5, 1, &baseline);
|
||||
// fillROIColor(displayImage, cv::Rect(cv::Point(p.x, p.y + baseline),
|
||||
// cv::Point(p.x + textSize.width, p.y - textSize.height)),
|
||||
// bgcolor, opacity);
|
||||
// cv::putText(displayImage, str, p, font, fontScale, color, thickness);
|
||||
//}
|
||||
29
engines/OpenVINOEngine/include/utils/image_utils.h
Normal file
29
engines/OpenVINOEngine/include/utils/image_utils.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
// Copyright (C) 2021-2024 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
enum RESIZE_MODE {
|
||||
RESIZE_FILL,
|
||||
RESIZE_KEEP_ASPECT,
|
||||
RESIZE_KEEP_ASPECT_LETTERBOX
|
||||
};
|
||||
|
||||
cv::Mat resizeImageExt(const cv::Mat& mat, int width, int height, RESIZE_MODE resizeMode = RESIZE_FILL,
|
||||
cv::InterpolationFlags interpolationMode = cv::INTER_LINEAR, cv::Rect* roi = nullptr,
|
||||
cv::Scalar BorderConstant = cv::Scalar(0, 0, 0));
|
||||
52
engines/OpenVINOEngine/include/utils/images_capture.h
Normal file
52
engines/OpenVINOEngine/include/utils/images_capture.h
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright (C) 2020-2024 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <stddef.h>
|
||||
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <opencv2/core.hpp>
|
||||
|
||||
#include "utils/performance_metrics.hpp"
|
||||
|
||||
enum class read_type { efficient, safe };
|
||||
|
||||
class ImagesCapture {
|
||||
public:
|
||||
const bool loop;
|
||||
|
||||
ImagesCapture(bool loop) : loop{loop} {}
|
||||
virtual double fps() const = 0;
|
||||
virtual cv::Mat read() = 0;
|
||||
virtual std::string getType() const = 0;
|
||||
const PerformanceMetrics& getMetrics() {
|
||||
return readerMetrics;
|
||||
}
|
||||
virtual ~ImagesCapture() = default;
|
||||
|
||||
protected:
|
||||
PerformanceMetrics readerMetrics;
|
||||
};
|
||||
|
||||
// An advanced version of
|
||||
// try {
|
||||
// return cv::VideoCapture(std::stoi(input));
|
||||
// } catch (const std::invalid_argument&) {
|
||||
// return cv::VideoCapture(input);
|
||||
// } catch (const std::out_of_range&) {
|
||||
// return cv::VideoCapture(input);
|
||||
// }
|
||||
// Some VideoCapture backends continue owning the video buffer under cv::Mat. safe_copy forses to return a copy from
|
||||
// read()
|
||||
// https://github.com/opencv/opencv/blob/46e1560678dba83d25d309d8fbce01c40f21b7be/modules/gapi/include/opencv2/gapi/streaming/cap.hpp#L72-L76
|
||||
std::unique_ptr<ImagesCapture> openImagesCapture(
|
||||
const std::string& input,
|
||||
bool loop,
|
||||
read_type type = read_type::efficient,
|
||||
size_t initialImageId = 0,
|
||||
size_t readLengthLimit = std::numeric_limits<size_t>::max(), // General option
|
||||
cv::Size cameraResolution = {1280, 720});
|
||||
149
engines/OpenVINOEngine/include/utils/input_wrappers.hpp
Normal file
149
engines/OpenVINOEngine/include/utils/input_wrappers.hpp
Normal file
@@ -0,0 +1,149 @@
|
||||
// Copyright (C) 2018-2024 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
class InputChannel;
|
||||
|
||||
class IInputSource {
|
||||
public:
|
||||
virtual bool read(cv::Mat& mat, const std::shared_ptr<InputChannel>& caller) = 0;
|
||||
virtual void addSubscriber(const std::weak_ptr<InputChannel>& inputChannel) = 0;
|
||||
virtual cv::Size getSize() = 0;
|
||||
virtual void lock() {
|
||||
sourceLock.lock();
|
||||
}
|
||||
virtual void unlock() {
|
||||
sourceLock.unlock();
|
||||
}
|
||||
virtual ~IInputSource() = default;
|
||||
private:
|
||||
std::mutex sourceLock;
|
||||
};
|
||||
|
||||
class InputChannel: public std::enable_shared_from_this<InputChannel> { // note: public inheritance
|
||||
public:
|
||||
InputChannel(const InputChannel&) = delete;
|
||||
InputChannel& operator=(const InputChannel&) = delete;
|
||||
static std::shared_ptr<InputChannel> create(const std::shared_ptr<IInputSource>& source) {
|
||||
auto tmp = std::shared_ptr<InputChannel>(new InputChannel(source));
|
||||
source->addSubscriber(tmp);
|
||||
return tmp;
|
||||
}
|
||||
bool read(cv::Mat& mat) {
|
||||
readQueueMutex.lock();
|
||||
if (readQueue.empty()) {
|
||||
readQueueMutex.unlock();
|
||||
source->lock();
|
||||
readQueueMutex.lock();
|
||||
if (readQueue.empty()) {
|
||||
bool res = source->read(mat, shared_from_this());
|
||||
readQueueMutex.unlock();
|
||||
source->unlock();
|
||||
return res;
|
||||
} else {
|
||||
source->unlock();
|
||||
}
|
||||
}
|
||||
mat = readQueue.front().clone();
|
||||
readQueue.pop();
|
||||
readQueueMutex.unlock();
|
||||
return true;
|
||||
}
|
||||
void push(const cv::Mat& mat) {
|
||||
readQueueMutex.lock();
|
||||
readQueue.push(mat);
|
||||
readQueueMutex.unlock();
|
||||
}
|
||||
cv::Size getSize() {
|
||||
return source->getSize();
|
||||
}
|
||||
|
||||
private:
|
||||
explicit InputChannel(const std::shared_ptr<IInputSource>& source): source{source} {}
|
||||
std::shared_ptr<IInputSource> source;
|
||||
std::queue<cv::Mat, std::list<cv::Mat>> readQueue;
|
||||
std::mutex readQueueMutex;
|
||||
};
|
||||
|
||||
class VideoCaptureSource: public IInputSource {
|
||||
public:
|
||||
VideoCaptureSource(const cv::VideoCapture& videoCapture, bool loop): videoCapture{videoCapture}, loop{loop},
|
||||
imSize{static_cast<int>(videoCapture.get(cv::CAP_PROP_FRAME_WIDTH)), static_cast<int>(videoCapture.get(cv::CAP_PROP_FRAME_HEIGHT))} {}
|
||||
bool read(cv::Mat& mat, const std::shared_ptr<InputChannel>& caller) override {
|
||||
if (!videoCapture.read(mat)) {
|
||||
if (loop) {
|
||||
videoCapture.set(cv::CAP_PROP_POS_FRAMES, 0);
|
||||
videoCapture.read(mat);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (1 != subscribedInputChannels.size()) {
|
||||
cv::Mat shared = mat.clone();
|
||||
for (const std::weak_ptr<InputChannel>& weakInputChannel : subscribedInputChannels) {
|
||||
try {
|
||||
std::shared_ptr<InputChannel> sharedInputChannel = std::shared_ptr<InputChannel>(weakInputChannel);
|
||||
if (caller != sharedInputChannel) {
|
||||
sharedInputChannel->push(shared);
|
||||
}
|
||||
} catch (const std::bad_weak_ptr&) {}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void addSubscriber(const std::weak_ptr<InputChannel>& inputChannel) override {
|
||||
subscribedInputChannels.push_back(inputChannel);
|
||||
}
|
||||
cv::Size getSize() override {
|
||||
return imSize;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::weak_ptr<InputChannel>> subscribedInputChannels;
|
||||
cv::VideoCapture videoCapture;
|
||||
bool loop;
|
||||
cv::Size imSize;
|
||||
};
|
||||
|
||||
class ImageSource: public IInputSource {
|
||||
public:
|
||||
ImageSource(const cv::Mat& im, bool loop): im{im.clone()}, loop{loop} {} // clone to avoid image changing
|
||||
bool read(cv::Mat& mat, const std::shared_ptr<InputChannel>& caller) override {
|
||||
if (!loop) {
|
||||
auto subscribedInputChannelsIt = subscribedInputChannels.find(caller);
|
||||
if (subscribedInputChannels.end() == subscribedInputChannelsIt) {
|
||||
return false;
|
||||
} else {
|
||||
subscribedInputChannels.erase(subscribedInputChannelsIt);
|
||||
mat = im;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
mat = im;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
void addSubscriber(const std::weak_ptr<InputChannel>& inputChannel) override {
|
||||
if (false == subscribedInputChannels.insert(inputChannel).second)
|
||||
throw std::invalid_argument("The insertion did not take place");
|
||||
}
|
||||
cv::Size getSize() override {
|
||||
return im.size();
|
||||
}
|
||||
|
||||
private:
|
||||
std::set<std::weak_ptr<InputChannel>, std::owner_less<std::weak_ptr<InputChannel>>> subscribedInputChannels;
|
||||
cv::Mat im;
|
||||
bool loop;
|
||||
};
|
||||
57
engines/OpenVINOEngine/include/utils/kuhn_munkres.hpp
Normal file
57
engines/OpenVINOEngine/include/utils/kuhn_munkres.hpp
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright (C) 2018-2024 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "opencv2/core.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
|
||||
///
|
||||
/// \brief The KuhnMunkres class
|
||||
///
|
||||
/// Solves the assignment problem.
|
||||
///
|
||||
class KuhnMunkres {
|
||||
public:
|
||||
///
|
||||
/// \brief Initializes the class for assignment problem solving.
|
||||
/// \param[in] greedy If a faster greedy matching algorithm should be used.
|
||||
explicit KuhnMunkres(bool greedy = false);
|
||||
|
||||
///
|
||||
/// \brief Solves the assignment problem for given dissimilarity matrix.
|
||||
/// It returns a vector that where each element is a column index for
|
||||
/// corresponding row (e.g. result[0] stores optimal column index for very
|
||||
/// first row in the dissimilarity matrix).
|
||||
/// \param dissimilarity_matrix CV_32F dissimilarity matrix.
|
||||
/// \return Optimal column index for each row. -1 means that there is no
|
||||
/// column for row.
|
||||
///
|
||||
std::vector<size_t> Solve(const cv::Mat &dissimilarity_matrix);
|
||||
|
||||
private:
|
||||
static constexpr int kStar = 1;
|
||||
static constexpr int kPrime = 2;
|
||||
|
||||
cv::Mat dm_;
|
||||
cv::Mat marked_;
|
||||
std::vector<cv::Point> points_;
|
||||
|
||||
std::vector<int> is_row_visited_;
|
||||
std::vector<int> is_col_visited_;
|
||||
|
||||
int n_;
|
||||
bool greedy_;
|
||||
|
||||
void TrySimpleCase();
|
||||
bool CheckIfOptimumIsFound();
|
||||
cv::Point FindUncoveredMinValPos();
|
||||
void UpdateDissimilarityMatrix(float val);
|
||||
int FindInRow(int row, int what);
|
||||
int FindInCol(int col, int what);
|
||||
void Run();
|
||||
};
|
||||
81
engines/OpenVINOEngine/include/utils/nms.hpp
Normal file
81
engines/OpenVINOEngine/include/utils/nms.hpp
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
// Copyright (C) 2021-2024 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "opencv2/core.hpp"
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
|
||||
struct Anchor {
|
||||
float left;
|
||||
float top;
|
||||
float right;
|
||||
float bottom;
|
||||
|
||||
float getWidth() const {
|
||||
return (right - left) + 1.0f;
|
||||
}
|
||||
float getHeight() const {
|
||||
return (bottom - top) + 1.0f;
|
||||
}
|
||||
float getXCenter() const {
|
||||
return left + (getWidth() - 1.0f) / 2.0f;
|
||||
}
|
||||
float getYCenter() const {
|
||||
return top + (getHeight() - 1.0f) / 2.0f;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Anchor>
|
||||
std::vector<int> nms(const std::vector<Anchor>& boxes, const std::vector<float>& scores,
|
||||
const float thresh, bool includeBoundaries=false) {
|
||||
std::vector<float> areas(boxes.size());
|
||||
for (size_t i = 0; i < boxes.size(); ++i) {
|
||||
areas[i] = (boxes[i].right - boxes[i].left + includeBoundaries) * (boxes[i].bottom - boxes[i].top + includeBoundaries);
|
||||
}
|
||||
std::vector<int> order(scores.size());
|
||||
std::iota(order.begin(), order.end(), 0);
|
||||
std::sort(order.begin(), order.end(), [&scores](int o1, int o2) { return scores[o1] > scores[o2]; });
|
||||
|
||||
size_t ordersNum = 0;
|
||||
for (; ordersNum < order.size() && scores[order[ordersNum]] >= 0; ordersNum++);
|
||||
|
||||
std::vector<int> keep;
|
||||
bool shouldContinue = true;
|
||||
for (size_t i = 0; shouldContinue && i < ordersNum; ++i) {
|
||||
auto idx1 = order[i];
|
||||
if (idx1 >= 0) {
|
||||
keep.push_back(idx1);
|
||||
shouldContinue = false;
|
||||
for (size_t j = i + 1; j < ordersNum; ++j) {
|
||||
auto idx2 = order[j];
|
||||
if (idx2 >= 0) {
|
||||
shouldContinue = true;
|
||||
auto overlappingWidth = std::fminf(boxes[idx1].right, boxes[idx2].right) - std::fmaxf(boxes[idx1].left, boxes[idx2].left);
|
||||
auto overlappingHeight = std::fminf(boxes[idx1].bottom, boxes[idx2].bottom) - std::fmaxf(boxes[idx1].top, boxes[idx2].top);
|
||||
auto intersection = overlappingWidth > 0 && overlappingHeight > 0 ? overlappingWidth * overlappingHeight : 0;
|
||||
auto overlap = intersection / (areas[idx1] + areas[idx2] - intersection);
|
||||
|
||||
if (overlap >= thresh) {
|
||||
order[j] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return keep;
|
||||
}
|
||||
347
engines/OpenVINOEngine/include/utils/ocv_common.hpp
Normal file
347
engines/OpenVINOEngine/include/utils/ocv_common.hpp
Normal file
@@ -0,0 +1,347 @@
|
||||
// Copyright (C) 2018-2024 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
/**
|
||||
* @brief a header file with common samples functionality using OpenCV
|
||||
* @file ocv_common.hpp
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <openvino/openvino.hpp>
|
||||
|
||||
#include "utils/common.hpp"
|
||||
#include "utils/shared_tensor_allocator.hpp"
|
||||
|
||||
/**
|
||||
* @brief Get cv::Mat value in the correct format.
|
||||
*/
|
||||
template <typename T>
|
||||
const T getMatValue(const cv::Mat& mat, size_t h, size_t w, size_t c) {
|
||||
switch (mat.type()) {
|
||||
case CV_8UC1: return (T)mat.at<uchar>((int)h, (int)w);
|
||||
case CV_8UC3: return (T)mat.at<cv::Vec3b>((int)h, (int)w)[c];
|
||||
case CV_32FC1: return (T)mat.at<float>((int)h, (int)w);
|
||||
case CV_32FC3: return (T)mat.at<cv::Vec3f>((int)h, (int)w)[c];
|
||||
}
|
||||
throw std::runtime_error("cv::Mat type is not recognized");
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Resize and copy image data from cv::Mat object to a given Tensor object.
|
||||
* @param mat - given cv::Mat object with an image data.
|
||||
* @param tensor - Tensor object which to be filled by an image data.
|
||||
* @param batchIndex - batch index of an image inside of the blob.
|
||||
*/
|
||||
static UNUSED void matToTensor(const cv::Mat& mat, ov::Tensor& tensor, int batchIndex = 0) {
|
||||
ov::Shape tensorShape = tensor.get_shape();
|
||||
static const ov::Layout layout("NCHW");
|
||||
const size_t width = tensorShape[ov::layout::width_idx(layout)];
|
||||
const size_t height = tensorShape[ov::layout::height_idx(layout)];
|
||||
const size_t channels = tensorShape[ov::layout::channels_idx(layout)];
|
||||
if (static_cast<size_t>(mat.channels()) != channels) {
|
||||
throw std::runtime_error("The number of channels for model input and image must match");
|
||||
}
|
||||
if (channels != 1 && channels != 3) {
|
||||
throw std::runtime_error("Unsupported number of channels");
|
||||
}
|
||||
int batchOffset = batchIndex * width * height * channels;
|
||||
|
||||
cv::Mat resizedMat;
|
||||
if (static_cast<int>(width) != mat.size().width || static_cast<int>(height) != mat.size().height) {
|
||||
cv::resize(mat, resizedMat, cv::Size(width, height));
|
||||
} else {
|
||||
resizedMat = mat;
|
||||
}
|
||||
|
||||
if (tensor.get_element_type() == ov::element::f32) {
|
||||
float_t* tensorData = tensor.data<float_t>();
|
||||
for (size_t c = 0; c < channels; c++)
|
||||
for (size_t h = 0; h < height; h++)
|
||||
for (size_t w = 0; w < width; w++)
|
||||
tensorData[batchOffset + c * width * height + h * width + w] =
|
||||
getMatValue<float_t>(resizedMat, h, w, c);
|
||||
} else {
|
||||
uint8_t* tensorData = tensor.data<uint8_t>();
|
||||
if (resizedMat.depth() == CV_32F) {
|
||||
throw std::runtime_error("Conversion of cv::Mat from float_t to uint8_t is forbidden");
|
||||
}
|
||||
for (size_t c = 0; c < channels; c++)
|
||||
for (size_t h = 0; h < height; h++)
|
||||
for (size_t w = 0; w < width; w++)
|
||||
tensorData[batchOffset + c * width * height + h * width + w] =
|
||||
getMatValue<uint8_t>(resizedMat, h, w, c);
|
||||
}
|
||||
}
|
||||
|
||||
static UNUSED ov::Tensor wrapMat2Tensor(const cv::Mat& mat) {
|
||||
auto matType = mat.type() & CV_MAT_DEPTH_MASK;
|
||||
if (matType != CV_8U && matType != CV_32F) {
|
||||
throw std::runtime_error("Unsupported mat type for wrapping");
|
||||
}
|
||||
bool isMatFloat = matType == CV_32F;
|
||||
|
||||
const size_t channels = mat.channels();
|
||||
const size_t height = mat.rows;
|
||||
const size_t width = mat.cols;
|
||||
|
||||
const size_t strideH = mat.step.buf[0];
|
||||
const size_t strideW = mat.step.buf[1];
|
||||
|
||||
const bool isDense = !isMatFloat ? (strideW == channels && strideH == channels * width) :
|
||||
(strideW == channels * sizeof(float) && strideH == channels * width * sizeof(float));
|
||||
if (!isDense) {
|
||||
throw std::runtime_error("Doesn't support conversion from not dense cv::Mat");
|
||||
}
|
||||
auto precision = isMatFloat ? ov::element::f32 : ov::element::u8;
|
||||
return ov::Tensor(precision, ov::Shape{ 1, height, width, channels }, SharedMatAllocator{mat});
|
||||
}
|
||||
|
||||
static inline void resize2tensor(const cv::Mat& mat, ov::Tensor& tensor) {
|
||||
static const ov::Layout layout{"NHWC"};
|
||||
const ov::Shape& shape = tensor.get_shape();
|
||||
cv::Size size{int(shape[ov::layout::width_idx(layout)]), int(shape[ov::layout::height_idx(layout)])};
|
||||
assert(tensor.get_element_type() == ov::element::u8);
|
||||
assert(shape.size() == 4);
|
||||
assert(shape[ov::layout::batch_idx(layout)] == 1);
|
||||
assert(shape[ov::layout::channels_idx(layout)] == 3);
|
||||
cv::resize(mat, cv::Mat{size, CV_8UC3, tensor.data<uint8_t>()}, size);
|
||||
}
|
||||
|
||||
struct IntervalCondition {
|
||||
using DimType = size_t;
|
||||
using IndexType = size_t;
|
||||
using ConditionChecker = std::function<bool(IndexType, const ov::PartialShape&)>;
|
||||
|
||||
template<class Cond>
|
||||
constexpr IntervalCondition(IndexType i1, IndexType i2, Cond c) :
|
||||
impl([=](IndexType i0, const ov::PartialShape& shape) {
|
||||
return c(shape[i0].get_max_length(), shape[i1].get_max_length()) && c(shape[i0].get_max_length(), shape[i2].get_max_length());})
|
||||
{}
|
||||
bool operator() (IndexType i0, const ov::PartialShape& shape) const { return impl(i0, shape); }
|
||||
private:
|
||||
ConditionChecker impl;
|
||||
};
|
||||
|
||||
template <template<class> class Cond, class ...Args>
|
||||
IntervalCondition makeCond(Args&&...args) {
|
||||
return IntervalCondition(std::forward<Args>(args)..., Cond<IntervalCondition::DimType>{});
|
||||
}
|
||||
using LayoutCondition = std::tuple<size_t/*dim index*/, IntervalCondition, std::string>;
|
||||
|
||||
static inline std::tuple<bool, ov::Layout> makeGuesLayoutFrom4DShape(const ov::PartialShape& shape) {
|
||||
// at the moment we make assumption about NCHW & NHCW only
|
||||
// if hypothetical C value is less than hypothetical H and W - then
|
||||
// out assumption is correct and we pick a corresponding layout
|
||||
static const std::array<LayoutCondition, 2> hypothesisMatrix {{
|
||||
{1, makeCond<std::less_equal>(2, 3), "NCHW"},
|
||||
{3, makeCond<std::less_equal>(1, 2), "NHWC"}
|
||||
}};
|
||||
for (const auto &h : hypothesisMatrix) {
|
||||
|
||||
auto channel_index = std::get<0>(h);
|
||||
const auto &cond = std::get<1>(h);
|
||||
if (cond(channel_index, shape)) {
|
||||
return std::make_tuple(true, ov::Layout{std::get<2>(h)});
|
||||
}
|
||||
}
|
||||
return {false, ov::Layout{}};
|
||||
}
|
||||
|
||||
static inline ov::Layout getLayoutFromShape(const ov::PartialShape& shape) {
|
||||
if (shape.size() == 2) {
|
||||
return "NC";
|
||||
}
|
||||
if (shape.size() == 3) {
|
||||
if (shape[0] == 1) {
|
||||
return "NHW";
|
||||
}
|
||||
if (shape[2] == 1) {
|
||||
return "HWN";
|
||||
}
|
||||
throw std::runtime_error("Can't guess layout for " + shape.to_string());
|
||||
}
|
||||
if (shape.size() == 4) {
|
||||
if (ov::Interval{1, 4}.contains(shape[1].get_interval())) {
|
||||
return "NCHW";
|
||||
}
|
||||
if (ov::Interval{1, 4}.contains(shape[3].get_interval())) {
|
||||
return "NHWC";
|
||||
}
|
||||
if (shape[1] == shape[2]) {
|
||||
return "NHWC";
|
||||
}
|
||||
if (shape[2] == shape[3]) {
|
||||
return "NCHW";
|
||||
}
|
||||
bool guesResult = false;
|
||||
ov::Layout guessedLayout;
|
||||
std::tie(guesResult, guessedLayout) = makeGuesLayoutFrom4DShape(shape);
|
||||
if (guesResult) {
|
||||
return guessedLayout;
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("Usupported " + std::to_string(shape.size()) + "D shape");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Puts text message on the frame, highlights the text with a white border to make it distinguishable from
|
||||
* the background.
|
||||
* @param frame - frame to put the text on.
|
||||
* @param message - text of the message.
|
||||
* @param position - bottom-left corner of the text string in the image.
|
||||
* @param fontFace - font type.
|
||||
* @param fontScale - font scale factor that is multiplied by the font-specific base size.
|
||||
* @param color - text color.
|
||||
* @param thickness - thickness of the lines used to draw a text.
|
||||
*/
|
||||
inline void putHighlightedText(const cv::Mat& frame,
|
||||
const std::string& message,
|
||||
cv::Point position,
|
||||
int fontFace,
|
||||
double fontScale,
|
||||
cv::Scalar color,
|
||||
int thickness) {
|
||||
cv::putText(frame, message, position, fontFace, fontScale, cv::Scalar(255, 255, 255), thickness + 1);
|
||||
cv::putText(frame, message, position, fontFace, fontScale, color, thickness);
|
||||
}
|
||||
|
||||
// TODO: replace with Size::empty() after OpenCV3 is dropped
|
||||
static inline bool isSizeEmpty(const cv::Size& size) {
|
||||
return size.width <= 0 || size.height <= 0;
|
||||
}
|
||||
|
||||
// TODO: replace with Rect::empty() after OpenCV3 is dropped
|
||||
static inline bool isRectEmpty(const cv::Rect& rect) {
|
||||
return rect.width <= 0 || rect.height <= 0;
|
||||
}
|
||||
|
||||
class OutputTransform {
|
||||
public:
|
||||
OutputTransform() : doResize(false), scaleFactor(1) {}
|
||||
|
||||
OutputTransform(cv::Size inputSize, cv::Size outputResolution) :
|
||||
doResize(true), scaleFactor(1), inputSize(inputSize), outputResolution(outputResolution) {}
|
||||
|
||||
cv::Size computeResolution() {
|
||||
float inputWidth = static_cast<float>(inputSize.width);
|
||||
float inputHeight = static_cast<float>(inputSize.height);
|
||||
scaleFactor = MIN(outputResolution.height / inputHeight, outputResolution.width / inputWidth);
|
||||
newResolution = cv::Size{static_cast<int>(inputWidth * scaleFactor), static_cast<int>(inputHeight * scaleFactor)};
|
||||
return newResolution;
|
||||
}
|
||||
|
||||
void resize(cv::Mat& image) {
|
||||
if (!doResize) { return; }
|
||||
cv::Size currSize = image.size();
|
||||
if (currSize != inputSize) {
|
||||
inputSize = currSize;
|
||||
computeResolution();
|
||||
}
|
||||
if (scaleFactor == 1) { return; }
|
||||
cv::resize(image, image, newResolution);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void scaleCoord(T& coord) {
|
||||
if (!doResize || scaleFactor == 1) { return; }
|
||||
coord.x = std::floor(coord.x * scaleFactor);
|
||||
coord.y = std::floor(coord.y * scaleFactor);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void scaleRect(T& rect) {
|
||||
if (!doResize || scaleFactor == 1) { return; }
|
||||
scaleCoord(rect);
|
||||
rect.width = std::floor(rect.width * scaleFactor);
|
||||
rect.height = std::floor(rect.height * scaleFactor);
|
||||
}
|
||||
|
||||
bool doResize;
|
||||
|
||||
private:
|
||||
float scaleFactor;
|
||||
cv::Size inputSize;
|
||||
cv::Size outputResolution;
|
||||
cv::Size newResolution;
|
||||
};
|
||||
|
||||
class InputTransform {
|
||||
public:
|
||||
InputTransform() : reverseInputChannels(false), isTrivial(true) {}
|
||||
|
||||
InputTransform(bool reverseInputChannels, const std::string& meanValues, const std::string& scaleValues) :
|
||||
reverseInputChannels(reverseInputChannels),
|
||||
isTrivial(!reverseInputChannels && meanValues.empty() && scaleValues.empty()),
|
||||
means(meanValues.empty() ? cv::Scalar(0.0, 0.0, 0.0) : string2Vec(meanValues)),
|
||||
stdScales(scaleValues.empty() ? cv::Scalar(1.0, 1.0, 1.0) : string2Vec(scaleValues)) {
|
||||
}
|
||||
|
||||
cv::Scalar string2Vec(const std::string& string) {
|
||||
const auto& strValues = split(string, ' ');
|
||||
std::vector<float> values;
|
||||
try {
|
||||
for (auto& str : strValues)
|
||||
values.push_back(std::stof(str));
|
||||
}
|
||||
catch (const std::invalid_argument&) {
|
||||
throw std::runtime_error("Invalid parameter --mean_values or --scale_values is provided.");
|
||||
}
|
||||
if (values.size() != 3) {
|
||||
throw std::runtime_error("InputTransform expects 3 values per channel, but get \"" + string + "\".");
|
||||
}
|
||||
return cv::Scalar(values[0], values[1], values[2]);
|
||||
}
|
||||
|
||||
void setPrecision(ov::preprocess::PrePostProcessor& ppp, const std::string& tensorName) {
|
||||
const auto precision = isTrivial ? ov::element::u8 : ov::element::f32;
|
||||
ppp.input(tensorName).tensor().
|
||||
set_element_type(precision);
|
||||
}
|
||||
|
||||
cv::Mat operator()(const cv::Mat& inputs) {
|
||||
if (isTrivial) { return inputs; }
|
||||
cv::Mat result;
|
||||
inputs.convertTo(result, CV_32F);
|
||||
if (reverseInputChannels) {
|
||||
cv::cvtColor(result, result, cv::COLOR_BGR2RGB);
|
||||
}
|
||||
// TODO: merge the two following lines after OpenCV3 is droppped
|
||||
result -= means;
|
||||
result /= cv::Mat{stdScales};
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
bool reverseInputChannels;
|
||||
bool isTrivial;
|
||||
cv::Scalar means;
|
||||
cv::Scalar stdScales;
|
||||
};
|
||||
|
||||
class LazyVideoWriter {
|
||||
cv::VideoWriter writer;
|
||||
unsigned nwritten;
|
||||
public:
|
||||
const std::string filenames;
|
||||
const double fps;
|
||||
const unsigned lim;
|
||||
|
||||
LazyVideoWriter(const std::string& filenames, double fps, unsigned lim) :
|
||||
nwritten{1}, filenames{filenames}, fps{fps}, lim{lim} {}
|
||||
void write(const cv::Mat& im) {
|
||||
if (writer.isOpened() && (nwritten < lim || 0 == lim)) {
|
||||
writer.write(im);
|
||||
++nwritten;
|
||||
return;
|
||||
}
|
||||
if (!writer.isOpened() && !filenames.empty()) {
|
||||
if (!writer.open(filenames, cv::VideoWriter::fourcc('M', 'J', 'P', 'G'), fps, im.size())) {
|
||||
throw std::runtime_error("Can't open video writer");
|
||||
}
|
||||
writer.write(im);
|
||||
}
|
||||
}
|
||||
};
|
||||
92
engines/OpenVINOEngine/include/utils/performance_metrics.hpp
Normal file
92
engines/OpenVINOEngine/include/utils/performance_metrics.hpp
Normal file
@@ -0,0 +1,92 @@
|
||||
// Copyright (C) 2020-2024 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
/**
|
||||
* @brief a header file for performance metrics calculation class
|
||||
* @file performance_metrics.hpp
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "utils/ocv_common.hpp"
|
||||
|
||||
class PerformanceMetrics {
|
||||
public:
|
||||
using Clock = std::chrono::steady_clock;
|
||||
using TimePoint = std::chrono::time_point<Clock>;
|
||||
using Duration = Clock::duration;
|
||||
using Ms = std::chrono::duration<double, std::ratio<1, 1000>>;
|
||||
using Sec = std::chrono::duration<double, std::ratio<1, 1>>;
|
||||
|
||||
struct Metrics {
|
||||
double latency;
|
||||
double fps;
|
||||
};
|
||||
|
||||
enum MetricTypes {
|
||||
ALL,
|
||||
FPS,
|
||||
LATENCY
|
||||
};
|
||||
|
||||
PerformanceMetrics(Duration timeWindow = std::chrono::seconds(1));
|
||||
void update(TimePoint lastRequestStartTime,
|
||||
const cv::Mat& frame,
|
||||
cv::Point position = {15, 30},
|
||||
int fontFace = cv::FONT_HERSHEY_COMPLEX,
|
||||
double fontScale = 0.75,
|
||||
cv::Scalar color = {200, 10, 10},
|
||||
int thickness = 2, MetricTypes metricType = ALL);
|
||||
void update(TimePoint lastRequestStartTime);
|
||||
|
||||
/// Paints metrics over provided mat
|
||||
/// @param frame frame to paint over
|
||||
/// @param position left top corner of text block
|
||||
/// @param fontScale font scale
|
||||
/// @param color font color
|
||||
/// @param thickness font thickness
|
||||
void paintMetrics(const cv::Mat& frame,
|
||||
cv::Point position = { 15, 30 },
|
||||
int fontFace = cv::FONT_HERSHEY_COMPLEX,
|
||||
double fontScale = 0.75,
|
||||
cv::Scalar color = { 200, 10, 10 },
|
||||
int thickness = 2, MetricTypes metricType = ALL) const;
|
||||
|
||||
Metrics getLast() const;
|
||||
Metrics getTotal() const;
|
||||
void logTotal() const;
|
||||
|
||||
private:
|
||||
struct Statistic {
|
||||
Duration latency;
|
||||
Duration period;
|
||||
int frameCount;
|
||||
|
||||
Statistic() {
|
||||
latency = Duration::zero();
|
||||
period = Duration::zero();
|
||||
frameCount = 0;
|
||||
}
|
||||
|
||||
void combine(const Statistic& other) {
|
||||
latency += other.latency;
|
||||
period += other.period;
|
||||
frameCount += other.frameCount;
|
||||
}
|
||||
};
|
||||
|
||||
Duration timeWindowSize;
|
||||
Statistic lastMovingStatistic;
|
||||
Statistic currentMovingStatistic;
|
||||
Statistic totalStatistic;
|
||||
TimePoint lastUpdateTime;
|
||||
bool firstFrameProcessed;
|
||||
};
|
||||
|
||||
void logLatencyPerStage(double readLat, double preprocLat, double inferLat, double postprocLat, double renderLat);
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
// Copyright (C) 2021-2024 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <opencv2/core.hpp>
|
||||
|
||||
struct SharedMatAllocator {
|
||||
const cv::Mat mat;
|
||||
void* allocate(size_t bytes, size_t) {return bytes <= mat.rows * mat.step[0] ? mat.data : nullptr;}
|
||||
void deallocate(void*, size_t, size_t) noexcept {}
|
||||
bool is_equal(const SharedMatAllocator& other) const noexcept {return this == &other;}
|
||||
};
|
||||
99
engines/OpenVINOEngine/include/utils/slog.hpp
Normal file
99
engines/OpenVINOEngine/include/utils/slog.hpp
Normal file
@@ -0,0 +1,99 @@
|
||||
// Copyright (C) 2018-2024 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
/**
|
||||
* @brief a header file with logging facility for common samples
|
||||
* @file log.hpp
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
namespace slog {
|
||||
|
||||
/**
|
||||
* @class LogStreamEndLine
|
||||
* @brief The LogStreamEndLine class implements an end line marker for a log stream
|
||||
*/
|
||||
class LogStreamEndLine { };
|
||||
|
||||
static constexpr LogStreamEndLine endl;
|
||||
|
||||
|
||||
/**
|
||||
* @class LogStreamBoolAlpha
|
||||
* @brief The LogStreamBoolAlpha class implements bool printing for a log stream
|
||||
*/
|
||||
class LogStreamBoolAlpha { };
|
||||
|
||||
static constexpr LogStreamBoolAlpha boolalpha;
|
||||
|
||||
|
||||
/**
|
||||
* @class LogStream
|
||||
* @brief The LogStream class implements a stream for sample logging
|
||||
*/
|
||||
class LogStream {
|
||||
std::string _prefix;
|
||||
std::ostream* _log_stream;
|
||||
bool _new_line;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief A constructor. Creates a LogStream object
|
||||
* @param prefix The prefix to print
|
||||
*/
|
||||
LogStream(const std::string &prefix, std::ostream& log_stream)
|
||||
: _prefix(prefix), _new_line(true) {
|
||||
_log_stream = &log_stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A stream output operator to be used within the logger
|
||||
* @param arg Object for serialization in the logger message
|
||||
*/
|
||||
template<class T>
|
||||
LogStream &operator<<(const T &arg) {
|
||||
if (_new_line) {
|
||||
(*_log_stream) << "[ " << _prefix << " ] ";
|
||||
_new_line = false;
|
||||
}
|
||||
|
||||
(*_log_stream) << arg;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Specializing for LogStreamEndLine to support slog::endl
|
||||
LogStream& operator<< (const LogStreamEndLine &/*arg*/) {
|
||||
_new_line = true;
|
||||
|
||||
(*_log_stream) << std::endl;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Specializing for LogStreamBoolAlpha to support slog::boolalpha
|
||||
LogStream& operator<< (const LogStreamBoolAlpha &/*arg*/) {
|
||||
(*_log_stream) << std::boolalpha;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Specializing for std::vector and std::list
|
||||
template<template<class, class> class Container, class T>
|
||||
LogStream& operator<< (const Container<T, std::allocator<T>>& container) {
|
||||
for (const auto& el : container) {
|
||||
*this << el << slog::endl;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static LogStream info("INFO", std::cout);
|
||||
static LogStream debug("DEBUG", std::cout);
|
||||
static LogStream warn("WARNING", std::cout);
|
||||
static LogStream err("ERROR", std::cerr);
|
||||
|
||||
} // namespace slog
|
||||
160
engines/OpenVINOEngine/include/utils/threads_common.hpp
Normal file
160
engines/OpenVINOEngine/include/utils/threads_common.hpp
Normal file
@@ -0,0 +1,160 @@
|
||||
// Copyright (C) 2018-2024 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include "utils/performance_metrics.hpp"
|
||||
|
||||
// VideoFrame can represent not a single image but the whole grid
|
||||
class VideoFrame {
|
||||
public:
|
||||
typedef std::shared_ptr<VideoFrame> Ptr;
|
||||
|
||||
VideoFrame(unsigned sourceID, int64_t frameId, const cv::Mat& frame = cv::Mat()) :
|
||||
sourceID{sourceID}, frameId{frameId}, frame{frame} {}
|
||||
virtual ~VideoFrame() = default; // A user has to define how it is reconstructed
|
||||
|
||||
const unsigned sourceID;
|
||||
const int64_t frameId;
|
||||
cv::Mat frame;
|
||||
|
||||
PerformanceMetrics::TimePoint timestamp;
|
||||
};
|
||||
|
||||
class Worker;
|
||||
|
||||
class Task {
|
||||
public:
|
||||
explicit Task(VideoFrame::Ptr sharedVideoFrame, float priority = 0):
|
||||
sharedVideoFrame{sharedVideoFrame}, priority{priority} {}
|
||||
virtual bool isReady() = 0;
|
||||
virtual void process() = 0;
|
||||
virtual ~Task() = default;
|
||||
|
||||
std::string name;
|
||||
VideoFrame::Ptr sharedVideoFrame; // it is possible that two tasks try to draw on the same cvMat
|
||||
const float priority;
|
||||
};
|
||||
|
||||
struct HigherPriority {
|
||||
bool operator()(const std::shared_ptr<Task>& lhs, const std::shared_ptr<Task>& rhs) const {
|
||||
return lhs->priority > rhs->priority
|
||||
|| (lhs->priority == rhs->priority && lhs->sharedVideoFrame->frameId < rhs->sharedVideoFrame->frameId)
|
||||
|| (lhs->priority == rhs->priority && lhs->sharedVideoFrame->frameId == rhs->sharedVideoFrame->frameId && lhs < rhs);
|
||||
}
|
||||
};
|
||||
|
||||
class Worker {
|
||||
public:
|
||||
explicit Worker(unsigned threadNum):
|
||||
threadPool(threadNum), running{false} {}
|
||||
~Worker() {
|
||||
stop();
|
||||
}
|
||||
void runThreads() {
|
||||
running = true;
|
||||
for (std::thread& t : threadPool) {
|
||||
t = std::thread(&Worker::threadFunc, this);
|
||||
}
|
||||
}
|
||||
void push(std::shared_ptr<Task> task) {
|
||||
tasksMutex.lock();
|
||||
tasks.insert(task);
|
||||
tasksMutex.unlock();
|
||||
tasksCondVar.notify_one();
|
||||
}
|
||||
void threadFunc() {
|
||||
while (running) {
|
||||
std::unique_lock<std::mutex> lk(tasksMutex);
|
||||
while (running && tasks.empty()) {
|
||||
tasksCondVar.wait(lk);
|
||||
}
|
||||
try {
|
||||
auto it = std::find_if(tasks.begin(), tasks.end(), [](const std::shared_ptr<Task>& task){return task->isReady();});
|
||||
if (tasks.end() != it) {
|
||||
const std::shared_ptr<Task> task = std::move(*it);
|
||||
tasks.erase(it);
|
||||
lk.unlock();
|
||||
task->process();
|
||||
}
|
||||
} catch (...) {
|
||||
std::lock_guard<std::mutex> lock{exceptionMutex};
|
||||
if (nullptr == currentException) {
|
||||
currentException = std::current_exception();
|
||||
stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void stop() {
|
||||
running = false;
|
||||
tasksCondVar.notify_all();
|
||||
}
|
||||
void join() {
|
||||
for (auto& t : threadPool) {
|
||||
t.join();
|
||||
}
|
||||
if (nullptr != currentException) {
|
||||
std::rethrow_exception(currentException);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::condition_variable tasksCondVar;
|
||||
std::set<std::shared_ptr<Task>, HigherPriority> tasks;
|
||||
std::mutex tasksMutex;
|
||||
std::vector<std::thread> threadPool;
|
||||
std::atomic<bool> running;
|
||||
std::exception_ptr currentException;
|
||||
std::mutex exceptionMutex;
|
||||
};
|
||||
|
||||
|
||||
template <class C> class ConcurrentContainer {
|
||||
public:
|
||||
C container;
|
||||
mutable std::mutex mutex;
|
||||
|
||||
bool lockedEmpty() const noexcept {
|
||||
std::lock_guard<std::mutex> lock{mutex};
|
||||
return container.empty();
|
||||
}
|
||||
typename C::size_type lockedSize() const noexcept {
|
||||
std::lock_guard<std::mutex> lock{mutex};
|
||||
return container.size();
|
||||
}
|
||||
void lockedPushBack(const typename C::value_type& value) {
|
||||
std::lock_guard<std::mutex> lock{mutex};
|
||||
container.push_back(value);
|
||||
}
|
||||
bool lockedTryPop(typename C::value_type& value) {
|
||||
mutex.lock();
|
||||
if (!container.empty()) {
|
||||
value = container.back();
|
||||
container.pop_back();
|
||||
mutex.unlock();
|
||||
return true;
|
||||
} else {
|
||||
mutex.unlock();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
operator C() const {
|
||||
std::lock_guard<std::mutex> lock{mutex};
|
||||
return container;
|
||||
}
|
||||
};
|
||||
66
engines/OpenVINOEngine/include/utils/visualizer.hpp
Normal file
66
engines/OpenVINOEngine/include/utils/visualizer.hpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
// Copyright (C) 2021-2024 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 <string>
|
||||
#include <utility>
|
||||
|
||||
#include <opencv2/core.hpp>
|
||||
|
||||
struct ImageResult;
|
||||
|
||||
class Visualizer {
|
||||
private:
|
||||
// names of window and trackbar
|
||||
std::string winName = "Image Processing Demo (press A for help)";
|
||||
std::string trackbarName = "Orig/Diff | Res";
|
||||
|
||||
// images info
|
||||
cv::Size resolution = cv::Size(1000, 600);
|
||||
bool isResolutionSet = false;
|
||||
cv::Mat inputImg = cv::Mat(resolution, CV_32FC3, 0.);
|
||||
cv::Mat resultImg = cv::Mat(resolution, CV_32FC3, 0.);
|
||||
cv::Mat displayImg = cv::Mat(resolution, CV_32FC3, 0.);
|
||||
|
||||
// trackbar info
|
||||
std::string mode = "result";
|
||||
bool isTrackbarShown = false;
|
||||
int slider = 1;
|
||||
|
||||
// help message
|
||||
bool isHelpShown = false;
|
||||
std::string helpMessage[4] = {"Use R to display the result",
|
||||
"Use O to display the orig with result",
|
||||
"Use V to display the diff with result",
|
||||
"Esc or Q to quit"};
|
||||
void addTrackbar();
|
||||
void disableTrackbar();
|
||||
void setResolution(cv::Size& newResolution);
|
||||
void markImage(cv::Mat& image, const std::pair<std::string, std::string>& marks, float alpha);
|
||||
void drawSweepLine(cv::Mat& image);
|
||||
void changeDisplayImg();
|
||||
|
||||
public:
|
||||
Visualizer(const std::string& type = "");
|
||||
cv::Size getSize();
|
||||
|
||||
// change display image for new input and result images
|
||||
cv::Mat renderResultData(ImageResult result, cv::Size& newResolution);
|
||||
|
||||
// show display image or specified value
|
||||
void show(cv::Mat img = cv::Mat());
|
||||
|
||||
void handleKey(int key);
|
||||
};
|
||||
Reference in New Issue
Block a user