diff --git a/3rdparty/orbbecsdk/orbbecsdk.cmake b/3rdparty/orbbecsdk/orbbecsdk.cmake index db51aee9c4..8833a30d5a 100644 --- a/3rdparty/orbbecsdk/orbbecsdk.cmake +++ b/3rdparty/orbbecsdk/orbbecsdk.cmake @@ -1,18 +1,34 @@ +ocv_update(ORBBEC_SDK_VERSION "2") +ocv_update(ORBBEC_SDK_DOWNLOAD_DIR "${OpenCV_BINARY_DIR}/3rdparty/orbbecsdk") + function(download_orbbec_sdk root_var) - set(ORBBECSDK_DOWNLOAD_DIR "${OpenCV_BINARY_DIR}/3rdparty/orbbecsdk") - set(ORBBECSDK_FILE_HASH_CMAKE "e7566fa915a1b0c02640df41891916fe") - ocv_download(FILENAME "v1.9.4.tar.gz" - HASH ${ORBBECSDK_FILE_HASH_CMAKE} - URL "https://github.com/orbbec/OrbbecSDK/archive/refs/tags/v1.9.4/" - DESTINATION_DIR ${ORBBECSDK_DOWNLOAD_DIR} + if(ORBBEC_SDK_VERSION STREQUAL "1") + set(ORBBEC_SDK_FILE_HASH_CMAKE "e7566fa915a1b0c02640df41891916fe") + set(ORBBEC_SDK_GIT_TAG "1.9.4") + add_definitions(-DORBBEC_SDK_VERSION_MAJOR=1) + elseif(ORBBEC_SDK_VERSION STREQUAL "2") + set(ORBBEC_SDK_FILE_HASH_CMAKE "d828ac15618a56b9ae325bada8676e28") + set(ORBBEC_SDK_GIT_TAG "2.5.5") + add_definitions(-DORBBEC_SDK_VERSION_MAJOR=2) + else() + message(STATUS "Unsupported OrbbecSDK version: ${ORBBEC_SDK_VERSION}, use default version 2") + set(ORBBEC_SDK_FILE_HASH_CMAKE "d828ac15618a56b9ae325bada8676e28") + set(ORBBEC_SDK_GIT_TAG "2.5.5") + add_definitions(-DORBBEC_SDK_VERSION_MAJOR=2) + endif() + + ocv_download(FILENAME "v${ORBBEC_SDK_GIT_TAG}.tar.gz" + HASH ${ORBBEC_SDK_FILE_HASH_CMAKE} + URL "https://github.com/orbbec/OrbbecSDK/archive/refs/tags/v${ORBBEC_SDK_GIT_TAG}/" + DESTINATION_DIR ${ORBBEC_SDK_DOWNLOAD_DIR} ID OrbbecSDK STATUS res UNPACK RELATIVE_URL ) if(${res}) - message(STATUS "orbbec sdk downloaded to: ${ORBBECSDK_DOWNLOAD_DIR}") - set(${root_var} "${ORBBECSDK_DOWNLOAD_DIR}/OrbbecSDK-1.9.4" PARENT_SCOPE) + message(STATUS "OrbbecSDK downloaded to: ${ORBBEC_SDK_DOWNLOAD_DIR}") + set(${root_var} "${ORBBEC_SDK_DOWNLOAD_DIR}/OrbbecSDK-${ORBBEC_SDK_GIT_TAG}" PARENT_SCOPE) else() - message(FATAL_ERROR "Failed to download orbbec sdk") + message(FATAL_ERROR "Failed to download OrbbecSDK") endif() endfunction() \ No newline at end of file diff --git a/3rdparty/tbb/CMakeLists.txt b/3rdparty/tbb/CMakeLists.txt index 10f60094ae..2d25a3a08e 100644 --- a/3rdparty/tbb/CMakeLists.txt +++ b/3rdparty/tbb/CMakeLists.txt @@ -106,6 +106,11 @@ ocv_warnings_disable(CMAKE_CXX_FLAGS set(TBB_SOURCE_FILES ${lib_srcs} ${lib_hdrs}) set(tbb_version_file "version_string.ver") +if(NOT BUILD_INFO_SKIP_SYSTEM_VERSION) + set(TBB_HOST_VERSION " ${CMAKE_HOST_SYSTEM_VERSION}") +else() + set(TBB_HOST_VERSION "") +endif() configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${tbb_version_file}.cmakein" "${CMAKE_CURRENT_BINARY_DIR}/${tbb_version_file}" @ONLY) list(APPEND TBB_SOURCE_FILES "${CMAKE_CURRENT_BINARY_DIR}/${tbb_version_file}") diff --git a/3rdparty/tbb/version_string.ver.cmakein b/3rdparty/tbb/version_string.ver.cmakein index 1f8f0b818d..2953c1bc0c 100644 --- a/3rdparty/tbb/version_string.ver.cmakein +++ b/3rdparty/tbb/version_string.ver.cmakein @@ -1,6 +1,6 @@ #define __TBB_VERSION_STRINGS(N) \ #N": BUILD_PACKAGE OpenCV @OPENCV_VERSION@" ENDL \ -#N": BUILD_HOST @CMAKE_HOST_SYSTEM_NAME@ @CMAKE_HOST_SYSTEM_VERSION@ @CMAKE_HOST_SYSTEM_PROCESSOR@" ENDL \ +#N": BUILD_HOST @CMAKE_HOST_SYSTEM_NAME@@TBB_HOST_VERSION@ @CMAKE_HOST_SYSTEM_PROCESSOR@" ENDL \ #N": BUILD_TARGET @CMAKE_SYSTEM_NAME@ @CMAKE_SYSTEM_VERSION@ @CMAKE_SYSTEM_PROCESSOR@" ENDL \ #N": BUILD_COMPILER @CMAKE_CXX_COMPILER@ (ver @CMAKE_CXX_COMPILER_VERSION@)" ENDL \ #N": BUILD_COMMAND use cv::getBuildInformation() for details" ENDL diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f24f655a1..49c325c346 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1152,7 +1152,11 @@ endif() if(OPENCV_TIMESTAMP) status(" Timestamp:" ${OPENCV_TIMESTAMP}) endif() -status(" Host:" ${CMAKE_HOST_SYSTEM_NAME} ${CMAKE_HOST_SYSTEM_VERSION} ${CMAKE_HOST_SYSTEM_PROCESSOR}) +if(NOT BUILD_INFO_SKIP_SYSTEM_VERSION) + status(" Host:" ${CMAKE_HOST_SYSTEM_NAME} ${CMAKE_HOST_SYSTEM_VERSION} ${CMAKE_HOST_SYSTEM_PROCESSOR}) +else() + status(" Host:" ${CMAKE_HOST_SYSTEM_NAME} ${CMAKE_HOST_SYSTEM_PROCESSOR}) +endif() if(CMAKE_CROSSCOMPILING) status(" Target:" ${CMAKE_SYSTEM_NAME} ${CMAKE_SYSTEM_VERSION} ${CMAKE_SYSTEM_PROCESSOR}) endif() @@ -1543,7 +1547,7 @@ endif() if(WITH_FFMPEG OR HAVE_FFMPEG) if(OPENCV_FFMPEG_USE_FIND_PACKAGE) status(" FFMPEG:" HAVE_FFMPEG THEN "YES (find_package)" ELSE "NO (find_package)") - elseif(WIN32) + elseif(WIN32 AND NOT ARM AND NOT AARCH64) status(" FFMPEG:" HAVE_FFMPEG THEN "YES (prebuilt binaries)" ELSE NO) else() status(" FFMPEG:" HAVE_FFMPEG THEN YES ELSE NO) diff --git a/cmake/OpenCVDetectCXXCompiler.cmake b/cmake/OpenCVDetectCXXCompiler.cmake index 2049acfc14..47db7196d8 100644 --- a/cmake/OpenCVDetectCXXCompiler.cmake +++ b/cmake/OpenCVDetectCXXCompiler.cmake @@ -184,6 +184,8 @@ elseif(MSVC) set(OpenCV_RUNTIME vc16) elseif(MSVC_VERSION MATCHES "^19[34][0-9]$") set(OpenCV_RUNTIME vc17) + elseif(MSVC_VERSION MATCHES "^195[0-9]$") + set(OpenCV_RUNTIME vc18) else() message(WARNING "OpenCV does not recognize MSVC_VERSION \"${MSVC_VERSION}\". Cannot set OpenCV_RUNTIME") endif() diff --git a/cmake/templates/OpenCVConfig.root-WIN32.cmake.in b/cmake/templates/OpenCVConfig.root-WIN32.cmake.in index 62e36272f3..cc9fd8745f 100644 --- a/cmake/templates/OpenCVConfig.root-WIN32.cmake.in +++ b/cmake/templates/OpenCVConfig.root-WIN32.cmake.in @@ -141,15 +141,33 @@ elseif(MSVC) set(OpenCV_RUNTIME vc17) check_one_config(has_VS2022) if(NOT has_VS2022) - set(OpenCV_RUNTIME vc16) - check_one_config(has_VS2019) - if(NOT has_VS2019) - set(OpenCV_RUNTIME vc15) # selecting previous compatible runtime version - check_one_config(has_VS2017) - if(NOT has_VS2017) - set(OpenCV_RUNTIME vc14) # selecting previous compatible runtime version - endif() - endif() + set(OpenCV_RUNTIME vc16) # selecting previous compatible runtime version + check_one_config(has_VS2019) + if(NOT has_VS2019) + set(OpenCV_RUNTIME vc15) # selecting previous compatible runtime version + check_one_config(has_VS2017) + if(NOT has_VS2017) + set(OpenCV_RUNTIME vc14) # selecting previous compatible runtime version + endif() + endif() + endif() + elseif(MSVC_VERSION MATCHES "^195[0-9]$") + set(OpenCV_RUNTIME vc18) + check_one_config(has_VS2026) + if(NOT has_VS2026) + set(OpenCV_RUNTIME vc17) # selecting previous compatible runtime version + check_one_config(has_VS2022) + if(NOT has_VS2022) + set(OpenCV_RUNTIME vc16) # selecting previous compatible runtime version + check_one_config(has_VS2019) + if(NOT has_VS2019) + set(OpenCV_RUNTIME vc15) # selecting previous compatible runtime version + check_one_config(has_VS2017) + if(NOT has_VS2017) + set(OpenCV_RUNTIME vc14) # selecting previous compatible runtime version + endif() + endif() + endif() endif() endif() elseif(MINGW) diff --git a/doc/js_tutorials/js_assets/js_image_arithmetics_bitwise.html b/doc/js_tutorials/js_assets/js_image_arithmetics_bitwise.html index 05c0ffd730..ccf0bbbda7 100644 --- a/doc/js_tutorials/js_assets/js_image_arithmetics_bitwise.html +++ b/doc/js_tutorials/js_assets/js_image_arithmetics_bitwise.html @@ -82,7 +82,7 @@ cv.bitwise_and(logo, logo, imgFg, mask); // Put logo in ROI and modify the main image cv.add(imgBg, imgFg, sum); -dst = src.clone(); +dst = src.mat_clone(); for (let i = 0; i < logo.rows; i++) { for (let j = 0; j < logo.cols; j++) { dst.ucharPtr(i, j)[0] = sum.ucharPtr(i, j)[0]; diff --git a/doc/js_tutorials/js_assets/js_imgproc_camera.html b/doc/js_tutorials/js_assets/js_imgproc_camera.html index 2df68d7f33..273b11ff57 100644 --- a/doc/js_tutorials/js_assets/js_imgproc_camera.html +++ b/doc/js_tutorials/js_assets/js_imgproc_camera.html @@ -248,7 +248,7 @@ function backprojection(src) { if (base instanceof cv.Mat) { base.delete(); } - base = src.clone(); + base = src.mat_clone(); cv.cvtColor(base, base, cv.COLOR_RGB2HSV, 0); } cv.cvtColor(src, dstC3, cv.COLOR_RGB2HSV, 0); diff --git a/doc/js_tutorials/js_assets/js_intelligent_scissors.html b/doc/js_tutorials/js_assets/js_intelligent_scissors.html index 1782dc6f03..f48dd07e4b 100644 --- a/doc/js_tutorials/js_assets/js_intelligent_scissors.html +++ b/doc/js_tutorials/js_assets/js_intelligent_scissors.html @@ -53,7 +53,7 @@ canvas.addEventListener('click', e => { }); canvas.addEventListener('mousemove', e => { let x = e.offsetX, y = e.offsetY; //console.log(x, y); - let dst = src.clone(); + let dst = src.mat_clone(); if (hasMap && x >= 0 && x < src.cols && y >= 0 && y < src.rows) { let contour = new cv.Mat(); diff --git a/doc/js_tutorials/js_core/js_basic_ops/js_basic_ops.markdown b/doc/js_tutorials/js_core/js_basic_ops/js_basic_ops.markdown index ee110c37cb..74c3b9cc86 100644 --- a/doc/js_tutorials/js_core/js_basic_ops/js_basic_ops.markdown +++ b/doc/js_tutorials/js_core/js_basic_ops/js_basic_ops.markdown @@ -77,12 +77,14 @@ How to copy Mat There are 2 ways to copy a Mat: @code{.js} -// 1. Clone -let dst = src.clone(); +// 1. Clone (deep copy) +let dst = src.mat_clone(); // 2. CopyTo(only entries indicated in the mask are copied) src.copyTo(dst, mask); @endcode +@note In OpenCV.js, use `mat_clone()` instead of `clone()` to ensure deep copy behavior. The `clone()` method may perform shallow copy due to Emscripten embind limitations. + How to convert the type of Mat ------------------------------ diff --git a/doc/py_tutorials/py_setup/py_pip_install/py_pip_install.markdown b/doc/py_tutorials/py_setup/py_pip_install/py_pip_install.markdown new file mode 100644 index 0000000000..3630b3067d --- /dev/null +++ b/doc/py_tutorials/py_setup/py_pip_install/py_pip_install.markdown @@ -0,0 +1,116 @@ +# Install OpenCV for Python with pip {#tutorial_py_pip_install} + +This quick-start shows the **recommended** way for most users to get OpenCV in Python: install from +**PyPI** with `pip`. It also explains virtual environments, platform notes, and common troubleshooting. +If you need OS‑specific alternatives (system packages or source builds), see the OS pages linked +below, but those are **not required** for typical Python use. + +@note: OpenCV team maintains **PyPI** packages only. Conda distributions and platform specific builds +are community builds and hardware vendor builds and may differ from the official one. + +## Quick start + +```bash +# 1) Create and activate a virtual environment (recommended) +python -m venv .venv +# Windows: +.venv\Scripts\activate +# Linux/macOS: +source .venv/bin/activate + +# 2) Upgrade pip tooling +python -m pip install --upgrade pip setuptools wheel + +# 3) Install OpenCV from PyPI (choose ONE) +pip install opencv-python # main package (most users) +# or +pip install opencv-contrib-python # + extra modules (contrib) +# or +pip install opencv-python-headless # no GUI/backends (servers/CI) +# or +pip install opencv-contrib-python-headless # no GUI/backends with extra modules (servers/CI) +``` + +### Tiny hello‑world + +```python +import cv2 as cv +import numpy as np + +print("OpenCV:", cv.__version__) +img = np.zeros((120, 400, 3), dtype=np.uint8) +cv.putText(img, "OpenCV OK", (10, 80), cv.FONT_HERSHEY_SIMPLEX, 2, (255,255,255), 3) +# If you installed a non-headless build, you can display a window: +# cv.imshow("hello", img); cv.waitKey(0) +# Always safe (headless or not): save to file +cv.imwrite("hello.png", img) +``` + +## Virtual environments and IDEs + +Using a virtual environment keeps project dependencies isolated. Tools that create or activate envs include: + +- `venv` (built-in) and `virtualenv` +- Conda environments +- IDEs (VS Code, PyCharm) that may **auto-create and auto-activate** an env per workspace + +If imports fail inside an IDE, verify the interpreter selected by the IDE matches the environment +where you installed OpenCV. + +## OS notes + +- **Linux:** Your default Python may be `python3`. Use `python3 -m venv .venv` and `python3 -m pip ...`. +If you cannot use a virtual env, `pip --user` installs to your home directory: `python3 -m pip install --user opencv-python`. +- **Windows:** Install Python from [python.org] or via `winget install Python.Python.3`. Make sure +**“Add python to PATH”** is enabled or use the **“Open in terminal”** from your IDE, which selects +the right interpreter automatically. +- **macOS:** Use the system `python3` or a managed one (Homebrew or Python.org). +Always prefer a virtual environment. +- **Raspberry Pi / ARM boards:** Prebuilt wheels may not exist for some Pi OS / Python combinations. +See **Troubleshooting** below. + +## Choosing a PyPI variant + +- `opencv-python`: core OpenCV modules with GUI/backends +- `opencv-contrib-python`: includes **contrib** modules in addition to the core +- `opencv-python-headless`: no GUI/backends (ideal for servers/containers/CI) +- `opencv-contrib-python-headless`: contrib + headless + +Install exactly **one** of these per environment. + +## Troubleshooting + +Please start with opencv-python project [README](https://github.com/opencv/opencv-python/blob/4.x/README.md) + +**Pip is trying to build from source** +Symptoms: very long build step, CMake errors, compiler errors. +Fixes: +- Upgrade build tooling: `python -m pip install --upgrade pip setuptools wheel` +- Ensure your Python version is supported by the chosen package. +- If you are on an uncommon platform or Python build, switch to a supported Python or try a different +variant (headless vs non‑headless). + +**“No matching distribution found” or “Unsupported wheel”** +- Confirm your Python version (e.g., `python -V`). Choose a wheel that supports that version +(manylinux/macOS/Windows wheels on PyPI target specific Python versions). +- Create a fresh virtual environment with a mainstream Python (e.g., 3.10–3.12 for now) and reinstall. + +**Raspberry Pi / ARM** +- Wheels may lag behind new Python/Pi OS releases. Try `opencv-python-headless` first. If +unavailable, consider system packages for camera/GUI pieces, or build from source following +the OS page linked below. + +**Import works in terminal but fails in IDE** +- The IDE is using a different interpreter. Select the **same** environment inside your +IDE’s interpreter settings. + +## What about system packages or building from source? + +For beginners using Python, **PyPI is recommended**. Native distribution packages and full source +builds are better suited to advanced users with platform‑specific needs. You can still find them on +the OS‑specific pages, moved under “Alternatives.” + +## See also + +- @ref tutorial_py_root +- OS pages: @ref tutorial_py_setup_in_windows, @ref tutorial_py_setup_in_ubuntu, @ref tutorial_py_setup_in_fedora diff --git a/doc/py_tutorials/py_setup/py_setup_in_ubuntu/py_setup_in_ubuntu.markdown b/doc/py_tutorials/py_setup/py_setup_in_ubuntu/py_setup_in_ubuntu.markdown index b68e7e4797..ee6ab54d59 100644 --- a/doc/py_tutorials/py_setup/py_setup_in_ubuntu/py_setup_in_ubuntu.markdown +++ b/doc/py_tutorials/py_setup/py_setup_in_ubuntu/py_setup_in_ubuntu.markdown @@ -1,6 +1,8 @@ Install OpenCV-Python in Ubuntu {#tutorial_py_setup_in_ubuntu} =============================== +@note: Please prefer binaries distributed with PyPI, if possible. See @ref tutorial_py_pip_install for details. + Goals ----- diff --git a/doc/py_tutorials/py_setup/py_setup_in_windows/py_setup_in_windows.markdown b/doc/py_tutorials/py_setup/py_setup_in_windows/py_setup_in_windows.markdown index ed862757a6..20f136dd18 100644 --- a/doc/py_tutorials/py_setup/py_setup_in_windows/py_setup_in_windows.markdown +++ b/doc/py_tutorials/py_setup/py_setup_in_windows/py_setup_in_windows.markdown @@ -18,13 +18,13 @@ Installing OpenCV from prebuilt binaries -# Below Python packages are to be downloaded and installed to their default locations. - -# Python 3.x (3.4+) or Python 2.7.x from [here](https://www.python.org/downloads/). + -# Python 3.x (3.4+) from [here](https://www.python.org/downloads/). -# Numpy package (for example, using `pip install numpy` command). -# Matplotlib (`pip install matplotlib`) (*Matplotlib is optional, but recommended since we use it a lot in our tutorials*). --# Install all packages into their default locations. Python will be installed to `C:/Python27/` in case of Python 2.7. +-# Install all packages into their default locations. Python will be installed to `C:/Python34/` in case of Python 3.4. -# After installation, open Python IDLE. Enter **import numpy** and make sure Numpy is working fine. @@ -32,11 +32,11 @@ Installing OpenCV from prebuilt binaries [SourceForge site](https://sourceforge.net/projects/opencvlibrary/files/) and double-click to extract it. --# Goto **opencv/build/python/2.7** folder. +-# Goto **opencv/build/python/3.4** folder. --# Copy **cv2.pyd** to **C:/Python27/lib/site-packages**. +-# Copy **cv2.pyd** to **C:/Python34/lib/site-packages**. --# Copy the **opencv_world.dll** file to **C:/Python27/lib/site-packages** +-# Copy the **opencv_world.dll** file to **C:/Python34/lib/site-packages** -# Open Python IDLE and type following codes in Python terminal. @code diff --git a/doc/py_tutorials/py_setup/py_table_of_contents_setup.markdown b/doc/py_tutorials/py_setup/py_table_of_contents_setup.markdown index a5ea46d750..813e899320 100644 --- a/doc/py_tutorials/py_setup/py_table_of_contents_setup.markdown +++ b/doc/py_tutorials/py_setup/py_table_of_contents_setup.markdown @@ -6,6 +6,11 @@ Introduction to OpenCV {#tutorial_py_table_of_contents_setup} Getting Started with OpenCV-Python +- @subpage tutorial_py_pip_install + + Install OpenCV for + Python with pip + - @subpage tutorial_py_setup_in_windows Set Up diff --git a/doc/tutorials/app/orbbec_uvc.markdown b/doc/tutorials/app/orbbec_uvc.markdown index 7ddaa4d783..f40ed755d6 100644 --- a/doc/tutorials/app/orbbec_uvc.markdown +++ b/doc/tutorials/app/orbbec_uvc.markdown @@ -34,6 +34,15 @@ make sudo make install ``` +By default, when `-DOBSENSOR_USE_ORBBEC_SDK=ON` is enabled, OrbbecSDK v2 is used (i.e., `ORBBEC_SDK_VERSION` defaults to `2`); it supports the entire Orbbec Gemini 330 series. + +If you need legacy cameras such as Orbbec Femto, Gemini2XL, or Astra+, switch to OrbbecSDK v1 with the flag `-DORBBEC_SDK_VERSION=1`: +```bash + cmake -DOBSENSOR_USE_ORBBEC_SDK=ON -DORBBEC_SDK_VERSION=1 .. + make -j + sudo make install +``` + Code ---- diff --git a/doc/tutorials/introduction/linux_gdb_pretty_printer/linux_gdb_pretty_printer.markdown b/doc/tutorials/introduction/linux_gdb_pretty_printer/linux_gdb_pretty_printer.markdown index b0b8d404a0..0147ae2f58 100644 --- a/doc/tutorials/introduction/linux_gdb_pretty_printer/linux_gdb_pretty_printer.markdown +++ b/doc/tutorials/introduction/linux_gdb_pretty_printer/linux_gdb_pretty_printer.markdown @@ -1,7 +1,7 @@ Using OpenCV with gdb-powered IDEs {#tutorial_linux_gdb_pretty_printer} ===================== -@prev_tutorial{tutorial_linux_install} +@prev_tutorial{tutorial_oneapi_install} @next_tutorial{tutorial_linux_gcc_cmake} | | | diff --git a/doc/tutorials/introduction/linux_install/linux_install.markdown b/doc/tutorials/introduction/linux_install/linux_install.markdown index 63eb0a3403..187b8f1008 100644 --- a/doc/tutorials/introduction/linux_install/linux_install.markdown +++ b/doc/tutorials/introduction/linux_install/linux_install.markdown @@ -2,7 +2,7 @@ Installation in Linux {#tutorial_linux_install} ===================== @prev_tutorial{tutorial_env_reference} -@next_tutorial{tutorial_linux_gdb_pretty_printer} +@next_tutorial{tutorial_oneapi_install} | | | | -: | :- | diff --git a/doc/tutorials/introduction/oneapi_install/oneapi_install.markdown b/doc/tutorials/introduction/oneapi_install/oneapi_install.markdown new file mode 100644 index 0000000000..414517df91 --- /dev/null +++ b/doc/tutorials/introduction/oneapi_install/oneapi_install.markdown @@ -0,0 +1,106 @@ +Building OpenCV with oneAPI {#tutorial_oneapi_install} +=========================== + + +@prev_tutorial{tutorial_linux_install} +@next_tutorial{tutorial_linux_gcc_cmake} + +| | | +| -: | :- | +| Original author | Alessandro de Oliveira Faria | +| Compatibility | OpenCV >= 4.11.0 | + +@tableofcontents + +# Quick start {#tutorial_oneapi_install_quick_start} + +**oneAPI** is Intel's open initiative (now also maintained by the UXL Foundation) that combines a specification and a set of toolkits for programming CPUs, GPUs, FPGAs and NPUs with a single code base. The core is the SYCL standard (single-source C++ for parallelism), complemented by high-performance libraries — oneTBB (parallelism), oneMKL (linear algebra), oneDNN (neural networks), oneVPL (video), etc. Thus, when you compile with oneAPI's DPC++ (icpx) compiler, the binary gains optimized execution paths that choose, at runtime, the best vector instructions or the available device, without changing the source code. + +## Why compile OpenCV with the oneAPI ecosystem when targeting the CPU: + +* Simple, because by enabling the CMake options -DWITH_SYCL=ON -DWITH_TBB=ON -DWITH_ONEDNN=ON -DWITH_IPP=ON and using the icpx compiler, the OpenCV core starts to directly invoke oneAPI libraries. +* oneDNN replaces the generic kernels of the cv::dnn layer with implementations that exploit AVX2, AVX-512, AMX and VNNI, accelerating convolutions, matmul and network post-processing by up to 3-5× on modern CPUs. +* oneTBB takes over the thread pool, scheduling filters like cv::resize, cv::GaussianBlur or the G-API pipeline across all cores without busy-wait. +* IPP (now distributed via oneAPI Base Toolkit) provides optimized intrinsic routines for elementary operations (SAD, DFT, median blur), which OpenCV calls when it encounters the HAVE_IPP macro. +* All this happens transparently: the source code that uses cv::Mat remains the same, but the linked symbols point to vectorized versions, and the internal dispatcher selects the appropriate vector width at runtime. + + +## CPU Processor Requirements + +Systems based on Intel® 64 architectures below are supported both as host and target platforms. + +* Intel® Core™ processor family or higher +* Intel® Xeon® processor family +* Intel® Xeon® Scalable processor family + + +### Requirements for Accelerators + +* Integrated GEN9 (and higher) GPUs. See source in Intel® Graphics Compiler for OpenCL™ +* FPGA Card: see Intel(R) DPC++ Compiler System Requirements. + +### Disk Space Requirements + +* 3.3 GB of disk space (minimum) on a standard installation. + +@note: During the installation process, the installer may need up to 6 GB of additional temporary disk storage to manage the download and intermediate installation files. + + +### Memory Requirements + +* 8 GB RAM recommended + + +## How To install oneAPI + +Installing oneAPI: To quickly set up the oneAPI ecosystem on openSUSE, simply follow the official guide https://www.intel.com/content/www/us/en/developer/articles/guide/installation-guide-for-oneapi-toolkits.html, which shows you how to enable the distribution’s dedicated repository (zypper ar … oneAPI) and install the metapackages ― for example, intel-basekit (DPC++, TBB, oneDNN, IPP compilers) and, optionally, intel-hpckit or intel-renderkit if you need HPC or graphics tools. The guide also explains post-installation tweaks, such as loading the environment with source /opt/intel/oneapi/setvars.sh , ensuring that the binaries (icpx, dpcpp) and libraries are immediately available in your shell for compiling and running accelerated applications. + +## Download, Github Instruction, Build and Install + +1. Below are the commands to download last version (latest release on the date of publication of this text): + +``` +git clone https://github.com/opencv/opencv.git +``` + +2. and make sure you are using branch 4.*: + +``` +git status +On branch 4.x +``` + +3. Navigate to OpenCV repository and prepare the build folder: + +``` +cd opencv +mkdir build +cd build +``` + +4. Set up Intel oneAPI environment variables. For default installation: + +``` +source /opt/intel/oneapi/setvars.sh +``` + +5. Run CMake * with Intel® oneAPI DPC++/C++ Compiler to configure the project: + +``` + cmake -DCMAKE_C_COMPILER=icx \ + -DCMAKE_CXX_COMPILER=icpx + -DCMAKE_CXX_FLAGS="-march=native -mavx -mfma -msse -msse2" .. + cmake --build . +``` +6. Now Make sure openCV* is compiled with Intel® oneAPI DPC++/C++ Compiler and install: + +``` +readelf -p .comment bin/opencv_annotation +String dump of section '.comment': + [ 0] GCC: (SUSE Linux) 13.3.1 20250313 [revision 4ef1d8c84faeebffeb0cc01ee22e891b41e5c4e0] + [ 56] GCC: (SUSE Linux) 12.3.0 + [ 6f] Intel(R) oneAPI DPC++/C++ Compiler 2025.1.1 (2025.1.1.20250418) +make install +``` + +Have fun... diff --git a/doc/tutorials/introduction/table_of_content_introduction.markdown b/doc/tutorials/introduction/table_of_content_introduction.markdown index 4d7b0eb94e..2f8303ad6e 100644 --- a/doc/tutorials/introduction/table_of_content_introduction.markdown +++ b/doc/tutorials/introduction/table_of_content_introduction.markdown @@ -9,6 +9,7 @@ Introduction to OpenCV {#tutorial_table_of_content_introduction} ##### Linux - @subpage tutorial_linux_install +- @subpage tutorial_oneapi_install - @subpage tutorial_linux_gdb_pretty_printer - @subpage tutorial_linux_gcc_cmake - @subpage tutorial_linux_eclipse diff --git a/doc/tutorials/introduction/windows_install/windows_install.markdown b/doc/tutorials/introduction/windows_install/windows_install.markdown index d9b5f8d78b..3498f36ce3 100644 --- a/doc/tutorials/introduction/windows_install/windows_install.markdown +++ b/doc/tutorials/introduction/windows_install/windows_install.markdown @@ -379,6 +379,9 @@ our OpenCV library that we use in our projects. Start up a command window and en setx OpenCV_DIR D:\OpenCV\build\x64\vc17 (suggested for Visual Studio 2022 - 64 bit Windows) setx OpenCV_DIR D:\OpenCV\build\x86\vc17 (suggested for Visual Studio 2022 - 32 bit Windows) + + setx OpenCV_DIR D:\OpenCV\build\x64\vc18 (suggested for Visual Studio 2026 - 64 bit Windows) + setx OpenCV_DIR D:\OpenCV\build\x86\vc18 (suggested for Visual Studio 2026 - 32 bit Windows) @endcode Here the directory is where you have your OpenCV binaries (*extracted* or *built*). You can have different platform (e.g. x64 instead of x86) or compiler type, so substitute appropriate value. diff --git a/hal/ipp/CMakeLists.txt b/hal/ipp/CMakeLists.txt index 1aa8e6abd0..5ff630c8c0 100644 --- a/hal/ipp/CMakeLists.txt +++ b/hal/ipp/CMakeLists.txt @@ -21,7 +21,7 @@ add_library(ipphal STATIC #TODO: HAVE_IPP_ICV and HAVE_IPP_IW added as private macro till OpenCV itself is # source of IPP and public definitions lead to redefinition warning # The macro should be redefined as PUBLIC when IPP part is removed from core -# to make HAL the source of IPP integration +# to make HAL the source of IPP integration. The same is true for WITH_IPP_CALLS_ENFORCED if(HAVE_IPP_ICV) target_compile_definitions(ipphal PRIVATE HAVE_IPP_ICV) endif() @@ -30,6 +30,11 @@ if(HAVE_IPP_IW) target_compile_definitions(ipphal PRIVATE HAVE_IPP_IW) endif() +if(WITH_IPP_CALLS_ENFORCED) + target_compile_definitions(ipphal PRIVATE IPP_CALLS_ENFORCED) + message("WITH_IPP_CALLS_ENFORCED=${WITH_IPP_CALLS_ENFORCED}: enforced IPP calls are enabled in IPP HAL") +endif() + target_include_directories(ipphal PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include") ocv_warnings_disable(CMAKE_CXX_FLAGS -Wno-suggest-override) diff --git a/modules/3d/perf/perf_translation2d.cpp b/modules/3d/perf/perf_translation2d.cpp deleted file mode 100644 index 702325faf4..0000000000 --- a/modules/3d/perf/perf_translation2d.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// (3-clause BSD License) -// -// Copyright (C) 2015-2016, OpenCV Foundation, all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * Neither the names of the copyright holders nor the names of the contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall copyright holders or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -#include "perf_precomp.hpp" -#include -#include - -namespace opencv_test -{ -using namespace perf; - -CV_ENUM(Method, RANSAC, LMEDS) -typedef tuple TranslationParams; -typedef TestBaseWithParam EstimateTranslation2DPerf; -#define ESTIMATE_PARAMS Combine(Values(1000), Values(0.95), Method::all(), Values(10, 0)) - -static float rngIn(float from, float to) { return from + (to - from) * (float)theRNG(); } - -static cv::Mat rngTranslationMat() -{ - double tx = rngIn(-2.f, 2.f); - double ty = rngIn(-2.f, 2.f); - double t[2*3] = { 1.0, 0.0, tx, - 0.0, 1.0, ty }; - return cv::Mat(2, 3, CV_64F, t).clone(); -} - -PERF_TEST_P(EstimateTranslation2DPerf, EstimateTranslation2D, ESTIMATE_PARAMS) -{ - TranslationParams params = GetParam(); - const int n = get<0>(params); - const double confidence = get<1>(params); - const int method = get<2>(params); - const size_t refining = get<3>(params); - - //fixed seed so the generated data are deterministic - cv::theRNG().state = 0x12345678; - // ground-truth pure translation - cv::Mat T = rngTranslationMat(); - - // LMEDS can't handle more than 50% outliers (by design) - int m; - if (method == LMEDS) - m = 3*n/5; - else - m = 2*n/5; - - const float shift_outl = 15.f; - const float noise_level = 20.f; - - cv::Mat fpts(1, n, CV_32FC2); - cv::Mat tpts(1, n, CV_32FC2); - - randu(fpts, 0.f, 100.f); - transform(fpts, tpts, T); - - // add outliers to the tail [m, n) - cv::Mat outliers = tpts.colRange(m, n); - outliers.reshape(1) += shift_outl; - - cv::Mat noise(outliers.size(), outliers.type()); - randu(noise, 0.f, noise_level); - outliers += noise; - - cv::Vec2d T_est; - std::vector inliers(n); - - warmup(inliers, WARMUP_WRITE); - warmup(fpts, WARMUP_READ); - warmup(tpts, WARMUP_READ); - - TEST_CYCLE() - { - T_est = estimateTranslation2D(fpts, tpts, inliers, method, - /*ransacReprojThreshold=*/3.0, - /*maxIters=*/2000, - /*confidence=*/confidence, - /*refineIters=*/refining); - } - - // Convert to Mat for SANITY_CHECK consistency - cv::Mat T_est_mat = (cv::Mat_(2,1) << T_est[0], T_est[1]); - SANITY_CHECK(T_est_mat, 1e-6); -} - -} // namespace opencv_test \ No newline at end of file diff --git a/modules/3d/src/p3p.cpp b/modules/3d/src/p3p.cpp index 4006c99d4f..fa8fe1f68d 100644 --- a/modules/3d/src/p3p.cpp +++ b/modules/3d/src/p3p.cpp @@ -177,7 +177,7 @@ void p3p::calibrateAndNormalizePointsPnP(const Mat &opoints_, const Mat &ipoints Mat ipoints; convertPoints(ipoints_, ipoints, 2); - for (int i = 0; i < ipoints.rows; i++) { + for (int i = 0; i < 3; i++) { const double k_inv_u = ipoints.at(i, 0); const double k_inv_v = ipoints.at(i, 1); double x_norm = 1.0 / sqrt(k_inv_u*k_inv_u + k_inv_v*k_inv_v + 1); diff --git a/modules/3d/src/ptsetreg.cpp b/modules/3d/src/ptsetreg.cpp index 4fff6a3454..2bf4c40e82 100644 --- a/modules/3d/src/ptsetreg.cpp +++ b/modules/3d/src/ptsetreg.cpp @@ -1241,6 +1241,8 @@ Vec2d estimateTranslation2D(InputArray _from, InputArray _to, size_t maxIters, double confidence, size_t refineIters) { + CV_INSTRUMENT_REGION(); + using std::numeric_limits; const double NaN = numeric_limits::quiet_NaN(); Vec2d tvec(NaN, NaN); diff --git a/modules/calib3d/include/opencv2/calib3d.hpp b/modules/calib3d/include/opencv2/calib3d.hpp index 60b2c07c12..1d6793db1c 100644 --- a/modules/calib3d/include/opencv2/calib3d.hpp +++ b/modules/calib3d/include/opencv2/calib3d.hpp @@ -1059,7 +1059,8 @@ More information about Perspective-n-Points is described in @ref calib3d_solvePn of the P3P problem, the last one is used to retain the best solution that minimizes the reprojection error). - With @ref SOLVEPNP_ITERATIVE method and `useExtrinsicGuess=true`, the minimum number of points is 3 (3 points are sufficient to compute a pose but there are up to 4 solutions). The initial solution should be close to the - global solution to converge. + global solution to converge. The function returns true if some solution is found. User code is responsible for + solution quality assessment. - With @ref SOLVEPNP_IPPE input points must be >= 4 and object points must be coplanar. - With @ref SOLVEPNP_IPPE_SQUARE this is a special case suitable for marker pose estimation. Number of input points must be 4. Object points must be defined in the following order: @@ -3362,6 +3363,78 @@ CV_EXPORTS_W cv::Mat estimateAffinePartial2D(InputArray from, InputArray to, Out size_t maxIters = 2000, double confidence = 0.99, size_t refineIters = 10); +/** @brief Computes a pure 2D translation between two 2D point sets. + +It computes +\f[ +\begin{bmatrix} +x\\ +y +\end{bmatrix} += +\begin{bmatrix} +1 & 0\\ +0 & 1 +\end{bmatrix} +\begin{bmatrix} +X\\ +Y +\end{bmatrix} ++ +\begin{bmatrix} +t_x\\ +t_y +\end{bmatrix}. +\f] + +@param from First input 2D point set containing \f$(X,Y)\f$. +@param to Second input 2D point set containing \f$(x,y)\f$. +@param inliers Output vector indicating which points are inliers (1-inlier, 0-outlier). +@param method Robust method used to compute the transformation. The following methods are possible: +- @ref RANSAC - RANSAC-based robust method +- @ref LMEDS - Least-Median robust method +RANSAC is the default method. +@param ransacReprojThreshold Maximum reprojection error in the RANSAC algorithm to consider +a point as an inlier. Applies only to RANSAC. +@param maxIters The maximum number of robust method iterations. +@param confidence Confidence level, between 0 and 1, for the estimated transformation. Anything +between 0.95 and 0.99 is usually good enough. Values too close to 1 can slow down the estimation +significantly. Values lower than 0.8–0.9 can result in an incorrectly estimated transformation. +@param refineIters Maximum number of iterations of the refining algorithm. For pure translation +the least-squares solution on inliers is closed-form, so passing 0 is recommended (no additional refine). + +@return A 2D translation vector \f$[t_x, t_y]^T\f$ as `cv::Vec2d`. If the translation could not be +estimated, both components are set to NaN and, if @p inliers is provided, the mask is filled with zeros. + +\par Converting to a 2x3 transformation matrix: +\f[ +\begin{bmatrix} +1 & 0 & t_x\\ +0 & 1 & t_y +\end{bmatrix} +\f] + +@code{.cpp} +cv::Vec2d t = cv::estimateTranslation2D(from, to, inliers); +cv::Mat T = (cv::Mat_(2,3) << 1,0,t[0], 0,1,t[1]); +@endcode + +The function estimates a pure 2D translation between two 2D point sets using the selected robust +algorithm. Inliers are determined by the reprojection error threshold. + +@note +The RANSAC method can handle practically any ratio of outliers but needs a threshold to +distinguish inliers from outliers. The method LMeDS does not need any threshold but works +correctly only when there are more than 50% inliers. + +@sa estimateAffine2D, estimateAffinePartial2D, getAffineTransform +*/ +CV_EXPORTS_W cv::Vec2d estimateTranslation2D(InputArray from, InputArray to, OutputArray inliers = noArray(), + int method = RANSAC, + double ransacReprojThreshold = 3, + size_t maxIters = 2000, double confidence = 0.99, + size_t refineIters = 0); + /** @example samples/cpp/tutorial_code/features2D/Homography/decompose_homography.cpp An example program with homography decomposition. @@ -4259,7 +4332,7 @@ optimization. It is the \f$max(width,height)/\pi\f$ or the provided \f$f_x\f$, \ TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100, DBL_EPSILON)); /** - @brief Finds an object pose from 3D-2D point correspondences for fisheye camera moodel. + @brief Finds an object pose from 3D-2D point correspondences for fisheye camera model. @param objectPoints Array of object points in the object coordinate space, Nx3 1-channel or 1xN/Nx1 3-channel, where N is the number of points. vector\ can also be passed here. @@ -4275,7 +4348,7 @@ optimization. It is the \f$max(width,height)/\pi\f$ or the provided \f$f_x\f$, \ vectors, respectively, and further optimizes them. @param flags Method for solving a PnP problem: see @ref calib3d_solvePnP_flags @param criteria Termination criteria for internal undistortPoints call. - The function interally undistorts points with @ref undistortPoints and call @ref cv::solvePnP, + The function internally undistorts points with @ref undistortPoints and call @ref cv::solvePnP, thus the input are very similar. More information about Perspective-n-Points is described in @ref calib3d_solvePnP for more information. */ diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index f7d944ccdf..5e429f67a2 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -1406,8 +1406,13 @@ public: When the operation mask is specified, if the Mat::create call shown above reallocates the matrix, the newly allocated matrix is initialized with all zeros before copying the data. + + If (re)allocation of destination memory is not necessary (e.g. updating ROI), use copyAt() . + @param m Destination matrix. If it does not have a proper size or type before the operation, it is reallocated. + + @sa copyAt */ void copyTo( OutputArray m ) const; @@ -1420,6 +1425,30 @@ public: */ void copyTo( OutputArray m, InputArray mask ) const; + /** @brief Overwrites the existing matrix + + This method writes existing matrix data, just like copyTo(). + But if it does not have a proper size or type before the operation, an exception is thrown. + This function is helpful to update ROI in an existing matrix. + + If (re)allocation of destination memory is necessary, use copyTo() . + + @param m Destination matrix. + If it does not have a proper size or type before the operation, an exception is thrown. + + @sa copyTo + + */ + void copyAt( OutputArray m ) const; + + /** @overload + @param m Destination matrix. + If it does not have a proper size or type before the operation, an exception is thrown. + @param mask Operation mask of the same size as \*this. Its non-zero elements indicate which matrix + elements need to be copied. The mask has to be of type CV_8U and can have 1 or multiple channels. + */ + void copyAt( OutputArray m, InputArray mask ) const; + /** @brief Converts an array to another data type with optional scaling. The method converts source pixel values to the target data type. saturate_cast\<\> is applied at diff --git a/modules/core/include/opencv2/core/vsx_utils.hpp b/modules/core/include/opencv2/core/vsx_utils.hpp index 4d5a694bae..aafc6c07b1 100644 --- a/modules/core/include/opencv2/core/vsx_utils.hpp +++ b/modules/core/include/opencv2/core/vsx_utils.hpp @@ -257,8 +257,27 @@ VSX_IMPL_1VRG(vec_udword2, vec_udword2, vpopcntd, vec_popcntu) VSX_IMPL_1VRG(vec_udword2, vec_dword2, vpopcntd, vec_popcntu) // converts between single and double-precision -VSX_REDIRECT_1RG(vec_float4, vec_double2, vec_cvfo, vec_floate) -VSX_REDIRECT_1RG(vec_double2, vec_float4, vec_cvfo, vec_doubleo) +// vec_floate and vec_doubleo are available since Power10 and z14 +#if defined(__POWER10__) || (defined(__powerpc64__) && defined(__ARCH_PWR10__) +// Use VSX double<->float conversion instructions (if supported by the architecture) + VSX_REDIRECT_1RG(vec_float4, vec_double2, vec_cvfo, vec_floate) + VSX_REDIRECT_1RG(vec_double2, vec_float4, vec_cvfo, vec_doubleo) +#else +// Fallback: implement vec_cvfo using scalar operations (to ensure successful linking) + static inline vec_float4 vec_cvfo(const vec_double2& a) + { + float r0 = static_cast(reinterpret_cast(&a)[0]); + float r1 = static_cast(reinterpret_cast(&a)[1]); + return (vec_float4){r0, 0.f, r1, 0.f}; + } + + static inline vec_double2 vec_cvfo(const vec_float4& a) + { + double r0 = static_cast(reinterpret_cast(&a)[0]); + double r1 = static_cast(reinterpret_cast(&a)[2]); + return (vec_double2){r0, r1}; + } +#endif // converts word and doubleword to double-precision #undef vec_ctd diff --git a/modules/core/src/arithm.cpp b/modules/core/src/arithm.cpp index acebf3f62e..0e971802c0 100644 --- a/modules/core/src/arithm.cpp +++ b/modules/core/src/arithm.cpp @@ -1165,6 +1165,10 @@ void cv::add( InputArray src1, InputArray src2, OutputArray dst, if (src1.empty() && src2.empty()) { dst.release(); + if (dtype >= 0) + { + dst.create(0, 0, dtype); + } return; } @@ -1192,6 +1196,10 @@ void cv::subtract( InputArray _src1, InputArray _src2, OutputArray _dst, if (_src1.empty() && _src2.empty()) { _dst.release(); + if (dtype >= 0) + { + _dst.create(0, 0, dtype); + } return; } @@ -1409,6 +1417,10 @@ void cv::addWeighted( InputArray src1, double alpha, InputArray src2, if (src1.empty() && src2.empty()) { dst.release(); + if (dtype >= 0) + { + dst.create(0, 0, dtype); + } return; } diff --git a/modules/core/src/convert.dispatch.cpp b/modules/core/src/convert.dispatch.cpp index 16a760b1fc..85d6e26841 100644 --- a/modules/core/src/convert.dispatch.cpp +++ b/modules/core/src/convert.dispatch.cpp @@ -135,6 +135,7 @@ void Mat::convertTo(OutputArray dst, int type_, double alpha, double beta) const if (empty()) { dst.release(); + dst.create(size(), type_ >= 0 ? type_ : type()); return; } @@ -204,6 +205,7 @@ void UMat::convertTo(OutputArray dst, int type_, double alpha, double beta) cons if (empty()) { dst.release(); + dst.create(size(), type_ >= 0 ? type_ : type()); return; } diff --git a/modules/core/src/copy.cpp b/modules/core/src/copy.cpp index de7cb6354e..61f7d57457 100644 --- a/modules/core/src/copy.cpp +++ b/modules/core/src/copy.cpp @@ -642,6 +642,28 @@ void Mat::copyTo( OutputArray _dst, InputArray _mask ) const copymask(ptrs[0], 0, ptrs[2], 0, ptrs[1], 0, sz, &esz); } +/* dst = src */ +void Mat::copyAt( OutputArray _dst ) const +{ + CV_INSTRUMENT_REGION(); + + Mat dst = _dst.getMat(); + CV_CheckTrue( !dst.empty(), "dst must not be empty" ); + CV_CheckTypeEQ(type(), dst.type(), "Make the type of dst the same as src"); + CV_CheckEQ(size(), dst.size(), "Make the size of dst the same as src"); + copyTo(_dst); +} +void Mat::copyAt( OutputArray _dst, InputArray _mask ) const +{ + CV_INSTRUMENT_REGION(); + + Mat dst = _dst.getMat(); + CV_CheckTrue( !dst.empty(), "dst must not be empty" ); + CV_CheckTypeEQ(type(), dst.type(), "Make the type of dst the same as src"); + CV_CheckEQ(size(), dst.size(), "Make the size of dst the same as src"); + copyTo(_dst, _mask); +} + static bool can_apply_memset(const Mat &mat, const Scalar &s, int &fill_value) { diff --git a/modules/core/src/umatrix.cpp b/modules/core/src/umatrix.cpp index 7598abf647..37dc2628e8 100644 --- a/modules/core/src/umatrix.cpp +++ b/modules/core/src/umatrix.cpp @@ -1216,6 +1216,10 @@ void UMat::copyTo(OutputArray _dst) const return; } + _dst.create( dims, size.p, stype ); + if (empty()) + return; + size_t sz[CV_MAX_DIM] = {1}, srcofs[CV_MAX_DIM]={0}, dstofs[CV_MAX_DIM]={0}; size_t esz = CV_ELEM_SIZE(stype); int i, d = std::max(dims, 1); @@ -1225,10 +1229,6 @@ void UMat::copyTo(OutputArray _dst) const ndoffset(srcofs); srcofs[d-1] *= esz; - _dst.create( dims, size.p, stype ); - if (empty()) - return; - if( _dst.isUMat() ) { UMat dst = _dst.getUMat(); diff --git a/modules/core/test/test_mat.cpp b/modules/core/test/test_mat.cpp index c59a139449..07dc859cf1 100644 --- a/modules/core/test/test_mat.cpp +++ b/modules/core/test/test_mat.cpp @@ -1290,6 +1290,15 @@ TEST(Core_Mat, push_back) } } +TEST(Core_Mat, copyToConvertTo_Empty) +{ + cv::Mat A(0, 0, CV_16SC2), B, C; + A.copyTo(B); + ASSERT_EQ(A.type(), B.type()); + A.convertTo(C, CV_32SC2); + ASSERT_EQ(C.type(), CV_32SC2); +} + TEST(Core_Mat, copyNx1ToVector) { cv::Mat_ src(5, 1); @@ -2857,4 +2866,69 @@ TEST(UMat, reshape_empty) EXPECT_EQ(m4d.total(), (size_t)0); } +// see https://github.com/opencv/opencv/issues/27298 +TEST(Mat, copyAt_regression27298) +{ + cv::Mat src(40/*height*/, 30/*width*/, CV_8UC1, Scalar(255)); + // Normal + { + cv::Mat dst(100, 100, CV_8UC1, Scalar(0)); + cv::Mat roi(dst, cv::Rect(0, 0, 30/*width*/, 40/*height*/)); + void* roiData = roi.data; + EXPECT_NO_THROW(src.copyTo(roi)); + EXPECT_EQ(roi.data, roiData); + EXPECT_EQ(countNonZero(roi), roi.size().width * roi.size().height) << roi; + } + { + cv::Mat dst(100, 100, CV_8UC1, Scalar(0)); + cv::Mat roi(dst, cv::Rect(0, 0, 30/*width*/, 40/*height*/)); + void* roiData = roi.data; + EXPECT_NO_THROW(src.copyAt(roi)); + EXPECT_EQ(roi.data, roiData); + EXPECT_EQ(countNonZero(roi), roi.size().width * roi.size().height) << roi; + } + + // Empty + { + cv::Mat roi; // empty + EXPECT_NO_THROW(src.copyTo(roi)); + EXPECT_NE(roi.data, nullptr); // Allocated + EXPECT_EQ(countNonZero(roi), roi.size().width * roi.size().height) << roi; + } + { + cv::Mat roi; // empty + EXPECT_ANY_THROW(src.copyAt(roi)); + } + + // Different Type + { + cv::Mat dst(100, 100, CV_16UC1, Scalar(0)); + cv::Mat roi(dst, cv::Rect(0, 0, 30/*width*/, 40/*height*/)); + void* roiData = roi.data; + EXPECT_NO_THROW(src.copyTo(roi)); + EXPECT_NE(roi.data, roiData); // Reallocated + EXPECT_EQ(countNonZero(roi), roi.size().width * roi.size().height) << roi; + } + { + cv::Mat dst(100, 100, CV_16UC1, Scalar(0)); + cv::Mat roi(dst, cv::Rect(0, 0, 30/*width*/, 40/*height*/)); + EXPECT_ANY_THROW(src.copyAt(roi)); + } + + // Different Size + { + cv::Mat dst(100, 100, CV_8UC1, Scalar(0)); + cv::Mat roi(dst, cv::Rect(0, 0, 40/*width*/, 30/*height*/)); + void* roiData = roi.data; + EXPECT_NO_THROW(src.copyTo(roi)); + EXPECT_NE(roi.data, roiData); // Reallocated + EXPECT_EQ(countNonZero(roi), roi.size().width * roi.size().height) << roi; + } + { + cv::Mat dst(100, 100, CV_8UC1, Scalar(0)); + cv::Mat roi(dst, cv::Rect(0, 0, 40/*width*/, 30/*height*/)); + EXPECT_ANY_THROW(src.copyAt(roi)); + } +} + }} // namespace diff --git a/modules/core/test/test_umat.cpp b/modules/core/test/test_umat.cpp index bf525c9c61..4f3f03aed4 100644 --- a/modules/core/test/test_umat.cpp +++ b/modules/core/test/test_umat.cpp @@ -1177,6 +1177,14 @@ TEST(UMat, async_cleanup_without_call_chain_warning) } } +TEST(UMat, copyToConvertTo_Empty) +{ + cv::UMat A(0, 0, CV_16SC2), B, C; + A.copyTo(B); + ASSERT_EQ(A.type(), B.type()); + A.convertTo(C, CV_32SC2); + ASSERT_EQ(C.type(), CV_32SC2); +} ///////////// oclCleanupCallback threadsafe check (#5062) ///////////////////// diff --git a/modules/dnn/src/caffe/caffe_importer.cpp b/modules/dnn/src/caffe/caffe_importer.cpp index 3bd27c028a..4fc292510a 100644 --- a/modules/dnn/src/caffe/caffe_importer.cpp +++ b/modules/dnn/src/caffe/caffe_importer.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -57,7 +58,6 @@ #include #include - namespace cv { namespace dnn { CV__DNN_INLINE_NS_BEGIN @@ -206,7 +206,9 @@ public: return (str.size() >= _param.size()) && str.compare(str.size() - _param.size(), _param.size(), _param) == 0; } - void extractLayerParams(const Message &msg, cv::dnn::LayerParams ¶ms, bool isInternal = false) + template + typename std::enable_if::value, void>::type + extractLayerParams(const MSG &msg, cv::dnn::LayerParams ¶ms, bool isInternal = false) { const Descriptor *msgDesc = msg.GetDescriptor(); const Reflection *msgRefl = msg.GetReflection(); @@ -241,6 +243,13 @@ public: } } + template + typename std::enable_if::value, void>::type + extractLayerParams(const MSG &msg, cv::dnn::LayerParams ¶ms, bool isInternal = false) + { + CV_Error(Error::StsError, "DNN/CAFFE: do not have your message be a MessageLite"); + } + void blobShapeFromProto(const caffe::BlobProto &pbBlob, MatShape& shape) { shape.clear(); @@ -259,6 +268,18 @@ public: shape.resize(1, 1); // Is a scalar. } + template + typename std::enable_if::value, void>::type + AssertBlobProtoIsFloat(const BLOB_PROTO &pbBlob) { + CV_DbgAssert(pbBlob.GetDescriptor()->FindFieldByLowercaseName("data")->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT); + } + + template + typename std::enable_if::value, void>::type + AssertBlobProtoIsFloat(const BLOB_PROTO &pbBlob) { + CV_Error(Error::StsError, "DNN/CAFFE: do not have your message be a MessageLite"); + } + void blobFromProto(const caffe::BlobProto &pbBlob, cv::Mat &dstBlob) { MatShape shape; @@ -270,7 +291,7 @@ public: // Single precision floats. CV_Assert(pbBlob.data_size() == (int)dstBlob.total()); - CV_DbgAssert(pbBlob.GetDescriptor()->FindFieldByLowercaseName("data")->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT); + AssertBlobProtoIsFloat(pbBlob); Mat(dstBlob.size, CV_32F, (void*)pbBlob.data().data()).copyTo(dstBlob); } else diff --git a/modules/dnn/src/caffe/caffe_io.cpp b/modules/dnn/src/caffe/caffe_io.cpp index ebecf95eea..8897e70d67 100644 --- a/modules/dnn/src/caffe/caffe_io.cpp +++ b/modules/dnn/src/caffe/caffe_io.cpp @@ -101,6 +101,7 @@ #include #include #include +#include #include "caffe_io.hpp" #include "glog_emulator.hpp" @@ -1110,7 +1111,7 @@ const char* UpgradeV1LayerType(const V1LayerParameter_LayerType type) { static const int kProtoReadBytesLimit = INT_MAX; // Max size of 2 GB minus 1 byte. -bool ReadProtoFromBinary(ZeroCopyInputStream* input, Message *proto) { +bool ReadProtoFromBinary(ZeroCopyInputStream* input, MessageLite *proto) { CodedInputStream coded_input(input); #if GOOGLE_PROTOBUF_VERSION >= 3006000 coded_input.SetTotalBytesLimit(kProtoReadBytesLimit); @@ -1133,7 +1134,12 @@ bool ReadProtoFromTextFile(const char* filename, Message* proto) { return parser.Parse(&input, proto); } -bool ReadProtoFromBinaryFile(const char* filename, Message* proto) { +bool ReadProtoFromTextFile(const char* filename, MessageLite* proto) { + CV_Error(Error::StsError, "DNN/CAFFE: do not have your message be a MessageLite"); + return false; +} + +bool ReadProtoFromBinaryFile(const char* filename, MessageLite* proto) { std::ifstream fs(filename, std::ifstream::in | std::ifstream::binary); CHECK(fs.is_open()) << "Can't open \"" << filename << "\""; IstreamInputStream raw_input(&fs); @@ -1151,26 +1157,52 @@ bool ReadProtoFromTextBuffer(const char* data, size_t len, Message* proto) { return parser.Parse(&input, proto); } +bool ReadProtoFromTextBuffer(const char* data, size_t len, MessageLite* proto) { + CV_Error(Error::StsError, "DNN/CAFFE: do not have your message be a MessageLite"); + return false; +} -bool ReadProtoFromBinaryBuffer(const char* data, size_t len, Message* proto) { +bool ReadProtoFromBinaryBuffer(const char* data, size_t len, MessageLite* proto) { ArrayInputStream raw_input(data, len); return ReadProtoFromBinary(&raw_input, proto); } -void ReadNetParamsFromTextFileOrDie(const char* param_file, - NetParameter* param) { +template +typename std::enable_if::value, void>::type +ReadNetParamsFromTextFileOrDieImpl(const char* param_file, MESSAGE* param) { CHECK(ReadProtoFromTextFile(param_file, param)) << "Failed to parse NetParameter file: " << param_file; UpgradeNetAsNeeded(param_file, param); } -void ReadNetParamsFromTextBufferOrDie(const char* data, size_t len, - NetParameter* param) { +template +typename std::enable_if::value, void>::type +ReadNetParamsFromTextFileOrDieImpl(const char* param_file, MESSAGE* param) { + CV_Error(Error::StsError, "DNN/CAFFE: do not have your message be a MessageLite"); +} + +void ReadNetParamsFromTextFileOrDie(const char* param_file, NetParameter* param) { + ReadNetParamsFromTextFileOrDieImpl(param_file, param); +} + +template +typename std::enable_if::value, void>::type +ReadNetParamsFromTextBufferOrDieImpl(const char* data, size_t len, MESSAGE* param) { CHECK(ReadProtoFromTextBuffer(data, len, param)) << "Failed to parse NetParameter buffer"; UpgradeNetAsNeeded("memory buffer", param); } +template +typename std::enable_if::value, void>::type +ReadNetParamsFromTextBufferOrDieImpl(const char* data, size_t len, MESSAGE* param) { + CV_Error(Error::StsError, "DNN/CAFFE: do not have your message be a MessageLite"); +} + +void ReadNetParamsFromTextBufferOrDie(const char* data, size_t len, NetParameter* param) { + ReadNetParamsFromTextBufferOrDieImpl(data, len, param); +} + void ReadNetParamsFromBinaryFileOrDie(const char* param_file, NetParameter* param) { CHECK(ReadProtoFromBinaryFile(param_file, param)) diff --git a/modules/dnn/src/caffe/caffe_io.hpp b/modules/dnn/src/caffe/caffe_io.hpp index 544db1c3ed..71897d8af4 100644 --- a/modules/dnn/src/caffe/caffe_io.hpp +++ b/modules/dnn/src/caffe/caffe_io.hpp @@ -119,9 +119,11 @@ void ReadNetParamsFromTextBufferOrDie(const char* data, size_t len, // Utility functions used internally by Caffe and TensorFlow loaders bool ReadProtoFromTextFile(const char* filename, ::google::protobuf::Message* proto); -bool ReadProtoFromBinaryFile(const char* filename, ::google::protobuf::Message* proto); +bool ReadProtoFromTextFile(const char* filename, ::google::protobuf::MessageLite* proto); +bool ReadProtoFromBinaryFile(const char* filename, ::google::protobuf::MessageLite* proto); bool ReadProtoFromTextBuffer(const char* data, size_t len, ::google::protobuf::Message* proto); -bool ReadProtoFromBinaryBuffer(const char* data, size_t len, ::google::protobuf::Message* proto); +bool ReadProtoFromTextBuffer(const char* data, size_t len, ::google::protobuf::MessageLite* proto); +bool ReadProtoFromBinaryBuffer(const char* data, size_t len, ::google::protobuf::MessageLite* proto); } } diff --git a/modules/dnn/src/layers/convolution_layer.cpp b/modules/dnn/src/layers/convolution_layer.cpp index 7984495e71..18298f2b71 100644 --- a/modules/dnn/src/layers/convolution_layer.cpp +++ b/modules/dnn/src/layers/convolution_layer.cpp @@ -207,6 +207,7 @@ public: Ptr activ; Ptr fastConvImpl; + bool canUseWinograd = false; #ifdef HAVE_OPENCL Ptr > convolutionOp; @@ -400,6 +401,13 @@ public: #ifdef HAVE_OPENCL convolutionOp.release(); #endif + + // Winograd only works when input h and w >= 12. + canUseWinograd = useWinograd && inputs[0].dims == 4 && inputs[0].size[2] >= 12 && inputs[0].size[3] >= 12; + if (fastConvImpl && (fastConvImpl->conv_type == CONV_TYPE_WINOGRAD3X3) ^ canUseWinograd) + { + fastConvImpl.reset(); + } } bool setActivation(const Ptr& layer) CV_OVERRIDE @@ -1195,9 +1203,6 @@ public: int K = outputs[0].size[1]; int C = inputs[0].size[1]; - // Winograd only works when input h and w >= 12. - bool canUseWinograd = useWinograd && conv_dim == CONV_2D && inputs[0].size[2] >= 12 && inputs[0].size[3] >= 12; - CV_Assert(outputs[0].size[1] % ngroups == 0); fastConvImpl = initFastConv(weightsMat, &biasvec[0], ngroups, K, C, kernel_size, strides, dilations, pads_begin, pads_end, conv_dim, diff --git a/modules/dnn/src/tensorflow/tf_importer.cpp b/modules/dnn/src/tensorflow/tf_importer.cpp index 166d6b841e..f04f9d5e5a 100644 --- a/modules/dnn/src/tensorflow/tf_importer.cpp +++ b/modules/dnn/src/tensorflow/tf_importer.cpp @@ -31,6 +31,7 @@ Implementation of Tensorflow models parser #include #include #include +#include #include "tf_graph_simplifier.hpp" #endif @@ -3326,6 +3327,19 @@ Net readNetFromTensorflow(const std::vector& bufferModel, const std::vect engine, extraOutputs); } + +template +typename std::enable_if::value, void>::type +PrintToStringImpl(const GRAPH_DEF& net, std::string* content) { + google::protobuf::TextFormat::PrintToString(net, content); +} + +template +typename std::enable_if::value, void>::type +PrintToStringImpl(const GRAPH_DEF& net, std::string* content) { + CV_Error(Error::StsError, "DNN/TF: do not have your message be a MessageLite"); +} + void writeTextGraph(const String& _model, const String& output) { String model = _model; @@ -3348,7 +3362,7 @@ void writeTextGraph(const String& _model, const String& output) } std::string content; - google::protobuf::TextFormat::PrintToString(net, &content); + PrintToStringImpl(net, &content); std::ofstream ofs(output.c_str()); ofs << content; diff --git a/modules/dnn/test/test_layers.cpp b/modules/dnn/test/test_layers.cpp index 2182969696..7ae628735b 100644 --- a/modules/dnn/test/test_layers.cpp +++ b/modules/dnn/test/test_layers.cpp @@ -2906,4 +2906,47 @@ TEST(Layer_Size, onnx_0d_scalar) EXPECT_EQ(outs[0].at(0), 1); } +TEST(ConvolutionWinograd, Accuracy) +{ + Mat weights({2, 1, 3, 3}, CV_32F); + randn(weights, 0, 1); + + // Check convolution can switch between implementations on changed shape. + auto getNet = [&]() { + Net net; + LayerParams lp; + lp.name = "conv"; + lp.type = "Convolution"; + lp.set("kernel_size", 3); + lp.set("num_output", 2); + lp.set("pad", 0); + lp.set("stride", 1); + lp.set("bias_term", false); + + lp.blobs.push_back(weights); + net.addLayerToPrev(lp.name, lp.type, lp); + return net; + }; + + Mat inpSmall({1, 1, 5, 5}, CV_32F); + Mat inpLarge({1, 1, 64, 64}, CV_32F); + randn(inpSmall, 0, 1); + randn(inpLarge, 0, 1); + + Net net1 = getNet(); + Net net2 = getNet(); + net1.setInput(inpSmall); + net2.setInput(inpLarge); + Mat refSmall = net1.forward(); + Mat refLarge = net2.forward(); + + net1.setInput(inpLarge); + net2.setInput(inpSmall); + Mat outLarge = net1.forward(); + Mat outSmall = net2.forward(); + + normAssert(outSmall, refSmall, "Small input after large", 0.0, 0.0); + normAssert(outLarge, refLarge, "Large input after small", 0.0, 0.0); +} + }} // namespace diff --git a/modules/imgcodecs/src/bitstrm.cpp b/modules/imgcodecs/src/bitstrm.cpp index 12d9c1bcae..a7e6380dfb 100644 --- a/modules/imgcodecs/src/bitstrm.cpp +++ b/modules/imgcodecs/src/bitstrm.cpp @@ -153,7 +153,7 @@ void RBaseStream::setPos( int64_t pos ) int64_t RBaseStream::getPos() { CV_Assert(isOpened()); - int64_t pos = validateToInt64((m_current - m_start) + m_block_pos); + int64_t pos = static_cast((m_current - m_start) + m_block_pos); CV_Assert(pos >= m_block_pos); // overflow check CV_Assert(pos >= 0); // overflow check return pos; diff --git a/modules/imgcodecs/src/grfmt_base.cpp b/modules/imgcodecs/src/grfmt_base.cpp index 0cd372ec28..4aaa9bbc7f 100644 --- a/modules/imgcodecs/src/grfmt_base.cpp +++ b/modules/imgcodecs/src/grfmt_base.cpp @@ -79,6 +79,7 @@ Mat BaseImageDecoder::getMetadata(ImageMetadataType type) const case IMAGE_METADATA_XMP: case IMAGE_METADATA_ICCP: + case IMAGE_METADATA_CICP: return makeMat(m_metadata[type]); default: diff --git a/modules/imgcodecs/src/grfmt_gif.cpp b/modules/imgcodecs/src/grfmt_gif.cpp index f9c5744466..13f467157e 100644 --- a/modules/imgcodecs/src/grfmt_gif.cpp +++ b/modules/imgcodecs/src/grfmt_gif.cpp @@ -212,7 +212,7 @@ bool GifDecoder::readData(Mat &img) { if(!restore.empty()) { Mat roi = Mat(lastImage, cv::Rect(left,top,width,height)); - restore.copyTo(roi); + restore.copyAt(roi); } return hasRead; diff --git a/modules/imgcodecs/src/grfmt_png.cpp b/modules/imgcodecs/src/grfmt_png.cpp index dbb3c41cf2..a505266a8b 100644 --- a/modules/imgcodecs/src/grfmt_png.cpp +++ b/modules/imgcodecs/src/grfmt_png.cpp @@ -715,7 +715,7 @@ void PngDecoder::compose_frame(std::vector& rows_dst, const std::vect // Blending mode for (unsigned int i = 0; i < w; i++, sp += channels, dp += channels) { - uint16_t alpha = sp[3]; + uint16_t alpha = channels < 4 ? 0 : sp[3]; if (channels < 4 || alpha == 65535 || dp[3] == 0) { // Fully opaque OR destination fully transparent: direct copy @@ -745,7 +745,7 @@ void PngDecoder::compose_frame(std::vector& rows_dst, const std::vect // Blending mode for (unsigned int i = 0; i < w; i++, sp += channels, dp += channels) { - uint8_t alpha = sp[3]; + uint8_t alpha = channels < 4 ? 0 : sp[3]; if (channels < 4 || alpha == 255 || dp[3] == 0) { // Fully opaque OR destination fully transparent: direct copy diff --git a/modules/imgcodecs/src/loadsave.cpp b/modules/imgcodecs/src/loadsave.cpp index cd31608740..30b263e4ff 100644 --- a/modules/imgcodecs/src/loadsave.cpp +++ b/modules/imgcodecs/src/loadsave.cpp @@ -476,7 +476,8 @@ static const char* metadataTypeToString(ImageMetadataType type) { return type == IMAGE_METADATA_EXIF ? "Exif" : type == IMAGE_METADATA_XMP ? "XMP" : - type == IMAGE_METADATA_ICCP ? "ICC Profile" : "???"; + type == IMAGE_METADATA_ICCP ? "ICC Profile" : + type == IMAGE_METADATA_CICP ? "cICP" : "???"; } static void addMetadata(ImageEncoder& encoder, diff --git a/modules/imgcodecs/src/utils.cpp b/modules/imgcodecs/src/utils.cpp index cfbd62b7bc..41fd9f5041 100644 --- a/modules/imgcodecs/src/utils.cpp +++ b/modules/imgcodecs/src/utils.cpp @@ -51,13 +51,6 @@ int validateToInt(size_t sz) return valueInt; } -int64_t validateToInt64(ptrdiff_t sz) -{ - int64_t valueInt = static_cast(sz); - CV_Assert((ptrdiff_t)valueInt == sz); - return valueInt; -} - #define SCALE 14 #define cR (int)(0.299*(1 << SCALE) + 0.5) #define cG (int)(0.587*(1 << SCALE) + 0.5) diff --git a/modules/imgcodecs/src/utils.hpp b/modules/imgcodecs/src/utils.hpp index f2649f0ecd..95deebde31 100644 --- a/modules/imgcodecs/src/utils.hpp +++ b/modules/imgcodecs/src/utils.hpp @@ -45,7 +45,6 @@ namespace cv { int validateToInt(size_t step); -int64_t validateToInt64(ptrdiff_t step); template static inline size_t safeCastToSizeT(const _Tp v_origin, const char* msg) diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp index 54e29c26fa..703b784281 100644 --- a/modules/imgproc/include/opencv2/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc.hpp @@ -1065,6 +1065,18 @@ public: //!@brief Returns Size defines the number of tiles in row and column. CV_WRAP virtual Size getTilesGridSize() const = 0; + /** @brief Sets bit shift parameter for histogram bins. + + @param bitShift bit shift value (default is 0). + */ + CV_WRAP virtual void setBitShift(int bitShift) = 0; + + /** @brief Returns the bit shift parameter for histogram bins. + + @return current bit shift value. + */ + CV_WRAP virtual int getBitShift() const = 0; + CV_WRAP virtual void collectGarbage() = 0; }; diff --git a/modules/imgproc/src/clahe.cpp b/modules/imgproc/src/clahe.cpp index b787378ee3..ae41c84c79 100644 --- a/modules/imgproc/src/clahe.cpp +++ b/modules/imgproc/src/clahe.cpp @@ -118,12 +118,12 @@ namespace clahe namespace { - template + template class CLAHE_CalcLut_Body : public cv::ParallelLoopBody { public: - CLAHE_CalcLut_Body(const cv::Mat& src, const cv::Mat& lut, const cv::Size& tileSize, const int& tilesX, const int& clipLimit, const float& lutScale) : - src_(src), lut_(lut), tileSize_(tileSize), tilesX_(tilesX), clipLimit_(clipLimit), lutScale_(lutScale) + CLAHE_CalcLut_Body(const cv::Mat& src, const cv::Mat& lut, const cv::Size& tileSize, const int& tilesX, const int& clipLimit, const float& lutScale, const int& histSize, const int& shift) : + src_(src), lut_(lut), tileSize_(tileSize), tilesX_(tilesX), clipLimit_(clipLimit), lutScale_(lutScale), histSize_(histSize), shift_(shift) { } @@ -137,10 +137,12 @@ namespace int tilesX_; int clipLimit_; float lutScale_; + int histSize_; + int shift_; }; - template - void CLAHE_CalcLut_Body::operator ()(const cv::Range& range) const + template + void CLAHE_CalcLut_Body::operator ()(const cv::Range& range) const { T* tileLut = lut_.ptr(range.start); const size_t lut_step = lut_.step / sizeof(T); @@ -162,9 +164,9 @@ namespace // calc histogram - cv::AutoBuffer _tileHist(histSize); + cv::AutoBuffer _tileHist(histSize_); int* tileHist = _tileHist.data(); - std::fill(tileHist, tileHist + histSize, 0); + std::fill(tileHist, tileHist + histSize_, 0); int height = tileROI.height; const size_t sstep = src_.step / sizeof(T); @@ -174,13 +176,13 @@ namespace for (; x <= tileROI.width - 4; x += 4) { int t0 = ptr[x], t1 = ptr[x+1]; - tileHist[t0 >> shift]++; tileHist[t1 >> shift]++; + tileHist[t0 >> shift_]++; tileHist[t1 >> shift_]++; t0 = ptr[x+2]; t1 = ptr[x+3]; - tileHist[t0 >> shift]++; tileHist[t1 >> shift]++; + tileHist[t0 >> shift_]++; tileHist[t1 >> shift_]++; } for (; x < tileROI.width; ++x) - tileHist[ptr[x] >> shift]++; + tileHist[ptr[x] >> shift_]++; } // clip histogram @@ -189,7 +191,7 @@ namespace { // how many pixels were clipped int clipped = 0; - for (int i = 0; i < histSize; ++i) + for (int i = 0; i < histSize_; ++i) { if (tileHist[i] > clipLimit_) { @@ -199,16 +201,16 @@ namespace } // redistribute clipped pixels - int redistBatch = clipped / histSize; - int residual = clipped - redistBatch * histSize; + int redistBatch = clipped / histSize_; + int residual = clipped - redistBatch * histSize_; - for (int i = 0; i < histSize; ++i) + for (int i = 0; i < histSize_; ++i) tileHist[i] += redistBatch; if (residual != 0) { - int residualStep = MAX(histSize / residual, 1); - for (int i = 0; i < histSize && residual > 0; i += residualStep, residual--) + int residualStep = MAX(histSize_ / residual, 1); + for (int i = 0; i < histSize_ && residual > 0; i += residualStep, residual--) tileHist[i]++; } } @@ -216,7 +218,7 @@ namespace // calc Lut int sum = 0; - for (int i = 0; i < histSize; ++i) + for (int i = 0; i < histSize_; ++i) { sum += tileHist[i]; tileLut[i] = cv::saturate_cast(sum * lutScale_); @@ -224,12 +226,12 @@ namespace } } - template + template class CLAHE_Interpolation_Body : public cv::ParallelLoopBody { public: - CLAHE_Interpolation_Body(const cv::Mat& src, const cv::Mat& dst, const cv::Mat& lut, const cv::Size& tileSize, const int& tilesX, const int& tilesY) : - src_(src), dst_(dst), lut_(lut), tileSize_(tileSize), tilesX_(tilesX), tilesY_(tilesY) + CLAHE_Interpolation_Body(const cv::Mat& src, const cv::Mat& dst, const cv::Mat& lut, const cv::Size& tileSize, const int& tilesX, const int& tilesY, const int& shift) : + src_(src), dst_(dst), lut_(lut), tileSize_(tileSize), tilesX_(tilesX), tilesY_(tilesY), shift_(shift) { buf.allocate(src.cols << 2); ind1_p = buf.data(); @@ -268,14 +270,15 @@ namespace cv::Size tileSize_; int tilesX_; int tilesY_; + int shift_; cv::AutoBuffer buf; int * ind1_p, * ind2_p; float * xa_p, * xa1_p; }; - template - void CLAHE_Interpolation_Body::operator ()(const cv::Range& range) const + template + void CLAHE_Interpolation_Body::operator ()(const cv::Range& range) const { float inv_th = 1.0f / tileSize_.height; @@ -299,7 +302,7 @@ namespace for (int x = 0; x < src_.cols; ++x) { - int srcVal = srcRow[x] >> shift; + int srcVal = srcRow[x] >> shift_; int ind1 = ind1_p[x] + srcVal; int ind2 = ind2_p[x] + srcVal; @@ -307,7 +310,7 @@ namespace float res = (lutPlane1[ind1] * xa1_p[x] + lutPlane1[ind2] * xa_p[x]) * ya1 + (lutPlane2[ind1] * xa1_p[x] + lutPlane2[ind2] * xa_p[x]) * ya; - dstRow[x] = cv::saturate_cast(res) << shift; + dstRow[x] = cv::saturate_cast(res) << shift_; } } } @@ -315,7 +318,7 @@ namespace class CLAHE_Impl CV_FINAL : public cv::CLAHE { public: - CLAHE_Impl(double clipLimit = 40.0, int tilesX = 8, int tilesY = 8); + CLAHE_Impl(double clipLimit = 40.0, int tilesX = 8, int tilesY = 8, int bitShift = 0); void apply(cv::InputArray src, cv::OutputArray dst) CV_OVERRIDE; @@ -325,12 +328,16 @@ namespace void setTilesGridSize(cv::Size tileGridSize) CV_OVERRIDE; cv::Size getTilesGridSize() const CV_OVERRIDE; + void setBitShift(int bitShift) CV_OVERRIDE; + int getBitShift() const CV_OVERRIDE; + void collectGarbage() CV_OVERRIDE; private: double clipLimit_; int tilesX_; int tilesY_; + int bitShift_; cv::Mat srcExt_; cv::Mat lut_; @@ -341,8 +348,8 @@ namespace #endif }; - CLAHE_Impl::CLAHE_Impl(double clipLimit, int tilesX, int tilesY) : - clipLimit_(clipLimit), tilesX_(tilesX), tilesY_(tilesY) + CLAHE_Impl::CLAHE_Impl(double clipLimit, int tilesX, int tilesY, int bitShift) : + clipLimit_(clipLimit), tilesX_(tilesX), tilesY_(tilesY), bitShift_(bitShift) { } @@ -356,7 +363,7 @@ namespace bool useOpenCL = cv::ocl::isOpenCLActivated() && _src.isUMat() && _src.dims()<=2 && _src.type() == CV_8UC1; #endif - int histSize = _src.type() == CV_8UC1 ? 256 : 65536; + int histSize = _src.type() == CV_8UC1 ? (256 >> bitShift_) : (65536 >> bitShift_); cv::Size tileSize; cv::_InputArray _srcForLut; @@ -411,9 +418,13 @@ namespace cv::Ptr calcLutBody; if (_src.type() == CV_8UC1) - calcLutBody = cv::makePtr >(srcForLut, lut_, tileSize, tilesX_, clipLimit, lutScale); + { + calcLutBody = cv::makePtr >(srcForLut, lut_, tileSize, tilesX_, clipLimit, lutScale, histSize, bitShift_); + } else if (_src.type() == CV_16UC1) - calcLutBody = cv::makePtr >(srcForLut, lut_, tileSize, tilesX_, clipLimit, lutScale); + { + calcLutBody = cv::makePtr >(srcForLut, lut_, tileSize, tilesX_, clipLimit, lutScale, histSize, bitShift_); + } else CV_Error( cv::Error::StsBadArg, "Unsupported type" ); @@ -421,9 +432,13 @@ namespace cv::Ptr interpolationBody; if (_src.type() == CV_8UC1) - interpolationBody = cv::makePtr >(src, dst, lut_, tileSize, tilesX_, tilesY_); + { + interpolationBody = cv::makePtr >(src, dst, lut_, tileSize, tilesX_, tilesY_, bitShift_); + } else if (_src.type() == CV_16UC1) - interpolationBody = cv::makePtr >(src, dst, lut_, tileSize, tilesX_, tilesY_); + { + interpolationBody = cv::makePtr >(src, dst, lut_, tileSize, tilesX_, tilesY_, bitShift_); + } cv::parallel_for_(cv::Range(0, src.rows), *interpolationBody); } @@ -449,6 +464,16 @@ namespace return cv::Size(tilesX_, tilesY_); } + void CLAHE_Impl::setBitShift(int bitShift) + { + bitShift_ = bitShift; + } + + int CLAHE_Impl::getBitShift() const + { + return bitShift_; + } + void CLAHE_Impl::collectGarbage() { srcExt_.release(); diff --git a/modules/imgproc/src/drawing.cpp b/modules/imgproc/src/drawing.cpp index 3f4f62046c..89898e2445 100644 --- a/modules/imgproc/src/drawing.cpp +++ b/modules/imgproc/src/drawing.cpp @@ -1647,6 +1647,18 @@ ThickLine( Mat& img, Point2l p0, Point2l p1, const void* color, { static const double INV_XY_ONE = 1./static_cast(XY_ONE); + Rect_ boundingRect(Point2l(0, 0), (Size2l)img.size()); + if( (thickness > 1) && (shift == 0) && ( !boundingRect.contains(p0) || !boundingRect.contains(p1) ) ) + { + const int margin = thickness; + const Point2l offset(margin, margin); + p0 += offset; + p1 += offset; + clipLine(Size2l(boundingRect.width+2*margin, boundingRect.height+2*margin), p0, p1); + p0 -= offset; + p1 -= offset; + } + p0.x <<= XY_SHIFT - shift; p0.y <<= XY_SHIFT - shift; p1.x <<= XY_SHIFT - shift; diff --git a/modules/imgproc/src/geometry.cpp b/modules/imgproc/src/geometry.cpp index 244cae4e19..8bef6668cd 100644 --- a/modules/imgproc/src/geometry.cpp +++ b/modules/imgproc/src/geometry.cpp @@ -651,171 +651,108 @@ static Rect pointSetBoundingRect( const Mat& points ) int depth = points.depth(); CV_Assert(npoints >= 0 && (depth == CV_32F || depth == CV_32S)); - int xmin = 0, ymin = 0, xmax = -1, ymax = -1, i; + int xmin = 0, ymin = 0, xmax = -1, ymax = -1, i = 0; bool is_float = depth == CV_32F; if( npoints == 0 ) return Rect(); -#if CV_SIMD // TODO: enable for CV_SIMD_SCALABLE, loop tail related. if( !is_float ) { const int32_t* pts = points.ptr(); int64_t firstval = 0; std::memcpy(&firstval, pts, sizeof(pts[0]) * 2); + xmin = xmax = pts[0]; + ymin = ymax = pts[1]; +#if CV_SIMD || CV_SIMD_SCALABLE v_int32 minval, maxval; minval = maxval = v_reinterpret_as_s32(vx_setall_s64(firstval)); //min[0]=pt.x, min[1]=pt.y, min[2]=pt.x, min[3]=pt.y - for( i = 1; i <= npoints - VTraits::vlanes()/2; i+= VTraits::vlanes()/2 ) + const int nlanes = VTraits::vlanes()/2; + for (; i < npoints; i += nlanes) { + if (i > npoints - nlanes) + { + if (i == 0) + break; + i = npoints - nlanes; + } v_int32 ptXY2 = vx_load(pts + 2 * i); minval = v_min(ptXY2, minval); maxval = v_max(ptXY2, maxval); } - minval = v_min(v_reinterpret_as_s32(v_expand_low(v_reinterpret_as_u32(minval))), v_reinterpret_as_s32(v_expand_high(v_reinterpret_as_u32(minval)))); - maxval = v_max(v_reinterpret_as_s32(v_expand_low(v_reinterpret_as_u32(maxval))), v_reinterpret_as_s32(v_expand_high(v_reinterpret_as_u32(maxval)))); - if( i <= npoints - VTraits::vlanes()/4 ) + constexpr int max_nlanes = VTraits::max_nlanes; + int arr_minval[max_nlanes], arr_maxval[max_nlanes]; + vx_store(arr_minval, minval); + vx_store(arr_maxval, maxval); + for (int j = 0; j < nlanes; j++) { - v_int32 ptXY = v_reinterpret_as_s32(v_expand_low(v_reinterpret_as_u32(vx_load_low(pts + 2 * i)))); - minval = v_min(ptXY, minval); - maxval = v_max(ptXY, maxval); - i += VTraits::vlanes()/2; + xmin = std::min(xmin, arr_minval[2*j]); + ymin = std::min(ymin, arr_minval[2*j+1]); + xmax = std::max(xmax, arr_maxval[2*j]); + ymax = std::max(ymax, arr_maxval[2*j+1]); } - for(int j = 16; j < VTraits::vlanes(); j*=2) +#endif + for( ; i < npoints; i++ ) { - minval = v_min(v_reinterpret_as_s32(v_expand_low(v_reinterpret_as_u32(minval))), v_reinterpret_as_s32(v_expand_high(v_reinterpret_as_u32(minval)))); - maxval = v_max(v_reinterpret_as_s32(v_expand_low(v_reinterpret_as_u32(maxval))), v_reinterpret_as_s32(v_expand_high(v_reinterpret_as_u32(maxval)))); + int pt_x = pts[2*i]; + int pt_y = pts[2*i+1]; + + xmin = std::min(xmin, pt_x); + xmax = std::max(xmax, pt_x); + ymin = std::min(ymin, pt_y); + ymax = std::max(ymax, pt_y); } - xmin = v_get0(minval); - xmax = v_get0(maxval); - ymin = v_get0(v_reinterpret_as_s32(v_expand_high(v_reinterpret_as_u32(minval)))); - ymax = v_get0(v_reinterpret_as_s32(v_expand_high(v_reinterpret_as_u32(maxval)))); -#if CV_SIMD_WIDTH > 16 - if( i < npoints ) - { - v_int32x4 minval2, maxval2; - minval2 = maxval2 = v_reinterpret_as_s32(v_expand_low(v_reinterpret_as_u32(v_load_low(pts + 2 * i)))); - for( i++; i < npoints; i++ ) - { - v_int32x4 ptXY = v_reinterpret_as_s32(v_expand_low(v_reinterpret_as_u32(v_load_low(pts + 2 * i)))); - minval2 = v_min(ptXY, minval2); - maxval2 = v_max(ptXY, maxval2); - } - xmin = min(xmin, v_get0(minval2)); - xmax = max(xmax, v_get0(maxval2)); - ymin = min(ymin, v_get0(v_reinterpret_as_s32(v_expand_high(v_reinterpret_as_u32(minval2))))); - ymax = max(ymax, v_get0(v_reinterpret_as_s32(v_expand_high(v_reinterpret_as_u32(maxval2))))); - } -#endif // CV_SIMD } else { const float* pts = points.ptr(); int64_t firstval = 0; std::memcpy(&firstval, pts, sizeof(pts[0]) * 2); + xmin = xmax = cvFloor(pts[0]); + ymin = ymax = cvFloor(pts[1]); +#if CV_SIMD || CV_SIMD_SCALABLE v_float32 minval, maxval; minval = maxval = v_reinterpret_as_f32(vx_setall_s64(firstval)); //min[0]=pt.x, min[1]=pt.y, min[2]=pt.x, min[3]=pt.y - for( i = 1; i <= npoints - VTraits::vlanes()/2; i+= VTraits::vlanes()/2 ) + const int nlanes = VTraits::vlanes()/2; + for (; i < npoints; i += nlanes) { + if (i > npoints - nlanes) + { + if (i == 0) + break; + i = npoints - nlanes; + } v_float32 ptXY2 = vx_load(pts + 2 * i); minval = v_min(ptXY2, minval); maxval = v_max(ptXY2, maxval); } - minval = v_min(v_reinterpret_as_f32(v_expand_low(v_reinterpret_as_u32(minval))), v_reinterpret_as_f32(v_expand_high(v_reinterpret_as_u32(minval)))); - maxval = v_max(v_reinterpret_as_f32(v_expand_low(v_reinterpret_as_u32(maxval))), v_reinterpret_as_f32(v_expand_high(v_reinterpret_as_u32(maxval)))); - if( i <= npoints - VTraits::vlanes()/4 ) + constexpr int max_nlanes = VTraits::max_nlanes; + float arr_minval[max_nlanes], arr_maxval[max_nlanes]; + vx_store(arr_minval, minval); + vx_store(arr_maxval, maxval); + for (int j = 0; j < nlanes; j++) { - v_float32 ptXY = v_reinterpret_as_f32(v_expand_low(v_reinterpret_as_u32(vx_load_low(pts + 2 * i)))); - minval = v_min(ptXY, minval); - maxval = v_max(ptXY, maxval); - i += VTraits::vlanes()/4; - } - for(int j = 16; j < VTraits::vlanes(); j*=2) - { - minval = v_min(v_reinterpret_as_f32(v_expand_low(v_reinterpret_as_u32(minval))), v_reinterpret_as_f32(v_expand_high(v_reinterpret_as_u32(minval)))); - maxval = v_max(v_reinterpret_as_f32(v_expand_low(v_reinterpret_as_u32(maxval))), v_reinterpret_as_f32(v_expand_high(v_reinterpret_as_u32(maxval)))); - } - xmin = cvFloor(v_get0(minval)); - xmax = cvFloor(v_get0(maxval)); - ymin = cvFloor(v_get0(v_reinterpret_as_f32(v_expand_high(v_reinterpret_as_u32(minval))))); - ymax = cvFloor(v_get0(v_reinterpret_as_f32(v_expand_high(v_reinterpret_as_u32(maxval))))); -#if CV_SIMD_WIDTH > 16 - if( i < npoints ) - { - v_float32x4 minval2, maxval2; - minval2 = maxval2 = v_reinterpret_as_f32(v_expand_low(v_reinterpret_as_u32(v_load_low(pts + 2 * i)))); - for( i++; i < npoints; i++ ) - { - v_float32x4 ptXY = v_reinterpret_as_f32(v_expand_low(v_reinterpret_as_u32(v_load_low(pts + 2 * i)))); - minval2 = v_min(ptXY, minval2); - maxval2 = v_max(ptXY, maxval2); - } - xmin = min(xmin, cvFloor(v_get0(minval2))); - xmax = max(xmax, cvFloor(v_get0(maxval2))); - ymin = min(ymin, cvFloor(v_get0(v_reinterpret_as_f32(v_expand_high(v_reinterpret_as_u32(minval2)))))); - ymax = max(ymax, cvFloor(v_get0(v_reinterpret_as_f32(v_expand_high(v_reinterpret_as_u32(maxval2)))))); + int _xmin = cvFloor(arr_minval[2*j]), _ymin = cvFloor(arr_minval[2*j+1]); + int _xmax = cvFloor(arr_maxval[2*j]), _ymax = cvFloor(arr_maxval[2*j+1]); + xmin = std::min(xmin, _xmin); + ymin = std::min(ymin, _ymin); + xmax = std::max(xmax, _xmax); + ymax = std::max(ymax, _ymax); } #endif - } -#else - const Point* pts = points.ptr(); - Point pt = pts[0]; - - if( !is_float ) - { - xmin = xmax = pt.x; - ymin = ymax = pt.y; - - for( i = 1; i < npoints; i++ ) + for( ; i < npoints; i++ ) { - pt = pts[i]; + // because right and bottom sides of the bounding rectangle are not inclusive + // (note +1 in width and height calculation below), cvFloor is used here instead of cvCeil + int pt_x = cvFloor(pts[2*i]); + int pt_y = cvFloor(pts[2*i+1]); - if( xmin > pt.x ) - xmin = pt.x; - - if( xmax < pt.x ) - xmax = pt.x; - - if( ymin > pt.y ) - ymin = pt.y; - - if( ymax < pt.y ) - ymax = pt.y; + xmin = std::min(xmin, pt_x); + xmax = std::max(xmax, pt_x); + ymin = std::min(ymin, pt_y); + ymax = std::max(ymax, pt_y); } } - else - { - Cv32suf v; - // init values - xmin = xmax = CV_TOGGLE_FLT(pt.x); - ymin = ymax = CV_TOGGLE_FLT(pt.y); - - for( i = 1; i < npoints; i++ ) - { - pt = pts[i]; - pt.x = CV_TOGGLE_FLT(pt.x); - pt.y = CV_TOGGLE_FLT(pt.y); - - if( xmin > pt.x ) - xmin = pt.x; - - if( xmax < pt.x ) - xmax = pt.x; - - if( ymin > pt.y ) - ymin = pt.y; - - if( ymax < pt.y ) - ymax = pt.y; - } - - v.i = CV_TOGGLE_FLT(xmin); xmin = cvFloor(v.f); - v.i = CV_TOGGLE_FLT(ymin); ymin = cvFloor(v.f); - // because right and bottom sides of the bounding rectangle are not inclusive - // (note +1 in width and height calculation below), cvFloor is used here instead of cvCeil - v.i = CV_TOGGLE_FLT(xmax); xmax = cvFloor(v.f); - v.i = CV_TOGGLE_FLT(ymax); ymax = cvFloor(v.f); - } -#endif return Rect(xmin, ymin, xmax - xmin + 1, ymax - ymin + 1); } diff --git a/modules/imgproc/src/grabcut.cpp b/modules/imgproc/src/grabcut.cpp index 358747843e..115f346e99 100644 --- a/modules/imgproc/src/grabcut.cpp +++ b/modules/imgproc/src/grabcut.cpp @@ -371,28 +371,30 @@ static void initGMMs( const Mat& img, const Mat& mask, GMM& bgdGMM, GMM& fgdGMM const int kMeansType = KMEANS_PP_CENTERS; Mat bgdLabels, fgdLabels; - std::vector bgdSamples, fgdSamples; + std::vector bgdSamples, fgdSamples; Point p; for( p.y = 0; p.y < img.rows; p.y++ ) { for( p.x = 0; p.x < img.cols; p.x++ ) { if( mask.at(p) == GC_BGD || mask.at(p) == GC_PR_BGD ) - bgdSamples.push_back( (Vec3f)img.at(p) ); + bgdSamples.push_back( img.at(p) ); else // GC_FGD | GC_PR_FGD - fgdSamples.push_back( (Vec3f)img.at(p) ); + fgdSamples.push_back( img.at(p) ); } } CV_Assert( !bgdSamples.empty() && !fgdSamples.empty() ); { - Mat _bgdSamples( (int)bgdSamples.size(), 3, CV_32FC1, &bgdSamples[0][0] ); + Mat _bgdSamples( (int)bgdSamples.size(), 3, CV_8UC1, &bgdSamples[0][0] ); + _bgdSamples.convertTo(_bgdSamples, CV_32FC1); int num_clusters = GMM::componentsCount; num_clusters = std::min(num_clusters, (int)bgdSamples.size()); kmeans( _bgdSamples, num_clusters, bgdLabels, TermCriteria( TermCriteria::MAX_ITER, kMeansItCount, 0.0), 0, kMeansType ); } { - Mat _fgdSamples( (int)fgdSamples.size(), 3, CV_32FC1, &fgdSamples[0][0] ); + Mat _fgdSamples( (int)fgdSamples.size(), 3, CV_8UC1, &fgdSamples[0][0] ); + _fgdSamples.convertTo(_fgdSamples, CV_32FC1); int num_clusters = GMM::componentsCount; num_clusters = std::min(num_clusters, (int)fgdSamples.size()); kmeans( _fgdSamples, num_clusters, fgdLabels, @@ -401,12 +403,12 @@ static void initGMMs( const Mat& img, const Mat& mask, GMM& bgdGMM, GMM& fgdGMM bgdGMM.initLearning(); for( int i = 0; i < (int)bgdSamples.size(); i++ ) - bgdGMM.addSample( bgdLabels.at(i,0), bgdSamples[i] ); + bgdGMM.addSample( bgdLabels.at(i,0), Vec3d(bgdSamples[i]) ); bgdGMM.endLearning(); fgdGMM.initLearning(); for( int i = 0; i < (int)fgdSamples.size(); i++ ) - fgdGMM.addSample( fgdLabels.at(i,0), fgdSamples[i] ); + fgdGMM.addSample( fgdLabels.at(i,0), Vec3d(fgdSamples[i]) ); fgdGMM.endLearning(); } diff --git a/modules/imgproc/src/hough.cpp b/modules/imgproc/src/hough.cpp index f82ecec504..9e81b396da 100644 --- a/modules/imgproc/src/hough.cpp +++ b/modules/imgproc/src/hough.cpp @@ -228,7 +228,7 @@ HoughLinesStandard( InputArray src, OutputArray lines, int type, int idx = _sort_buf[i]; int n = cvFloor(idx*scale) - 1; int r = idx - (n+1)*(numrho+2) - 1; - line.rho = (r - (numrho - 1)*0.5f) * rho; + line.rho = (r - (numrho - 1)/2) * rho; line.angle = static_cast(min_theta) + n * theta; if (type == CV_32FC2) { diff --git a/modules/imgproc/src/moments.cpp b/modules/imgproc/src/moments.cpp index c5bb115cb9..287cc125a9 100644 --- a/modules/imgproc/src/moments.cpp +++ b/modules/imgproc/src/moments.cpp @@ -401,7 +401,7 @@ static bool ocl_moments( InputArray _src, Moments& m, bool binary) const int TILE_SIZE = 32; const int K = 10; - Size sz = _src.getSz(); + Size sz = _src.size(); int xtiles = divUp(sz.width, TILE_SIZE); int ytiles = divUp(sz.height, TILE_SIZE); int ntiles = xtiles*ytiles; diff --git a/modules/imgproc/src/opencl/hough_lines.cl b/modules/imgproc/src/opencl/hough_lines.cl index 907811cded..5ae4171fcb 100644 --- a/modules/imgproc/src/opencl/hough_lines.cl +++ b/modules/imgproc/src/opencl/hough_lines.cl @@ -162,7 +162,7 @@ __kernel void get_lines(__global uchar * accum_ptr, int accum_step, int accum_of if (index < linesMax) { - float radius = (x - (accum_cols - 3) * 0.5f) * rho; + float radius = (x - (accum_cols - 3) / 2) * rho; float angle = y * theta; lines[index] = (float2)(radius, angle); diff --git a/modules/imgproc/test/test_drawing.cpp b/modules/imgproc/test/test_drawing.cpp index 12e10a1396..9424a38133 100755 --- a/modules/imgproc/test/test_drawing.cpp +++ b/modules/imgproc/test/test_drawing.cpp @@ -592,7 +592,7 @@ TEST(Drawing, longline) Mat mat = Mat::zeros(256, 256, CV_8UC1); line(mat, cv::Point(34, 204), cv::Point(46400, 47400), cv::Scalar(255), 3); - EXPECT_EQ(310, cv::countNonZero(mat)); + EXPECT_EQ(264, cv::countNonZero(mat)); Point pt[6]; pt[0].x = 32; diff --git a/modules/imgproc/test/test_houghlines.cpp b/modules/imgproc/test/test_houghlines.cpp index 02eb2d4379..82b2864b13 100644 --- a/modules/imgproc/test/test_houghlines.cpp +++ b/modules/imgproc/test/test_houghlines.cpp @@ -340,6 +340,69 @@ TEST(HoughLines, regression_21983) EXPECT_NEAR(lines[0][1], 1.57179642, 1e-4); } +TEST(HoughLines, regression_25038_vertical) +{ + cv::Mat img = cv::Mat::zeros(8, 8, CV_8UC1); + img.col(3).setTo(255); + + cv::Mat lines; + cv::HoughLines(img, lines, 0.5, CV_PI/4., 2); + EXPECT_EQ(1, lines.cols); + EXPECT_EQ(1, lines.rows); + EXPECT_EQ(2, lines.channels()); + EXPECT_NEAR(3, lines.at(0)[0], 1e-5); + EXPECT_NEAR(0, lines.at(0)[1], 1e-5); + + cv::HoughLines(img, lines, 0.05, CV_PI/4., 2); + EXPECT_EQ(1, lines.cols); + EXPECT_EQ(1, lines.rows); + EXPECT_EQ(2, lines.channels()); + EXPECT_NEAR(3, lines.at(0)[0], 1e-5); + EXPECT_NEAR(0, lines.at(0)[1], 1e-5); +} + +TEST(HoughLines, regression_25038_even) +{ + cv::Mat img = cv::Mat::zeros(8, 8, CV_8UC1); + img.col(4).setTo(255); + + cv::Mat lines; + cv::HoughLines(img, lines, 0.5, CV_PI/4., 2); + EXPECT_EQ(1, lines.cols); + EXPECT_EQ(1, lines.rows); + EXPECT_EQ(2, lines.channels()); + EXPECT_NEAR(4, lines.at(0)[0], 1e-5); + EXPECT_NEAR(0, lines.at(0)[1], 1e-5); + + cv::HoughLines(img, lines, 0.05, CV_PI/4., 2); + EXPECT_EQ(1, lines.cols); + EXPECT_EQ(1, lines.rows); + EXPECT_EQ(2, lines.channels()); + EXPECT_NEAR(4, lines.at(0)[0], 1e-5); + EXPECT_NEAR(0, lines.at(0)[1], 1e-5); +} + +TEST(HoughLines, regression_25038_horizontal) +{ + cv::Mat img = cv::Mat::zeros(8, 8, CV_8UC1); + img.row(3).setTo(255); + + cv::Mat lines; + cv::HoughLines(img, lines, 0.5, CV_PI/4., 2); + EXPECT_EQ(1, lines.cols); + EXPECT_EQ(1, lines.rows); + EXPECT_EQ(2, lines.channels()); + EXPECT_NEAR(3, lines.at(0)[0], 1e-5); + EXPECT_NEAR(CV_PI/2., lines.at(0)[1], 1e-5); + + cv::HoughLines(img, lines, 0.05, CV_PI/4., 2); + EXPECT_EQ(1, lines.cols); + EXPECT_EQ(1, lines.rows); + EXPECT_EQ(2, lines.channels()); + EXPECT_NEAR(3, lines.at(0)[0], 1e-5); + EXPECT_NEAR(CV_PI/2., lines.at(0)[1], 1e-5); +} + TEST(WeightedHoughLines, horizontal) { Mat img(25, 25, CV_8UC1, Scalar(0)); diff --git a/modules/js/test/test_features.js b/modules/js/test/test_features.js index 6875189a9d..d497091c71 100644 --- a/modules/js/test/test_features.js +++ b/modules/js/test/test_features.js @@ -26,7 +26,7 @@ QUnit.test('Detectors', function(assert) { let orb = new cv.ORB(); orb.detect(image, kp); - assert.equal(kp.size(), 67, 'ORB'); + assert.equal(kp.size(), 68, 'ORB'); /* TODO: Fix test failure Expected: 7 Result: 0 bug: https://github.com/opencv/opencv/issues/25862 @@ -62,14 +62,14 @@ QUnit.test('BFMatcher', function(assert) { let orb = new cv.ORB(); orb.detectAndCompute(image, new cv.Mat(), kp, descriptors); - assert.equal(kp.size(), 67); + assert.equal(kp.size(), 68); // Run a matcher. let dm = new cv.DMatchVector(); let matcher = new cv.BFMatcher(); matcher.match(descriptors, descriptors, dm); - assert.equal(dm.size(), 67); + assert.equal(dm.size(), 68); }); QUnit.test('Drawing', function(assert) { @@ -80,7 +80,7 @@ QUnit.test('Drawing', function(assert) { let descriptors = new cv.Mat(); let orb = new cv.ORB(); orb.detectAndCompute(image, new cv.Mat(), kp, descriptors); - assert.equal(kp.size(), 67); + assert.equal(kp.size(), 68); let dst = new cv.Mat(); cv.drawKeypoints(image, kp, dst); @@ -91,7 +91,7 @@ QUnit.test('Drawing', function(assert) { let dm = new cv.DMatchVector(); let matcher = new cv.BFMatcher(); matcher.match(descriptors, descriptors, dm); - assert.equal(dm.size(), 67); + assert.equal(dm.size(), 68); cv.drawMatches(image, kp, image, kp, dm, dst); assert.equal(dst.rows, image.rows); @@ -99,7 +99,7 @@ QUnit.test('Drawing', function(assert) { dm = new cv.DMatchVectorVector(); matcher.knnMatch(descriptors, descriptors, dm, 2); - assert.equal(dm.size(), 67); + assert.equal(dm.size(), 68); cv.drawMatchesKnn(image, kp, image, kp, dm, dst); assert.equal(dst.rows, image.rows); assert.equal(dst.cols, 2 * image.cols); diff --git a/modules/python/src2/typing_stubs_generation/nodes/type_node.py b/modules/python/src2/typing_stubs_generation/nodes/type_node.py index 86bd744a1c..f6ba773654 100644 --- a/modules/python/src2/typing_stubs_generation/nodes/type_node.py +++ b/modules/python/src2/typing_stubs_generation/nodes/type_node.py @@ -274,14 +274,21 @@ class AliasTypeNode(TypeNode): required_modules: Tuple[str, ...] = ()) -> None: super().__init__(ctype_name, required_modules) self.value = value - self._export_name = export_name + # If alias is exported as is - use its ctype_name + if export_name is None: + forbidden_symbols = (":", "*", "&") + assert all(symbol not in ctype_name for symbol in forbidden_symbols), ( + "Failed to create AliasTypeNode without export_name. " + f"'{ctype_name}' should not contain any of {forbidden_symbols}" + ) + self._export_name = ctype_name + else: + self._export_name = export_name self.doc = doc @property def typename(self) -> str: - if self._export_name is not None: - return self._export_name - return self.ctype_name + return self._export_name @property def full_typename(self) -> str: diff --git a/modules/videoio/cmake/detect_ffmpeg.cmake b/modules/videoio/cmake/detect_ffmpeg.cmake index dd5eefaac9..7ad5ecb950 100644 --- a/modules/videoio/cmake/detect_ffmpeg.cmake +++ b/modules/videoio/cmake/detect_ffmpeg.cmake @@ -12,7 +12,7 @@ if(NOT HAVE_FFMPEG AND OPENCV_FFMPEG_USE_FIND_PACKAGE) endif() endif() -if(NOT HAVE_FFMPEG AND WIN32 AND NOT ARM AND NOT OPENCV_FFMPEG_SKIP_DOWNLOAD) +if(NOT HAVE_FFMPEG AND WIN32 AND NOT ARM AND NOT AARCH64 AND NOT OPENCV_FFMPEG_SKIP_DOWNLOAD) include("${OpenCV_SOURCE_DIR}/3rdparty/ffmpeg/ffmpeg.cmake") download_win_ffmpeg(FFMPEG_CMAKE_SCRIPT) if(FFMPEG_CMAKE_SCRIPT) diff --git a/modules/videoio/cmake/detect_obsensor.cmake b/modules/videoio/cmake/detect_obsensor.cmake index c7e6164c0f..0fa41481d9 100644 --- a/modules/videoio/cmake/detect_obsensor.cmake +++ b/modules/videoio/cmake/detect_obsensor.cmake @@ -13,8 +13,12 @@ if(NOT HAVE_OBSENSOR) set(HAVE_OBSENSOR TRUE) set(HAVE_OBSENSOR_ORBBEC_SDK TRUE) ocv_add_external_target(obsensor "${OrbbecSDK_INCLUDE_DIRS}" "${OrbbecSDK_LIBRARY}" "HAVE_OBSENSOR;HAVE_OBSENSOR_ORBBEC_SDK") - file(COPY ${OrbbecSDK_DLL_FILES} DESTINATION ${CMAKE_BINARY_DIR}/bin) file(COPY ${OrbbecSDK_DLL_FILES} DESTINATION ${CMAKE_BINARY_DIR}/lib) + if(NOT ORBBEC_SDK_VERSION STREQUAL "1") + # OrbbecSDK v2 loads some libraries at runtime. + file(COPY ${OrbbecSDK_RUNTIME_RESOURCE_FILES} DESTINATION ${CMAKE_BINARY_DIR}/lib) + install(DIRECTORY ${OrbbecSDK_RUNTIME_RESOURCE_FILES} DESTINATION ${OPENCV_LIB_INSTALL_PATH}) + endif() install(FILES ${OrbbecSDK_DLL_FILES} DESTINATION ${OPENCV_LIB_INSTALL_PATH}) ocv_install_3rdparty_licenses(OrbbecSDK ${OrbbecSDK_DIR}/LICENSE.txt) endif() diff --git a/modules/videoio/src/cap_msmf.cpp b/modules/videoio/src/cap_msmf.cpp index 5c2121498d..f5c1b65663 100644 --- a/modules/videoio/src/cap_msmf.cpp +++ b/modules/videoio/src/cap_msmf.cpp @@ -1569,6 +1569,7 @@ bool CvCapture_MSMF::configureAudioFrame() { if (!audioSamples.empty() || !bufferAudioData.empty() && aEOS) { + const int bytesPerSample = (captureAudioFormat.bit_per_sample/8) * captureAudioFormat.nChannels; _ComPtr buf = NULL; std::vector audioDataInUse; BYTE* ptr = NULL; @@ -1601,20 +1602,19 @@ bool CvCapture_MSMF::configureAudioFrame() } audioSamples.clear(); - audioSamplePos += chunkLengthOfBytes/((captureAudioFormat.bit_per_sample/8)*captureAudioFormat.nChannels); - chunkLengthOfBytes = (videoStream != -1) ? (LONGLONG)((requiredAudioTime*captureAudioFormat.nSamplesPerSec*captureAudioFormat.nChannels*(captureAudioFormat.bit_per_sample)/8)/1e7) : cursize; - if ((videoStream != -1) && (chunkLengthOfBytes % ((int)(captureAudioFormat.bit_per_sample)/8* (int)captureAudioFormat.nChannels) != 0)) + audioSamplePos += chunkLengthOfBytes/bytesPerSample; + chunkLengthOfBytes = (videoStream != -1) ? (LONGLONG)((requiredAudioTime*captureAudioFormat.nSamplesPerSec*bytesPerSample)/1e7) : cursize; + if ((videoStream != -1) && (chunkLengthOfBytes % bytesPerSample != 0)) { if ( (double)audioSamplePos/captureAudioFormat.nSamplesPerSec + audioStartOffset * 1e-7 - usedVideoSampleTime * 1e-7 >= 0 ) chunkLengthOfBytes -= numberOfAdditionalAudioBytes; - numberOfAdditionalAudioBytes = ((int)(captureAudioFormat.bit_per_sample)/8* (int)captureAudioFormat.nChannels) - - chunkLengthOfBytes % ((int)(captureAudioFormat.bit_per_sample)/8* (int)captureAudioFormat.nChannels); + numberOfAdditionalAudioBytes = bytesPerSample - chunkLengthOfBytes % bytesPerSample; chunkLengthOfBytes += numberOfAdditionalAudioBytes; } if (lastFrame && !syncLastFrame || aEOS && !vEOS) { chunkLengthOfBytes = bufferAudioData.size(); - audioSamplePos += chunkLengthOfBytes/((captureAudioFormat.bit_per_sample/8)*captureAudioFormat.nChannels); + audioSamplePos += chunkLengthOfBytes/bytesPerSample; } CV_Check((double)chunkLengthOfBytes, chunkLengthOfBytes >= INT_MIN || chunkLengthOfBytes <= INT_MAX, "MSMF: The chunkLengthOfBytes is out of the allowed range"); copy(bufferAudioData.begin(), bufferAudioData.begin() + (int)chunkLengthOfBytes, std::back_inserter(audioDataInUse)); @@ -1825,7 +1825,8 @@ bool CvCapture_MSMF::grabFrame() if (audioStream != -1) { - bufferedAudioDuration = (double)(bufferAudioData.size()/((captureAudioFormat.bit_per_sample/8)*captureAudioFormat.nChannels))/captureAudioFormat.nSamplesPerSec; + const int bytesPerSample = (captureAudioFormat.bit_per_sample/8) * captureAudioFormat.nChannels; + bufferedAudioDuration = (double)(bufferAudioData.size()/bytesPerSample)/captureAudioFormat.nSamplesPerSec; audioFrame.release(); if (!aEOS) returnFlag &= grabAudioFrame(); diff --git a/modules/videoio/src/cap_obsensor_liborbbec.cpp b/modules/videoio/src/cap_obsensor_liborbbec.cpp index 3337d6f3ba..d8b44cf196 100644 --- a/modules/videoio/src/cap_obsensor_liborbbec.cpp +++ b/modules/videoio/src/cap_obsensor_liborbbec.cpp @@ -38,6 +38,9 @@ VideoCapture_obsensor::VideoCapture_obsensor(int, const cv::VideoCaptureParamete ob::Context::setLoggerToFile(OB_LOG_SEVERITY_OFF, ""); config = std::make_shared(); pipe = std::make_shared(); +#if ORBBEC_SDK_VERSION_MAJOR != 1 + alignFilter = std::make_shared(OB_STREAM_COLOR); +#endif int color_width = params.get(CAP_PROP_FRAME_WIDTH, OB_WIDTH_ANY); int color_height = params.get(CAP_PROP_FRAME_HEIGHT, OB_HEIGHT_ANY); @@ -75,12 +78,25 @@ VideoCapture_obsensor::VideoCapture_obsensor(int, const cv::VideoCaptureParamete config->enableStream(depthProfile->as()); } +#if ORBBEC_SDK_VERSION_MAJOR == 1 config->setAlignMode(ALIGN_D2C_SW_MODE); +#else + config->setFrameAggregateOutputMode(OB_FRAME_AGGREGATE_OUTPUT_ALL_TYPE_FRAME_REQUIRE); + pipe->enableFrameSync(); +#endif pipe->start(config, [&](std::shared_ptr frameset) { std::unique_lock lk(videoFrameMutex); +#if ORBBEC_SDK_VERSION_MAJOR == 1 colorFrame = frameset->colorFrame(); depthFrame = frameset->depthFrame(); +#else + auto alignFrameSet = alignFilter->process(frameset); + if (alignFrameSet) { + colorFrame = alignFrameSet->as()->colorFrame(); + depthFrame = alignFrameSet->as()->depthFrame(); + } +#endif }); auto param = pipe->getCameraParam(); diff --git a/modules/videoio/src/cap_obsensor_liborbbec.hpp b/modules/videoio/src/cap_obsensor_liborbbec.hpp index aa8c1d4728..d280d846e5 100644 --- a/modules/videoio/src/cap_obsensor_liborbbec.hpp +++ b/modules/videoio/src/cap_obsensor_liborbbec.hpp @@ -59,6 +59,9 @@ protected: std::shared_ptr grabbedDepthFrame; std::shared_ptr pipe; std::shared_ptr config; +#if ORBBEC_SDK_VERSION_MAJOR != 1 + std::shared_ptr alignFilter; +#endif CameraParam camParam; }; diff --git a/samples/dnn/js_face_recognition.html b/samples/dnn/js_face_recognition.html index 3b4ed390d7..aaee89327f 100644 --- a/samples/dnn/js_face_recognition.html +++ b/samples/dnn/js_face_recognition.html @@ -132,7 +132,7 @@ function main() { var cell = document.getElementById("targetNames").insertCell(0); cell.innerHTML = name; - persons[name] = face2vec(face).clone(); + persons[name] = face2vec(face).mat_clone(); var canvas = document.createElement("canvas"); canvas.setAttribute("width", 112);