diff --git a/modules/gapi/include/opencv2/gapi/infer/ov.hpp b/modules/gapi/include/opencv2/gapi/infer/ov.hpp index 9515744cac..3673ff53a2 100644 --- a/modules/gapi/include/opencv2/gapi/infer/ov.hpp +++ b/modules/gapi/include/opencv2/gapi/infer/ov.hpp @@ -66,6 +66,8 @@ struct ParamDesc { LayerVariantAttr> scale_values; LayerVariantAttr interpolation; + + bool clamp_outputs = false; }; struct CompiledModel { @@ -356,6 +358,24 @@ public: return *this; } + /** @brief Enables or disables clamping of model outputs in the PrePostProcessor. + + By default, output values are clamped to the valid range for the output precision + by the device or plugin. Enabling this option moves clamping to the PrePostProcessor stage. + + @note This feature is only available with OpenVINO 2025.2 and newer. + + @param flag If true, clamping is performed in the PrePostProcessor; + otherwise, it is handled by the device or plugin. + @return reference to this parameter structure. + */ + Params& + cfgClampOutputs(bool flag = true) { + detail::getModelToSetAttrOrThrow(m_desc.kind, "clamp outputs") + .clamp_outputs = std::move(flag); + return *this; + } + /** @brief Specifies the new shape for input layers. The function is used to set new shape for input layers. @@ -625,6 +645,14 @@ public: return *this; } + /** @see ov::Params::cfgClampOutputs. */ + Params& + cfgClampOutputs(bool flag = true) { + detail::getModelToSetAttrOrThrow(m_desc.kind, "clamp outputs") + .clamp_outputs = std::move(flag); + return *this; + } + /** @see ov::Params::cfgReshape. */ Params& cfgReshape(std::vector new_shape) { detail::getModelToSetAttrOrThrow(m_desc.kind, "reshape") diff --git a/modules/gapi/src/backends/ov/govbackend.cpp b/modules/gapi/src/backends/ov/govbackend.cpp index dbaba382db..4ea1c1cc0f 100644 --- a/modules/gapi/src/backends/ov/govbackend.cpp +++ b/modules/gapi/src/backends/ov/govbackend.cpp @@ -147,6 +147,25 @@ static int toCV(const ov::element::Type &type) { return -1; } +static inline std::pair get_CV_type_range(int cv_type) { + switch (cv_type) { + case CV_8U: + return { static_cast(std::numeric_limits::min()), + static_cast(std::numeric_limits::max()) }; + case CV_32S: + return { static_cast(std::numeric_limits::min()), + static_cast(std::numeric_limits::max()) }; + case CV_32F: + return { static_cast(std::numeric_limits::lowest()), + static_cast(std::numeric_limits::max()) }; + case CV_16F: + return { -65504.0, 65504.0 }; + default: + GAPI_Error("OV Backend: Unsupported data type"); + } + return {0.0, 0.0}; +} + static void copyFromOV(const ov::Tensor &tensor, cv::Mat &mat) { const auto total = mat.total() * mat.channels(); if (toCV(tensor.get_element_type()) != mat.depth() || @@ -1052,6 +1071,20 @@ public: if (explicit_out_tensor_prec) { m_ppp.output(output_name).tensor() .set_element_type(toOV(*explicit_out_tensor_prec)); + + if (m_model_info.clamp_outputs) { + #if INF_ENGINE_RELEASE >= 2025020000 + auto clamp_range = get_CV_type_range(*explicit_out_tensor_prec); + m_ppp.output(output_name).postprocess() + .clamp(clamp_range.first, clamp_range.second); + #else + static bool warned = false; + if (!warned) { + GAPI_LOG_WARNING(NULL, "cfgClampOutputs is enabled, but not supported in this OpenVINO version. Clamping will be ignored."); + warned = true; + } + #endif // INF_ENGINE_RELEASE >= 2025020000 + } } } }