1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-29 15:23:05 +04:00

Merge pull request #28588 from abhishek-gola:ORT_GPU_wrapper

Added OnnxRuntime GPU wrapper #28588

### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [x] The PR is proposed to the proper branch
- [x] There is a reference to the original bug report and related work
- [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [x] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
Abhishek Gola
2026-04-06 18:10:58 +05:30
committed by GitHub
parent a49a293d3c
commit 2ec6a6bb65
19 changed files with 402 additions and 135 deletions
+2
View File
@@ -395,6 +395,8 @@ OCV_OPTION(WITH_ONNXRUNTIME "Include Microsoft ONNX Runtime support" OFF
VERIFY HAVE_ONNX)
OCV_OPTION(DOWNLOAD_ONNXRUNTIME "Download ONNX Runtime prebuilt binaries" OFF
VISIBLE_IF WITH_ONNXRUNTIME)
OCV_OPTION(DOWNLOAD_ONNXRUNTIME_GPU "Download GPU-enabled ONNX Runtime prebuilt binaries when available" OFF
VISIBLE_IF WITH_ONNXRUNTIME)
OCV_OPTION(ONNXRUNTIME_PREFER_STATIC "Prefer static ONNX Runtime library when available" ON
VISIBLE_IF WITH_ONNXRUNTIME)
set(ONNXRUNTIME_VERSION "1.24.2" CACHE STRING "ONNX Runtime version to download (prebuilt binaries)")
@@ -526,6 +526,7 @@ OpenCV have own DNN inference module which have own build-in engine, but can als
| `WITH_OPENVINO` | _OFF_ | Enable Intel OpenVINO Toolkit support. Should be used for OpenVINO>=2022.1 instead of `WITH_INF_ENGINE` and `WITH_NGRAPH`. |
| `WITH_ONNXRUNTIME` | _OFF_ | Enable Microsoft ONNX Runtime backend support for OpenCV DNN. |
| `DOWNLOAD_ONNXRUNTIME` | _OFF_ | Download official ONNX Runtime prebuilt binaries when enabled (or when ONNX Runtime is not available in system paths). |
| `DOWNLOAD_ONNXRUNTIME_GPU` | _OFF_ | Download GPU-enabled ONNX Runtime prebuilt binaries when available (Windows x64 and Linux x64 only). Requires `WITH_ONNXRUNTIME=ON`. |
| `ONNXRUNTIME_PREFER_STATIC` | _ON_ | Prefer static `libonnxruntime.a` when both static and shared ONNX Runtime libraries are available. |
| `ONNXRUNTIME_VERSION` | _1.24.2_ | ONNX Runtime version to download for prebuilt packages. |
| `OPENCV_DNN_CUDA` | _OFF_ | Enable CUDA backend. [CUDA](https://en.wikipedia.org/wiki/CUDA), CUBLAS and [CUDNN](https://developer.nvidia.com/cudnn) must be installed. |
+120 -28
View File
@@ -110,12 +110,19 @@ ocv_warnings_disable(CMAKE_CXX_FLAGS
set(include_dirs "")
set(libs "")
# ONNX Runtime
ocv_option(WITH_ONNXRUNTIME "Build with ONNX Runtime support" OFF)
ocv_option(DOWNLOAD_ONNXRUNTIME "Download ONNX Runtime prebuilt binaries" OFF IF WITH_ONNXRUNTIME)
ocv_option(DOWNLOAD_ONNXRUNTIME_GPU "Download GPU-enabled ONNX Runtime prebuilt binaries when available" OFF IF WITH_ONNXRUNTIME)
set(ONNXRUNTIME_VERSION "1.24.2" CACHE STRING "ONNX Runtime version to download (prebuilt binaries)")
if(WITH_ONNXRUNTIME)
include("${OpenCV_SOURCE_DIR}/cmake/FindONNX.cmake")
set(_ort_download_requested OFF)
set(_ort_download_forced OFF)
if(DOWNLOAD_ONNXRUNTIME)
if(DOWNLOAD_ONNXRUNTIME OR DOWNLOAD_ONNXRUNTIME_GPU)
set(_ort_download_requested ON)
set(_ort_download_forced ON)
elseif(NOT HAVE_ONNXRUNTIME)
@@ -125,57 +132,143 @@ if(WITH_ONNXRUNTIME)
if(_ort_download_requested)
set(_ort_filename "")
set(_ort_md5 "")
set(_ort_package_kind "CPU")
if(DOWNLOAD_ONNXRUNTIME_GPU)
set(_ort_package_kind "GPU")
endif()
string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" _ort_processor)
set(_ort_is_x64 FALSE)
set(_ort_is_arm64 FALSE)
set(_ort_is_x86 FALSE)
if(X86_64 OR _ort_processor MATCHES "^(x86_64|amd64)$")
set(_ort_is_x64 TRUE)
endif()
if(ARM64 OR AARCH64 OR _ort_processor MATCHES "^(aarch64|arm64)$")
set(_ort_is_arm64 TRUE)
endif()
if(X86 OR _ort_processor MATCHES "^(x86|i[3-6]86)$")
set(_ort_is_x86 TRUE)
endif()
if(WIN32)
if(X86_64 OR CMAKE_SIZEOF_VOID_P EQUAL 8)
set(_ort_filename "onnxruntime-win-x64-${ONNXRUNTIME_VERSION}.zip")
set(_ort_md5 "c535ec65cf6f850f2a70b4029acdc5d7")
elseif(ARM64 OR AARCH64)
if(_ort_is_arm64)
if(DOWNLOAD_ONNXRUNTIME_GPU)
message(FATAL_ERROR "DNN: ONNX Runtime GPU package is not available for Windows ARM64. "
"Disable DOWNLOAD_ONNXRUNTIME_GPU or use a supported platform (Windows x64 or Linux x64).")
endif()
set(_ort_filename "onnxruntime-win-arm64-${ONNXRUNTIME_VERSION}.zip")
set(_ort_md5 "01df64c14cf9285a6b23744f1b2ddf63")
elseif(_ort_is_x64)
if(DOWNLOAD_ONNXRUNTIME_GPU)
set(_ort_filename "onnxruntime-win-x64-gpu-${ONNXRUNTIME_VERSION}.zip")
else()
set(_ort_filename "onnxruntime-win-x64-${ONNXRUNTIME_VERSION}.zip")
endif()
elseif(_ort_is_x86)
message(FATAL_ERROR
"DNN: No official ONNX Runtime prebuilt package detected for 32-bit Windows and "
"ONNXRUNTIME_VERSION='${ONNXRUNTIME_VERSION}'. "
"Disable DOWNLOAD_ONNXRUNTIME and provide ONNXRT_ROOT_DIR manually."
)
endif()
elseif(APPLE)
if(ARM64 OR AARCH64 OR CMAKE_OSX_ARCHITECTURES MATCHES "arm64")
if(DOWNLOAD_ONNXRUNTIME_GPU)
message(FATAL_ERROR "DNN: ONNX Runtime GPU package is not available for macOS. "
"Disable DOWNLOAD_ONNXRUNTIME_GPU or use a supported platform (Windows x64 or Linux x64).")
endif()
if(_ort_is_arm64)
set(_ort_filename "onnxruntime-osx-arm64-${ONNXRUNTIME_VERSION}.tgz")
set(_ort_md5 "44302ee5651926ba6b0a3e92a3a303db")
elseif(_ort_is_x64)
set(_ort_filename "onnxruntime-osx-x86_64-${ONNXRUNTIME_VERSION}.tgz")
else()
set(_ort_filename "onnxruntime-osx-universal2-${ONNXRUNTIME_VERSION}.tgz")
endif()
elseif(UNIX)
if(X86_64)
set(_ort_filename "onnxruntime-linux-x64-${ONNXRUNTIME_VERSION}.tgz")
set(_ort_md5 "8e444d3ed1ea286013e339132ed4f08e")
elseif(AARCH64 OR ARM64)
if(_ort_is_x64)
if(DOWNLOAD_ONNXRUNTIME_GPU)
set(_ort_filename "onnxruntime-linux-x64-gpu-${ONNXRUNTIME_VERSION}.tgz")
else()
set(_ort_filename "onnxruntime-linux-x64-${ONNXRUNTIME_VERSION}.tgz")
endif()
elseif(_ort_is_arm64)
if(DOWNLOAD_ONNXRUNTIME_GPU)
message(FATAL_ERROR "DNN: ONNX Runtime GPU package is not available for Linux AArch64. "
"Disable DOWNLOAD_ONNXRUNTIME_GPU or use a supported platform (Windows x64 or Linux x64).")
endif()
set(_ort_filename "onnxruntime-linux-aarch64-${ONNXRUNTIME_VERSION}.tgz")
set(_ort_md5 "857b0fbb35f9d4cc117033242fc2a3da")
endif()
endif()
if(NOT _ort_filename)
if(_ort_download_forced OR NOT HAVE_ONNXRUNTIME)
if(_ort_download_forced)
message(FATAL_ERROR
"DNN: there is no official ONNX Runtime prebuilt package for "
"DNN: DOWNLOAD_ONNXRUNTIME=ON, but there is no official ONNX Runtime prebuilt package for "
"CMAKE_SYSTEM_NAME='${CMAKE_SYSTEM_NAME}', CMAKE_SYSTEM_PROCESSOR='${CMAKE_SYSTEM_PROCESSOR}'. "
"Provide an installed ORT via ONNXRT_ROOT_DIR, or use a supported platform."
"Disable DOWNLOAD_ONNXRUNTIME and provide an installed ORT via ONNXRT_ROOT_DIR, or use a supported platform."
)
endif()
else()
set(_ort_url "https://github.com/microsoft/onnxruntime/releases/download/v${ONNXRUNTIME_VERSION}/${_ort_filename}")
string(REGEX REPLACE "\\.(tgz|zip)$" "" _ort_unpack_dirname "${_ort_filename}")
ocv_download(
FILENAME ${_ort_filename}
URL ${_ort_url}
DESTINATION_DIR "${OpenCV_BINARY_DIR}/3rdparty/onnxruntime"
ID "ORT"
HASH ${_ort_md5}
UNPACK
)
set(_ort_download_dir "${OpenCV_BINARY_DIR}/3rdparty/onnxruntime")
set(_ort_cache_dir "${OPENCV_DOWNLOAD_PATH}/onnxruntime")
set(_ort_cache_archive "${_ort_cache_dir}/${_ort_filename}")
set(_ort_extracted_dir "${_ort_download_dir}/${_ort_unpack_dirname}")
set(ONNXRT_ROOT_DIR "${OpenCV_BINARY_DIR}/3rdparty/onnxruntime/${_ort_unpack_dirname}"
message(STATUS "DNN: ONNX Runtime download mode: ${_ort_package_kind}")
message(STATUS "DNN: ONNX Runtime package: ${_ort_filename}")
# Download to persistent cache if not already present
if(NOT EXISTS "${_ort_cache_archive}")
file(MAKE_DIRECTORY "${_ort_cache_dir}")
message(STATUS "DNN: Downloading ONNX Runtime package from ${_ort_url}")
file(DOWNLOAD "${_ort_url}" "${_ort_cache_archive}"
SHOW_PROGRESS
STATUS _ort_download_status
LOG _ort_download_log)
list(GET _ort_download_status 0 _ort_download_status_code)
if(NOT _ort_download_status_code EQUAL 0)
file(REMOVE "${_ort_cache_archive}")
if(_ort_download_forced)
message(FATAL_ERROR "DNN: ONNX Runtime download failed. URL='${_ort_url}'. Log: ${_ort_download_log}")
else()
message(STATUS "DNN: ONNX Runtime download failed, skipping. Log: ${_ort_download_log}")
endif()
endif()
else()
message(STATUS "DNN: ONNX Runtime package found in cache: ${_ort_cache_archive}")
endif()
# Extract to build dir if not already extracted
if(EXISTS "${_ort_cache_archive}" AND NOT EXISTS "${_ort_extracted_dir}")
file(MAKE_DIRECTORY "${_ort_download_dir}")
message(STATUS "DNN: Extracting ONNX Runtime package to ${_ort_download_dir}")
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
file(ARCHIVE_EXTRACT INPUT "${_ort_cache_archive}"
DESTINATION "${_ort_download_dir}")
else()
if(_ort_filename MATCHES "\\.zip$")
set(_ort_tar_flags xvf)
else()
set(_ort_tar_flags xzf)
endif()
execute_process(
COMMAND "${CMAKE_COMMAND}" -E tar ${_ort_tar_flags} "${_ort_cache_archive}"
WORKING_DIRECTORY "${_ort_download_dir}"
RESULT_VARIABLE _ort_extract_status
)
if(NOT _ort_extract_status EQUAL 0)
message(FATAL_ERROR "DNN: ONNX Runtime extraction failed for '${_ort_cache_archive}'.")
endif()
endif()
endif()
set(ONNXRT_ROOT_DIR "${_ort_extracted_dir}"
CACHE PATH "ONNX Runtime install directory" FORCE)
if(NOT APPLE AND NOT WIN32)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-rpath,'$ORIGIN/../3rdparty/onnxruntime/${_ort_unpack_dirname}/lib'")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,'$ORIGIN/../3rdparty/onnxruntime/${_ort_unpack_dirname}/lib'")
endif()
include("${OpenCV_SOURCE_DIR}/cmake/FindONNX.cmake")
@@ -275,8 +368,7 @@ if(WITH_ONNXRUNTIME)
else()
message(SEND_ERROR
"DNN: ONNX Runtime support was requested (WITH_ONNXRUNTIME=ON), but it was not found. "
"Set ONNXRT_ROOT_DIR to an existing installation. "
"OpenCV attempts to download supported prebuilt ONNX Runtime packages automatically when needed."
"Set ONNXRT_ROOT_DIR to an existing installation or enable DOWNLOAD_ONNXRUNTIME=ON."
)
endif()
+13
View File
@@ -765,6 +765,19 @@ CV__DNN_INLINE_NS_BEGIN
*/
CV_WRAP void setPreferableTarget(int targetId);
/** @brief Finalizes the network configuration and prepares it for inference.
*
* This method must be called after setting backend/target via
* setPreferableBackend() and setPreferableTarget(), and before the first
* forward() call. It creates the underlying execution session (e.g. ONNX
* Runtime session) on the configured backend/target. If not called
* explicitly, the first forward() will call it automatically.
*
* Calling finalizeNet() early lets you pay the one-time setup cost at a
* predictable point and catch configuration errors before inference.
*/
CV_WRAP void finalizeNet();
/**
* @brief Set the tracing mode
* @param[in] tracingMode the tracing mode, see DNN_TRACE_*
+13
View File
@@ -131,6 +131,19 @@ void Net::setPreferableTarget(int targetId)
return impl->setPreferableTarget(targetId);
}
void Net::finalizeNet()
{
CV_TRACE_FUNCTION();
CV_Assert(impl);
#ifdef HAVE_ONNXRUNTIME
if (impl->mainGraph && impl->modelFormat == DNN_MODEL_ONNX && !impl->modelFileName.empty())
{
impl->finalizeOrt();
return;
}
#endif
}
void Net::setInputsNames(const std::vector<String>& inputBlobNames)
{
CV_TRACE_FUNCTION();
+3 -2
View File
@@ -1145,8 +1145,6 @@ void Net::Impl::forward(OutputArrayOfArrays outputBlobs,
const std::vector<String>& outBlobNames)
{
CV_Assert(!empty());
if (outBlobNames.empty())
CV_Error(Error::StsBadArg, "in Net::forward(), outBlobNames cannot be empty");
FPDenormalsIgnoreHintScope fp_denormals_ignore_scope;
if (mainGraph) {
@@ -1154,6 +1152,9 @@ void Net::Impl::forward(OutputArrayOfArrays outputBlobs,
return;
}
if (outBlobNames.empty())
CV_Error(Error::StsBadArg, "in Net::forward(), outBlobNames cannot be empty");
std::vector<LayerPin> pins;
for (int i = 0; i < outBlobNames.size(); i++)
{
+5 -1
View File
@@ -251,10 +251,14 @@ struct Net::Impl : public detail::NetImplBase
#endif
#ifdef HAVE_ONNXRUNTIME
void finalizeOrt();
void refreshOrtMainGraphOutputs();
void applyStagedOrtInputs();
std::vector<std::pair<std::string, Mat>> ort_staged_inputs;
std::shared_ptr<Ort::Env> ort_env;
std::shared_ptr<Ort::Session> ort_session;
std::shared_ptr<Ort::SessionOptions> ort_session_options;
std::shared_ptr<OrtNamesCache> ort_names_cache;
bool ortNeedsReinit = true; // session needs (re)creation on next finalizeNet
#endif
void allocateLayer(int lid, const LayersShapesMap& layersShapes);
+75
View File
@@ -52,6 +52,54 @@ struct OrtNamesCache
#endif
#ifdef HAVE_ONNXRUNTIME
void Net::Impl::applyStagedOrtInputs()
{
if (!ort_session || ort_staged_inputs.empty())
return;
if (!ort_names_cache)
ort_names_cache = std::make_shared<OrtNamesCache>(*ort_session);
OrtNamesCache& names = *ort_names_cache;
const size_t ninputs = names.input_names.size();
if (ninputs == 0)
CV_Error(Error::StsError, "DNN/ORT: ORT session has no inputs");
if (!netInputLayer)
{
netInputLayer = Ptr<DataLayer>(new DataLayer());
netInputLayer->name = "ort_data_layer";
netInputLayer->type = "Data";
}
if (netInputLayer->blobs.size() != ninputs)
netInputLayer->blobs.resize(ninputs);
for (size_t k = 0; k < ort_staged_inputs.size(); ++k)
{
const std::string& inpname = ort_staged_inputs[k].first;
const Mat& inputMat = ort_staged_inputs[k].second;
if (inputMat.empty())
CV_Error(Error::StsBadArg, "DNN/ORT: Input blob is empty");
size_t inputIdx = 0;
if (inpname.empty())
{
if (ninputs != 1)
CV_Error(Error::StsBadArg, "DNN/ORT: input name must be specified for models with multiple inputs");
inputIdx = 0;
}
else
{
auto it = names.input_name_to_index.find(inpname);
if (it == names.input_name_to_index.end())
CV_Error_(Error::StsObjectNotFound, ("DNN/ORT: input '%s' is not found", inpname.c_str()));
inputIdx = (size_t)it->second;
}
inputMat.copyTo(netInputLayer->blobs[inputIdx]);
}
ort_staged_inputs.clear();
}
static int cvTypeFromONNXElemType(const ONNXTensorElementDataType t)
{
switch (t)
@@ -571,6 +619,8 @@ void Net::Impl::allocateLayerOutputs(
void Net::Impl::forwardMainGraph(InputArrayOfArrays inputs, OutputArrayOfArrays outputs)
{
#ifdef HAVE_ONNXRUNTIME
if (mainGraph && modelFormat == DNN_MODEL_ONNX && !modelFileName.empty())
finalizeOrt();
if (this->ort_session)
{
if (!netInputLayer || netInputLayer->blobs.empty())
@@ -628,6 +678,8 @@ void Net::Impl::forwardMainGraph(InputArrayOfArrays inputs, OutputArrayOfArrays
void Net::Impl::forwardWithSingleOutput(const std::string& outname, OutputArrayOfArrays outputBlobs)
{
#ifdef HAVE_ONNXRUNTIME
if (mainGraph && modelFormat == DNN_MODEL_ONNX && !modelFileName.empty())
finalizeOrt();
if (this->ort_session)
{
if (!netInputLayer || netInputLayer->blobs.empty())
@@ -711,6 +763,8 @@ void Net::Impl::forwardWithSingleOutput(const std::string& outname, OutputArrayO
void Net::Impl::forwardWithMultipleOutputs(OutputArrayOfArrays outblobs, const std::vector<std::string>& outnames)
{
#ifdef HAVE_ONNXRUNTIME
if (mainGraph && modelFormat == DNN_MODEL_ONNX && !modelFileName.empty())
finalizeOrt();
if (this->ort_session)
{
if (!netInputLayer || netInputLayer->blobs.empty())
@@ -893,6 +947,27 @@ void Net::Impl::traceArg(std::ostream& strm_, const char* prefix, size_t i, Arg
void Net::Impl::setMainGraphInput(InputArray m, const std::string& inpname)
{
#ifdef HAVE_ONNXRUNTIME
if (ortNeedsReinit && mainGraph && modelFormat == DNN_MODEL_ONNX && !modelFileName.empty())
{
Mat inputMat = m.getMat();
if (inputMat.empty())
CV_Error(Error::StsBadArg, "DNN/ORT: Input blob is empty");
bool updated = false;
for (size_t i = 0; i < ort_staged_inputs.size(); ++i)
{
if (ort_staged_inputs[i].first == inpname)
{
inputMat.copyTo(ort_staged_inputs[i].second);
updated = true;
break;
}
}
if (!updated)
ort_staged_inputs.push_back(std::make_pair(inpname, inputMat.clone()));
return;
}
if (this->ort_session)
{
if (!this->ort_names_cache)
+131 -27
View File
@@ -14,10 +14,93 @@
#include "cuda4dnn/init.hpp"
#endif
#ifdef HAVE_ONNXRUNTIME
#include <onnxruntime_cxx_api.h>
#endif
namespace cv {
namespace dnn {
CV__DNN_INLINE_NS_BEGIN
#ifdef HAVE_ONNXRUNTIME
void Net::Impl::refreshOrtMainGraphOutputs()
{
CV_Assert(mainGraph && ort_session);
Ort::Session& session = *ort_session;
Ort::AllocatorWithDefaultOptions allocator;
const size_t noutputs = session.GetOutputCount();
CV_Assert(noutputs > 0);
std::vector<Arg> outs;
outs.reserve(noutputs);
for (size_t i = 0; i < noutputs; ++i)
{
Ort::AllocatedStringPtr out = session.GetOutputNameAllocated(i, allocator);
std::string outName = out ? std::string(out.get()) : std::string();
if (outName.empty())
outName = format("output_%zu", i);
if (haveArg(outName))
{
const int existingIdx = (int)argnames[outName];
if (args[(size_t)existingIdx].kind == DNN_ARG_OUTPUT)
{
outs.push_back(Arg(existingIdx));
continue;
}
std::string uniqueOutName = format("%s_%zu", outName.c_str(), i);
while (haveArg(uniqueOutName))
uniqueOutName += "_";
outName = uniqueOutName;
}
outs.push_back(newArg(outName, DNN_ARG_OUTPUT));
}
mainGraph->setOutputs(outs);
}
void Net::Impl::finalizeOrt()
{
if (ort_session && !ortNeedsReinit)
return;
CV_Assert(!modelFileName.empty());
int target = IS_DNN_CUDA_TARGET(preferableTarget) ? preferableTarget : DNN_TARGET_CPU;
ort_session.reset();
ort_names_cache.reset();
static auto s_env = std::make_shared<Ort::Env>(ORT_LOGGING_LEVEL_WARNING, "OpenCV_DNN_ORT");
ort_env = s_env;
Ort::SessionOptions opts;
if (IS_DNN_CUDA_TARGET(target))
{
OrtCUDAProviderOptions cuda{};
cuda.device_id = 0;
try { opts.AppendExecutionProvider_CUDA(cuda); }
catch (const std::exception& e)
{
CV_LOG_WARNING(NULL, "DNN/ONNX/ORT: CUDA EP unavailable (" << e.what() << "), using CPU");
target = DNN_TARGET_CPU;
opts = Ort::SessionOptions();
}
}
#ifdef _WIN32
std::wstring wpath(modelFileName.begin(), modelFileName.end());
ort_session = std::make_shared<Ort::Session>(*ort_env, wpath.c_str(), opts);
#else
ort_session = std::make_shared<Ort::Session>(*ort_env, modelFileName.c_str(), opts);
#endif
preferableTarget = target;
ortNeedsReinit = false;
refreshOrtMainGraphOutputs();
applyStagedOrtInputs();
}
#endif
Ptr<BackendWrapper> Net::Impl::wrap(Mat& host)
{
@@ -170,7 +253,7 @@ void Net::Impl::setPreferableBackend(Net& net, int backendId)
backendId = (Backend)getParam_DNN_BACKEND_DEFAULT();
if (backendId == DNN_BACKEND_INFERENCE_ENGINE)
backendId = DNN_BACKEND_INFERENCE_ENGINE_NGRAPH; // = getInferenceEngineBackendTypeParam();
backendId = DNN_BACKEND_INFERENCE_ENGINE_NGRAPH;
if (netWasQuantized && backendId != DNN_BACKEND_OPENCV && backendId != DNN_BACKEND_TIMVX &&
backendId != DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
@@ -186,44 +269,66 @@ void Net::Impl::setPreferableBackend(Net& net, int backendId)
}
#endif
if (preferableBackend != backendId)
{
if (mainGraph)
{
CV_LOG_WARNING(NULL, "Back-ends are not supported by the new graph engine for now");
preferableBackend = backendId;
return;
}
if (preferableBackend == backendId)
return;
clear();
if (backendId == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
{
#ifdef HAVE_ONNXRUNTIME
if (mainGraph && modelFormat == DNN_MODEL_ONNX && !modelFileName.empty())
{
preferableBackend = backendId;
ortNeedsReinit = true; // will be applied on finalizeNet()
return;
}
#endif
if (mainGraph)
{
CV_LOG_WARNING(NULL, "Back-ends are not supported by the new graph engine for now");
preferableBackend = backendId;
return;
}
clear();
if (backendId == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
{
#if defined(HAVE_INF_ENGINE)
switchToOpenVINOBackend(net);
switchToOpenVINOBackend(net);
#elif defined(ENABLE_PLUGINS)
auto& networkBackend = dnn_backend::createPluginDNNNetworkBackend("openvino");
networkBackend.switchBackend(net);
auto& networkBackend = dnn_backend::createPluginDNNNetworkBackend("openvino");
networkBackend.switchBackend(net);
#else
CV_Error(Error::StsNotImplemented, "OpenVINO backend is not available in the current OpenCV build");
CV_Error(Error::StsNotImplemented, "OpenVINO backend is not available in the current OpenCV build");
#endif
}
else if (backendId == DNN_BACKEND_CANN)
{
}
else if (backendId == DNN_BACKEND_CANN)
{
#ifdef HAVE_CANN
switchToCannBackend(net);
switchToCannBackend(net);
#else
CV_Error(Error::StsNotImplemented, "CANN backend is not availlable in the current OpenCV build");
CV_Error(Error::StsNotImplemented, "CANN backend is not availlable in the current OpenCV build");
#endif
}
else
{
preferableBackend = backendId;
}
}
else
{
preferableBackend = backendId;
}
}
void Net::Impl::setPreferableTarget(int targetId)
{
#ifdef HAVE_ONNXRUNTIME
if (mainGraph && modelFormat == DNN_MODEL_ONNX && !modelFileName.empty())
{
int resolved = IS_DNN_CUDA_TARGET(targetId) ? targetId : DNN_TARGET_CPU;
if (preferableTarget != resolved)
{
preferableTarget = resolved;
ortNeedsReinit = true; // will be applied on finalizeNet()
}
return;
}
#endif
if (mainGraph)
{
CV_LOG_WARNING(NULL, "Targets are not supported by the new graph engine for now");
@@ -286,6 +391,5 @@ void Net::Impl::setPreferableTarget(int targetId)
}
}
CV__DNN_INLINE_NS_END
}} // namespace cv::dnn
+2 -2
View File
@@ -4144,8 +4144,8 @@ Net readNetFromONNX(const String& onnxFile, int engine)
Net net = readNetFromONNX2_ORT(onnxFile);
if (net.empty())
CV_Error(Error::StsError, "DNN/ONNX/ORT: failed to load model");
if (!net.getImpl() || !net.getImpl()->ort_session)
CV_Error(Error::StsError, "DNN/ONNX/ORT: ONNX Runtime session was not initialized");
if (!net.getImpl() || net.getImpl()->modelFileName.empty())
CV_Error(Error::StsError, "DNN/ONNX/ORT: ONNX Runtime model metadata was not initialized");
return net;
#else
CV_LOG_WARNING(NULL, "DNN/ONNX/ORT: OpenCV was built without ONNX Runtime (WITH_ONNXRUNTIME=OFF). Falling back to ENGINE_AUTO.");
+10 -52
View File
@@ -5,10 +5,6 @@
#include "../precomp.hpp"
#include "../net_impl.hpp"
#ifdef HAVE_ONNXRUNTIME
#include <onnxruntime_cxx_api.h>
#endif
#include <opencv2/dnn/shape_utils.hpp>
#include <opencv2/dnn/layer_reg.private.hpp>
#include <opencv2/core/utils/filesystem.hpp>
@@ -2808,56 +2804,18 @@ Net readNetFromONNX2(const String& onnxFile)
#ifdef HAVE_ONNXRUNTIME
Net readNetFromONNX2_ORT(const String& onnxFile)
{
try
{
static auto s_ort_env = std::make_shared<Ort::Env>(ORT_LOGGING_LEVEL_WARNING, "OpenCV_DNN_ORT");
Net net;
auto impl = net.getImpl();
impl->modelFileName = onnxFile;
impl->modelFormat = DNN_MODEL_ONNX;
impl->ortNeedsReinit = true;
Net net;
auto impl = net.getImpl();
// Create an empty main graph placeholder so that callers can detect
// that a model has been loaded (e.g. !net.empty()).
impl->newGraph("ort_deferred", {}, true);
impl->ort_env = s_ort_env;
impl->ort_session_options = std::make_shared<Ort::SessionOptions>();
#ifdef _WIN32
std::wstring w_onnxFile(onnxFile.begin(), onnxFile.end());
impl->ort_session = std::make_shared<Ort::Session>(*s_ort_env, w_onnxFile.c_str(), *impl->ort_session_options);
#else
impl->ort_session = std::make_shared<Ort::Session>(*s_ort_env, onnxFile.c_str(), *impl->ort_session_options);
#endif
impl->modelFileName = onnxFile;
impl->modelFormat = DNN_MODEL_ONNX;
Ptr<Graph> g = impl->newGraph("ort_session_active", {}, true);
Ort::Session& session = *impl->ort_session;
Ort::AllocatorWithDefaultOptions allocator;
const size_t noutputs = session.GetOutputCount();
if (noutputs == 0)
CV_Error(Error::StsError, "DNN/ONNX/ORT: ORT session has no outputs");
std::vector<Arg> outs;
outs.reserve(noutputs);
for (size_t i = 0; i < noutputs; ++i)
{
Ort::AllocatedStringPtr out = session.GetOutputNameAllocated(i, allocator);
std::string n = out ? std::string(out.get()) : std::string();
if (n.empty())
n = format("output_%zu", i);
if (impl->haveArg(n))
n = format("%s_%zu", n.c_str(), i);
outs.push_back(impl->newArg(n, DNN_ARG_OUTPUT));
}
if (g)
g->setOutputs(outs);
CV_LOG_INFO(NULL, "DNN/ONNX: Successfully initialized ORT Session for " << onnxFile);
return net;
}
catch (const std::exception& e)
{
CV_LOG_WARNING(NULL, "DNN/ONNX/ORT: ORT initialization failed (" << e.what() << ")");
return Net();
}
CV_LOG_INFO(NULL, "DNN/ONNX/ORT: model registered for deferred ORT session: " << onnxFile);
return net;
}
#endif // HAVE_ONNXRUNTIME
+5 -5
View File
@@ -129,11 +129,13 @@ def apply_modnet(args, model, image):
image, args.scale, (args.width, args.height), args.mean, swapRB=args.rgb
)
model.setInput(inp)
t0 = cv.getTickCount()
out = model.forward()
t = (cv.getTickCount() - t0) / cv.getTickFrequency()
alpha_mask = postprocess_output(image, out)
alpha_3ch = cv.merge([alpha_mask / 255.0, alpha_mask / 255.0, alpha_mask / 255.0])
composite = (image.astype(np.float32) * alpha_3ch).astype(np.uint8)
return alpha_mask, composite
return alpha_mask, composite, t
def main(func_args=None):
@@ -156,10 +158,8 @@ def main(func_args=None):
args.model = findModel(args.model, args.sha1)
net = loadModel(args, engine)
alpha_mask, composite = apply_modnet(args, net, image)
t, _ = net.getPerfProfile()
label = "Inference time: %.2f ms" % (t * 1000.0 / cv.getTickFrequency())
alpha_mask, composite, t = apply_modnet(args, net, image)
label = "Inference time: %.2f ms" % (t * 1000.0)
draw_label(image, label, (0, 255, 0))
draw_label(alpha_mask, label, (255, 255, 255))
+3 -2
View File
@@ -135,7 +135,9 @@ def main(func_args=None):
# Run a model
net.setInput(blob)
t0 = cv.getTickCount()
out = net.forward()
t = (cv.getTickCount() - t0) / cv.getTickFrequency()
(h, w, _) = frame.shape
roi_rows = min(300, h)
@@ -143,8 +145,7 @@ def main(func_args=None):
frame[:roi_rows,:roi_cols,:] >>= 1
# Put efficiency information.
t, _ = net.getPerfProfile()
label = 'Inference time: %.1f ms' % (t * 1000.0 / cv.getTickFrequency())
label = 'Inference time: %.1f ms' % (t * 1000.0)
cv.putText(frame, label, (15, 30), cv.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0))
# Print predicted classes.
+3 -2
View File
@@ -99,10 +99,11 @@ def loadModel(args, engine):
return net
def apply_dexined(model, image):
t0 = cv.getTickCount()
out = model.forward()
t = (cv.getTickCount() - t0) / cv.getTickFrequency()
result,_ = post_processing(out, image.shape[:2])
t, _ = model.getPerfProfile()
label = 'Inference time: %.2f ms' % (t * 1000.0 / cv.getTickFrequency())
label = 'Inference time: %.2f ms' % (t * 1000.0)
cv.putText(image, label, (0, 15), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255))
cv.putText(result, label, (0, 15), cv.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255))
cv.imshow("Output", result)
+3 -3
View File
@@ -34,14 +34,14 @@ while cv.waitKey(1) < 0:
swapRB=True, crop=False)
net.setInput(inp)
t0 = cv.getTickCount()
out = net.forward()
t = (cv.getTickCount() - t0) / cv.getTickFrequency()
out = out.reshape(3, out.shape[2], out.shape[3])
out = out.transpose(1, 2, 0)
t, _ = net.getPerfProfile()
freq = cv.getTickFrequency() / 1000
print(t / freq, 'ms')
print('%.2f ms' % (t * 1000.0))
if args.median_filter:
out = cv.medianBlur(out, args.median_filter)
+3 -2
View File
@@ -105,7 +105,9 @@ while cv.waitKey(1) < 0:
# NOTE: In OpenCV 5.0, requesting 'detection_out_final' will fail if the .pbtxt
# does not register it as an output. See file header for details.
t0 = cv.getTickCount()
boxes, masks = net.forward(['detection_out_final', 'detection_masks'])
t = (cv.getTickCount() - t0) / cv.getTickFrequency()
numClasses = masks.shape[1]
numDetections = boxes.shape[2]
@@ -148,8 +150,7 @@ while cv.waitKey(1) < 0:
drawBox(*box)
# Put efficiency information.
t, _ = net.getPerfProfile()
label = 'Inference time: %.2f ms' % (t * 1000.0 / cv.getTickFrequency())
label = 'Inference time: %.2f ms' % (t * 1000.0)
cv.putText(frame, label, (0, 15), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0))
showLegend(classes)
+4 -4
View File
@@ -367,8 +367,11 @@ int main(int argc, char** argv)
}
preprocess(frame, net, Size(inpWidth, inpHeight));
TickMeter tickMeter;
vector<Mat> outs;
tickMeter.start();
net.forward(outs, net.getUnconnectedOutLayersNames());
tickMeter.stop();
classIds.clear();
confidences.clear();
@@ -378,13 +381,10 @@ int main(int argc, char** argv)
drawPred(classIds, confidences, boxes, frame, sans, stdSize, stdWeight, stdImgSize, stdThickness);
vector<double> layersTimes;
int imgWidth = max(frame.rows, frame.cols);
int size = static_cast<int>((stdSize * imgWidth) / (stdImgSize * 1.5));
int weight = static_cast<int>((stdWeight * imgWidth) / (stdImgSize * 1.5));
double freq = getTickFrequency() / 1000;
double t = net.getPerfProfile(layersTimes) / freq;
string label = format("FPS: %.2f", 1000/t);
string label = format("FPS: %.2f", 1000.0 / tickMeter.getTimeMilli());
putText(frame, label, Point(0, size), Scalar(0, 255, 0), sans, size, weight);
imshow(kWinName, frame);
}
+3 -3
View File
@@ -82,7 +82,9 @@ while cv.waitKey(1) < 0:
inp = cv.dnn.blobFromImage(frame, inScale, (inWidth, inHeight),
(0, 0, 0), swapRB=False, crop=False)
net.setInput(inp)
t0 = cv.getTickCount()
out = net.forward()
t = (cv.getTickCount() - t0) / cv.getTickFrequency()
assert(len(BODY_PARTS) <= out.shape[1])
@@ -115,8 +117,6 @@ while cv.waitKey(1) < 0:
cv.ellipse(frame, points[idFrom], (3, 3), 0, 0, 360, (0, 0, 255), cv.FILLED)
cv.ellipse(frame, points[idTo], (3, 3), 0, 0, 360, (0, 0, 255), cv.FILLED)
t, _ = net.getPerfProfile()
freq = cv.getTickFrequency() / 1000
cv.putText(frame, '%.2fms' % (t / freq), (10, 20), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0))
cv.putText(frame, '%.2f ms' % (t * 1000.0), (10, 20), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0))
cv.imshow('OpenPose using OpenCV', frame)
+3 -2
View File
@@ -132,12 +132,13 @@ def apply_super_resolution(net, image, args):
)
net.setInput(blob)
t0 = cv.getTickCount()
output = net.forward()
t = (cv.getTickCount() - t0) / cv.getTickFrequency()
result = postprocess_output(output, args, original_shape)
t, _ = net.getPerfProfile()
label = "Inference time: %.2f ms" % (t * 1000.0 / cv.getTickFrequency())
label = "Inference time: %.2f ms" % (t * 1000.0)
cv.putText(result, label, (10, 30), cv.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
return result