12 #include <opencv2/opencv.hpp>
13 #include <openvino/openvino.hpp>
16 #include "utils/shared_tensor_allocator.hpp"
22 const T
getMatValue(
const cv::Mat& mat,
size_t h,
size_t w,
size_t c) {
24 case CV_8UC1:
return (T)mat.at<uchar>(h, w);
25 case CV_8UC3:
return (T)mat.at<cv::Vec3b>(h, w)[c];
26 case CV_32FC1:
return (T)mat.at<
float>(h, w);
27 case CV_32FC3:
return (T)mat.at<cv::Vec3f>(h, w)[c];
29 throw std::runtime_error(
"cv::Mat type is not recognized");
38 static UNUSED
void matToTensor(
const cv::Mat& mat,
const ov::Tensor& tensor,
int batchIndex = 0) {
39 ov::Shape tensorShape = tensor.get_shape();
40 static const ov::Layout layout(
"NCHW");
41 const size_t width = tensorShape[ov::layout::width_idx(layout)];
42 const size_t height = tensorShape[ov::layout::height_idx(layout)];
43 const size_t channels = tensorShape[ov::layout::channels_idx(layout)];
44 if (
static_cast<size_t>(mat.channels()) != channels) {
45 throw std::runtime_error(
"The number of channels for model input and image must match");
47 if (channels != 1 && channels != 3) {
48 throw std::runtime_error(
"Unsupported number of channels");
50 int batchOffset = batchIndex * width * height * channels;
53 if (
static_cast<int>(width) != mat.size().width ||
static_cast<int>(height) != mat.size().height) {
54 cv::resize(mat, resizedMat, cv::Size(width, height));
59 if (tensor.get_element_type() == ov::element::f32) {
60 float_t* tensorData = tensor.data<float_t>();
61 for (
size_t c = 0; c < channels; c++)
62 for (
size_t h = 0; h < height; h++)
63 for (
size_t w = 0; w < width; w++)
64 tensorData[batchOffset + c * width * height + h * width + w] =
65 getMatValue<float_t>(resizedMat, h, w, c);
67 uint8_t* tensorData = tensor.data<uint8_t>();
68 if (resizedMat.depth() == CV_32F) {
69 throw std::runtime_error(
"Conversion of cv::Mat from float_t to uint8_t is forbidden");
71 for (
size_t c = 0; c < channels; c++)
72 for (
size_t h = 0; h < height; h++)
73 for (
size_t w = 0; w < width; w++)
74 tensorData[batchOffset + c * width * height + h * width + w] =
75 getMatValue<uint8_t>(resizedMat, h, w, c);
79 static UNUSED ov::Tensor wrapMat2Tensor(
const cv::Mat& mat) {
80 auto matType = mat.type() & CV_MAT_DEPTH_MASK;
81 if (matType != CV_8U && matType != CV_32F) {
82 throw std::runtime_error(
"Unsupported mat type for wrapping");
84 bool isMatFloat = matType == CV_32F;
86 const size_t channels = mat.channels();
87 const size_t height = mat.rows;
88 const size_t width = mat.cols;
90 const size_t strideH = mat.step.buf[0];
91 const size_t strideW = mat.step.buf[1];
93 const bool isDense = !isMatFloat ? (strideW == channels && strideH == channels * width) :
94 (strideW == channels *
sizeof(
float) && strideH == channels * width *
sizeof(float));
96 throw std::runtime_error(
"Doesn't support conversion from not dense cv::Mat");
98 auto precision = isMatFloat ? ov::element::f32 : ov::element::u8;
99 return ov::Tensor(precision, ov::Shape{ 1, height, width, channels },
SharedMatAllocator{mat});
102 static inline void resize2tensor(
const cv::Mat& mat,
const ov::Tensor& tensor) {
103 static const ov::Layout layout{
"NHWC"};
104 const ov::Shape& shape = tensor.get_shape();
105 cv::Size size{int(shape[ov::layout::width_idx(layout)]), int(shape[ov::layout::height_idx(layout)])};
106 assert(tensor.get_element_type() == ov::element::u8);
107 assert(shape.size() == 4);
108 assert(shape[ov::layout::batch_idx(layout)] == 1);
109 assert(shape[ov::layout::channels_idx(layout)] == 3);
110 cv::resize(mat, cv::Mat{size, CV_8UC3, tensor.data()}, size);
114 using DimType = size_t;
115 using IndexType = size_t;
116 using ConditionChecker = std::function<bool(IndexType,
const ov::PartialShape&)>;
120 impl([=](IndexType i0,
const ov::PartialShape& shape) {
121 return c(shape[i0].get_max_length(), shape[i1].get_max_length()) && c(shape[i0].get_max_length(), shape[i2].get_max_length());})
123 bool operator() (IndexType i0,
const ov::PartialShape& shape)
const {
return impl(i0, shape); }
125 ConditionChecker impl;
128 template <
template<
class>
class Cond,
class ...Args>
130 return IntervalCondition(std::forward<Args>(args)..., Cond<IntervalCondition::DimType>{});
134 static inline std::tuple<bool, ov::Layout> makeGuesLayoutFrom4DShape(
const ov::PartialShape& shape) {
138 static const std::array<LayoutCondition, 2> hypothesisMatrix {{
139 {1, makeCond<std::less_equal>(2, 3),
"NCHW"},
140 {3, makeCond<std::less_equal>(1, 2),
"NHWC"}
142 for (
const auto &h : hypothesisMatrix) {
144 auto channel_index = std::get<0>(h);
145 const auto &cond = std::get<1>(h);
146 if (cond(channel_index, shape)) {
147 return std::make_tuple(
true, ov::Layout{std::get<2>(h)});
150 return {
false, ov::Layout{}};
153 static inline ov::Layout getLayoutFromShape(
const ov::PartialShape& shape) {
154 if (shape.size() == 2) {
157 if (shape.size() == 3) {
164 throw std::runtime_error(
"Can't guess layout for " + shape.to_string());
166 if (shape.size() == 4) {
167 if (ov::Interval{1, 4}.contains(shape[1].get_interval())) {
170 if (ov::Interval{1, 4}.contains(shape[3].get_interval())) {
173 if (shape[1] == shape[2]) {
176 if (shape[2] == shape[3]) {
179 bool guesResult =
false;
180 ov::Layout guessedLayout;
181 std::tie(guesResult, guessedLayout) = makeGuesLayoutFrom4DShape(shape);
183 return guessedLayout;
186 throw std::runtime_error(
"Usupported " + std::to_string(shape.size()) +
"D shape");
201 const std::string& message,
207 cv::putText(frame, message, position, fontFace, fontScale, cv::Scalar(255, 255, 255), thickness + 1);
208 cv::putText(frame, message, position, fontFace, fontScale, color, thickness);
212 static inline bool isSizeEmpty(
const cv::Size& size) {
213 return size.width <= 0 || size.height <= 0;
217 static inline bool isRectEmpty(
const cv::Rect& rect) {
218 return rect.width <= 0 || rect.height <= 0;
226 doResize(
true), scaleFactor(1), inputSize(inputSize), outputResolution(outputResolution) {}
228 cv::Size computeResolution() {
229 float inputWidth =
static_cast<float>(inputSize.width);
230 float inputHeight =
static_cast<float>(inputSize.height);
231 scaleFactor = std::min(outputResolution.height / inputHeight, outputResolution.width / inputWidth);
232 newResolution = cv::Size{
static_cast<int>(inputWidth * scaleFactor),
static_cast<int>(inputHeight * scaleFactor)};
233 return newResolution;
236 void resize(cv::Mat& image) {
237 if (!doResize) {
return; }
238 cv::Size currSize = image.size();
239 if (currSize != inputSize) {
240 inputSize = currSize;
243 if (scaleFactor == 1) {
return; }
244 cv::resize(image, image, newResolution);
248 void scaleCoord(T& coord) {
249 if (!doResize || scaleFactor == 1) {
return; }
250 coord.x = std::floor(coord.x * scaleFactor);
251 coord.y = std::floor(coord.y * scaleFactor);
255 void scaleRect(T& rect) {
256 if (!doResize || scaleFactor == 1) {
return; }
258 rect.width = std::floor(rect.width * scaleFactor);
259 rect.height = std::floor(rect.height * scaleFactor);
267 cv::Size outputResolution;
268 cv::Size newResolution;
273 InputTransform() : reverseInputChannels(
false), isTrivial(
true) {}
275 InputTransform(
bool reverseInputChannels,
const std::string& meanValues,
const std::string& scaleValues) :
276 reverseInputChannels(reverseInputChannels),
277 isTrivial(!reverseInputChannels && meanValues.empty() && scaleValues.empty()),
278 means(meanValues.empty() ? cv::Scalar(0.0, 0.0, 0.0) : string2Vec(meanValues)),
279 stdScales(scaleValues.empty() ? cv::Scalar(1.0, 1.0, 1.0) : string2Vec(scaleValues)) {
282 cv::Scalar string2Vec(
const std::string&
string) {
283 const auto& strValues = split(
string,
' ');
284 std::vector<float> values;
286 for (
auto& str : strValues)
287 values.push_back(std::stof(str));
289 catch (
const std::invalid_argument&) {
290 throw std::runtime_error(
"Invalid parameter --mean_values or --scale_values is provided.");
292 if (values.size() != 3) {
293 throw std::runtime_error(
"InputTransform expects 3 values per channel, but get \"" +
string +
"\".");
295 return cv::Scalar(values[0], values[1], values[2]);
298 void setPrecision(ov::preprocess::PrePostProcessor& ppp,
const std::string& tensorName) {
299 const auto precision = isTrivial ? ov::element::u8 : ov::element::f32;
300 ppp.input(tensorName).tensor().
301 set_element_type(precision);
304 cv::Mat operator()(
const cv::Mat& inputs) {
305 if (isTrivial) {
return inputs; }
307 inputs.convertTo(result, CV_32F);
308 if (reverseInputChannels) {
309 cv::cvtColor(result, result, cv::COLOR_BGR2RGB);
313 result /= cv::Mat{stdScales};
318 bool reverseInputChannels;
321 cv::Scalar stdScales;
325 cv::VideoWriter writer;
328 const std::string filenames;
332 LazyVideoWriter(
const std::string& filenames,
double fps,
unsigned lim) :
333 nwritten{1}, filenames{filenames}, fps{fps}, lim{lim} {}
334 void write(
const cv::Mat& im) {
335 if (writer.isOpened() && (nwritten < lim || 0 == lim)) {
340 if (!writer.isOpened() && !filenames.empty()) {
341 if (!writer.open(filenames, cv::VideoWriter::fourcc(
'M',
'J',
'P',
'G'), fps, im.size())) {
342 throw std::runtime_error(
"Can't open video writer");
Definition: ocv_common.hpp:324
a header file with common samples functionality
const T getMatValue(const cv::Mat &mat, size_t h, size_t w, size_t c)
Get cv::Mat value in the correct format.
Definition: ocv_common.hpp:22
void putHighlightedText(const cv::Mat &frame, const std::string &message, cv::Point position, int fontFace, double fontScale, cv::Scalar color, int thickness)
Puts text message on the frame, highlights the text with a white border to make it distinguishable fr...
Definition: ocv_common.hpp:200
Definition: ocv_common.hpp:113
Definition: shared_tensor_allocator.hpp:21