1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-31 08:13:04 +04:00

Compare commits

...

22 Commits

Author SHA1 Message Date
Abhishek Gola e35ad60e4e Merge pull request #29544 from xi-guo-0/core-optimize-extract-channel-8uc2
core: optimize 8UC2 channel extraction
2026-07-30 16:49:19 +05:30
Abhishek Gola f42fa7b214 Merge pull request #29553 from mvanhorn/fix/26746-warn-external-grfmt-fallback
cmake: warn when external image-codec library is requested but not found 🤖🤖🤖
2026-07-30 16:38:23 +05:30
Abhishek Gola 2fb7adbd53 Merge pull request #29552 from sergiud/opencl-remap-artifacts
imgproc: fix OpenCL remap negative border rounding
2026-07-30 15:46:30 +05:30
Abhishek Gola 2b6c3df954 Merge pull request #29546 from uwezkhan/dtree-split-index-bound
bound categorical split indices in dtrees readSplit
2026-07-29 13:31:38 +05:30
Abhishek Gola a906dfbed2 Merge pull request #29626 from ArneshBanerjee/fix-29615-icvcvt-pointer-overflow-4x
imgcodecs: fix pointer overflow in 16u icvCvt helpers (4.x)
2026-07-28 19:52:22 +05:30
Arnesh Banerjee b7860407f0 imgcodecs: fix pointer overflow in 16u icvCvt helpers
The 16-bit icvCvt_* helpers in utils.cpp move the row pointer with
step/sizeof(x[0]) - size.width*N. sizeof is unsigned, so this is done in
unsigned math. When the caller passes step == 0, it underflows to a huge
value and the pointer goes out of range, which is undefined behavior.

The TIFF decoder hits this: it walks rows itself and calls these helpers
with step = 0, so reading a 16-bit 4-channel TIFF triggers the bug.

Cast sizeof(...) to int so the math is signed. Same result for normal
calls, no overflow when the step is 0.

Added Imgcodecs_Tiff.regression_29615_16UC4 which round-trips a CV_16UC4
TIFF in memory.

This is the 4.x version of the fix, requested in
https://github.com/opencv/opencv/pull/29620 (issue #29615).
2026-07-28 16:19:17 +05:30
Uwez Khan dee2bb288b bound categorical split indices in dtrees readSplit 2026-07-27 10:54:57 +05:30
Sergiu Deitsch 096759c0b0 imgproc: fix OpenCL remap negative rounding
Truncation toward zero produces incorrect interpolation indices for
negative border coordinates. Use nearest-even rounding so OpenCL remap
matches the CPU behavior.
2026-07-27 10:46:53 +05:30
Sergiu Deitsch 73c9537f3b imgproc: fix NVIDIA OpenCL remap kernel types
Match interpolation coefficient types to the working type so the double
kernel compiles on NVIDIA devices.
2026-07-27 10:46:53 +05:30
Alexander Smorkalov 70fc346580 Merge pull request #29549 from hanu-14:fix-https-readme-md
fix: upgrade http:// to https:// in README.md
2026-07-26 15:02:04 +03:00
Andrei Fedorov 664f59e750 Merge pull request #29542 from intel-staging:ipp/enable_instrumentation_fix
Implemented a check to enable instrumentation for IPP HAL #29542

To enable instrumentation for IPP HAL correctly it needed to generalize a part of `private.hpp` and put it to the separate file that can be included in `private.hpp` and `ipp_utils.hpp` both to avoid duplication.

Built with `-DENABLE_INSTRUMENTATION=ON` and ran `opencv_perf_imgproc --perf_instrument=1`:

  | Test | IPP weight before | IPP weight after |
  |---|---|---|
  | `distanceTransform` (8U->32F) | 0.0% | ~76% |
  | `ippSobel` | 0.0% | ~98% |
  | `scharrViaSobelFilter` | 0.0% | ~90% |

### Pull Request Readiness Checklist

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

- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [x] The PR is proposed to the proper branch
- [ ] There is a reference to the original bug report and related work
- [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [ ] The feature is well documented and sample code can be built with the project CMake
2026-07-26 15:01:24 +03:00
Alexander Smorkalov 19ef7e6e16 Merge pull request #29583 from uditjainstjis:fix-23580-hog-buffer-overflow
objdetect: fix out-of-bounds write in HOG gaussian weights #23580 🤖🤖🤖
2026-07-25 10:01:30 +03:00
Udit Jain c8446af29a objdetect: fix out-of-bounds write in HOG gaussian weights (blockSize.height vs width)
In HOGCache::init the block gaussian weights are computed into two buffers:
  AutoBuffer<float> di(blockSize.height), dj(blockSize.width);
The vectorized (CV_SIMD128) loop that fills dj was bounded by
`blockSize.height` instead of `blockSize.width`. When the block is taller than
it is wide, `v_store(_dj + j, ...)` writes past the end of the width-sized dj
buffer, causing a heap buffer overflow / access violation (e.g. HOGDescriptor
with a 198x281 window, or the 2399x2400 case from the report).

Bound the dj loop by `blockSize.width` to match the buffer size and the scalar
tail loop. This keeps the SIMD path (unlike the workaround in the report, which
disabled it).

Added a regression test that computes a HOGDescriptor with a tall block; without
the fix it triggers a heap-buffer-overflow (confirmed with AddressSanitizer at
hog.cpp:731 inside HOGCache::init).

Fixes #23580
2026-07-24 04:51:45 +05:30
Yuantao Feng 0e09f1a238 Merge pull request #29557 from fengyuentau:4x/hal_rvv/split_opt
hal_rvv core: Cover more data types for split with native RVV intrinsics #29557

Covering 16-bit, 32-bit and 64-bit split.

### Pull Request Readiness Checklist

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

- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [x] The PR is proposed to the proper branch
- [x] There is a reference to the original bug report and related work
- [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [x] The feature is well documented and sample code can be built with the project CMake
2026-07-21 10:16:38 +03:00
Alexander Smorkalov ba53d1d6b7 Merge pull request #29566 from fengyuentau:4x/hal_rvv/copy_mask_opt
hal_rvv core: Optimize RVV HAL masked copy
2026-07-21 10:15:07 +03:00
FENG Yuantao 1f36f15a49 Optimize RVV HAL masked copy 2026-07-20 23:43:41 +08:00
Alexander Smorkalov 2b6ea5f344 Merge pull request #29556 from fengyuentau:4x/hal_rvv/merge_opt
hal_rvv core: Optimize 32-bit and 64-bit merge
2026-07-20 12:26:12 +03:00
Xi Guo 1bf1e70c0f core: optimize 8UC2 channel extraction 2026-07-20 10:21:00 +08:00
FENG Yuantao 898f1e9691 Optimize RVV HAL 32-bit and 64-bit merge 2026-07-20 00:22:38 +08:00
Matt Van Horn a859f3feff cmake: warn when external grfmt library requested but not found
When a user disables a bundled image-codec dependency (e.g.
BUILD_ZLIB=OFF) to supply an external build but find_package()
cannot locate it, OpenCVFindLibsGrfmt.cmake silently falls back to
compiling the bundled 3rdparty version. As reported in the issue,
this is misleading: the editable ZLIB_LIBRARY_DEBUG/RELEASE cache
entries have no effect after the fallback and nothing points the
user at the real knob (ZLIB_ROOT / ZLIB_DIR).

Emit a message(WARNING) in each fallback branch, guarded by
NOT BUILD_<lib>, so the built-in fallback is no longer silent when
the user explicitly opted out of the bundled build. The warning
names the correct search variables for that library and points to
the CMake find_package / Find<lib> documentation. Applied
consistently to the zlib, libjpeg, libtiff, libpng and libwebp
fallback branches.

The existing fallback behavior is intentionally left unchanged, so
configurations that rely on the built-in fallback continue to build.

Fixes #26746
2026-07-18 10:02:13 -07:00
Alexander Smorkalov 6f402272e7 Merge branch 'as/release_4.14.0' into 4.x 2026-07-18 09:55:21 +03:00
MOHAMMED HANAN M T P 5ab3e2e580 fix: upgrade http:// to https:// in README.md 2026-07-18 11:13:02 +05:30
22 changed files with 875 additions and 251 deletions
+4 -4
View File
@@ -7,7 +7,7 @@
* Courses: <https://opencv.org/courses> * Courses: <https://opencv.org/courses>
* Docs: <https://docs.opencv.org/4.x/> * Docs: <https://docs.opencv.org/4.x/>
* Q&A forum: <https://forum.opencv.org> * Q&A forum: <https://forum.opencv.org>
* previous forum (read only): <http://answers.opencv.org> * previous forum (read only): <https://answers.opencv.org>
* Issue tracking: <https://github.com/opencv/opencv/issues> * Issue tracking: <https://github.com/opencv/opencv/issues>
* Additional OpenCV functionality: <https://github.com/opencv/opencv_contrib> * Additional OpenCV functionality: <https://github.com/opencv/opencv_contrib>
* Donate to OpenCV: <https://opencv.org/support/> * Donate to OpenCV: <https://opencv.org/support/>
@@ -28,9 +28,9 @@ Please read the [contribution guidelines](https://github.com/opencv/opencv/wiki/
### Additional Resources ### Additional Resources
* [Submit your OpenCV-based project](https://form.jotform.com/233105358823151) for inclusion in Community Friday on opencv.org * [Submit your OpenCV-based project](https://form.jotform.com/233105358823151) for inclusion in Community Friday on opencv.org
* [Subscribe to the OpenCV YouTube Channel](http://youtube.com/@opencvofficial) featuring OpenCV Live, an hour-long streaming show * [Subscribe to the OpenCV YouTube Channel](https://youtube.com/@opencvofficial) featuring OpenCV Live, an hour-long streaming show
* [Follow OpenCV on LinkedIn](http://linkedin.com/company/opencv/) for daily posts showing the state-of-the-art in computer vision & AI * [Follow OpenCV on LinkedIn](https://linkedin.com/company/opencv/) for daily posts showing the state-of-the-art in computer vision & AI
* [Apply to be an OpenCV Volunteer](https://form.jotform.com/232745316792159) to help organize events and online campaigns as well as amplify them * [Apply to be an OpenCV Volunteer](https://form.jotform.com/232745316792159) to help organize events and online campaigns as well as amplify them
* [Follow OpenCV on Mastodon](http://mastodon.social/@opencv) in the Fediverse * [Follow OpenCV on Mastodon](https://mastodon.social/@opencv) in the Fediverse
* [Follow OpenCV on Twitter](https://twitter.com/opencvlive) * [Follow OpenCV on Twitter](https://twitter.com/opencvlive)
* [OpenCV.ai](https://opencv.ai): Computer Vision and AI development services from the OpenCV team. * [OpenCV.ai](https://opencv.ai): Computer Vision and AI development services from the OpenCV team.
+27
View File
@@ -45,6 +45,11 @@ else()
endif() endif()
if(NOT ZLIB_FOUND) if(NOT ZLIB_FOUND)
if(NOT BUILD_ZLIB)
message(WARNING "ZLIB library has not been found, falling back to built-in version. "
"Set ZLIB_ROOT or ZLIB_DIR variable so that find_package(ZLIB) would be able to find it. "
"See find_package and FindZLIB cmake documentation for details.")
endif()
ocv_clear_vars(ZLIB_LIBRARY ZLIB_LIBRARIES ZLIB_INCLUDE_DIR) ocv_clear_vars(ZLIB_LIBRARY ZLIB_LIBRARIES ZLIB_INCLUDE_DIR)
set(ZLIB_LIBRARY zlib CACHE INTERNAL "") set(ZLIB_LIBRARY zlib CACHE INTERNAL "")
@@ -83,6 +88,12 @@ if(WITH_JPEG)
endif() endif()
if(NOT JPEG_FOUND) if(NOT JPEG_FOUND)
if(NOT BUILD_JPEG)
message(WARNING "JPEG library has not been found, falling back to built-in version. "
"Add the external installation prefix to CMAKE_PREFIX_PATH, or set JPEG_INCLUDE_DIR "
"and JPEG_LIBRARY, so that FindJPEG can locate it. "
"See FindJPEG cmake documentation for details.")
endif()
ocv_clear_vars(JPEG_LIBRARY JPEG_INCLUDE_DIR) ocv_clear_vars(JPEG_LIBRARY JPEG_INCLUDE_DIR)
if(NOT BUILD_JPEG_TURBO_DISABLE) if(NOT BUILD_JPEG_TURBO_DISABLE)
@@ -153,6 +164,12 @@ if(WITH_TIFF)
endif() endif()
if(NOT TIFF_FOUND) if(NOT TIFF_FOUND)
if(NOT BUILD_TIFF)
message(WARNING "TIFF library has not been found, falling back to built-in version. "
"Add the external installation prefix to CMAKE_PREFIX_PATH, or set TIFF_INCLUDE_DIR "
"and TIFF_LIBRARY, so that FindTIFF can locate it. "
"See FindTIFF cmake documentation for details.")
endif()
ocv_clear_vars(TIFF_LIBRARY TIFF_LIBRARIES TIFF_INCLUDE_DIR) ocv_clear_vars(TIFF_LIBRARY TIFF_LIBRARIES TIFF_INCLUDE_DIR)
set(TIFF_LIBRARY libtiff CACHE INTERNAL "") set(TIFF_LIBRARY libtiff CACHE INTERNAL "")
@@ -201,6 +218,11 @@ endif()
if(WITH_WEBP AND NOT WEBP_FOUND if(WITH_WEBP AND NOT WEBP_FOUND
AND (NOT ANDROID OR HAVE_CPUFEATURES) AND (NOT ANDROID OR HAVE_CPUFEATURES)
) )
if(NOT BUILD_WEBP)
message(WARNING "WebP library has not been found, falling back to built-in version. "
"Set WEBP_INCLUDE_DIR and WEBP_LIBRARY, or add the external installation prefix to "
"CMAKE_PREFIX_PATH, so that the external WebP can be located.")
endif()
ocv_clear_vars(WEBP_LIBRARY WEBP_INCLUDE_DIR) ocv_clear_vars(WEBP_LIBRARY WEBP_INCLUDE_DIR)
set(WEBP_LIBRARY libwebp CACHE INTERNAL "") set(WEBP_LIBRARY libwebp CACHE INTERNAL "")
set(WEBP_LIBRARIES ${WEBP_LIBRARY}) set(WEBP_LIBRARIES ${WEBP_LIBRARY})
@@ -353,6 +375,11 @@ if(NOT HAVE_SPNG AND WITH_PNG)
endif() endif()
if(NOT PNG_FOUND) if(NOT PNG_FOUND)
if(NOT BUILD_PNG)
message(WARNING "PNG library has not been found, falling back to built-in version. "
"Set PNG_ROOT or PNG_DIR variable so that find_package(PNG) would be able to find it. "
"See find_package and FindPNG cmake documentation for details.")
endif()
ocv_clear_vars(PNG_LIBRARY PNG_LIBRARIES PNG_INCLUDE_DIR PNG_DEFINITIONS) ocv_clear_vars(PNG_LIBRARY PNG_LIBRARIES PNG_INCLUDE_DIR PNG_DEFINITIONS)
set(PNG_LIBRARY libpng CACHE INTERNAL "") set(PNG_LIBRARY libpng CACHE INTERNAL "")
+7
View File
@@ -46,6 +46,13 @@ if(WITH_IPP_CALLS_ENFORCED)
message("WITH_IPP_CALLS_ENFORCED=${WITH_IPP_CALLS_ENFORCED}: enforced IPP calls are enabled in IPP HAL") message("WITH_IPP_CALLS_ENFORCED=${WITH_IPP_CALLS_ENFORCED}: enforced IPP calls are enabled in IPP HAL")
endif() endif()
# Enable cv::instr tracing of IPP calls inside the HAL so they show up in the
# instrumentation trace / IPP weight. Reuses the engine exported from
# opencv_core (symbols resolved at link time as ipphal is archived into core).
if(ENABLE_INSTRUMENTATION)
target_compile_definitions(ipphal PRIVATE ENABLE_INSTRUMENTATION)
endif()
target_include_directories(ipphal PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include") target_include_directories(ipphal PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include")
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wno-suggest-override) ocv_warnings_disable(CMAKE_CXX_FLAGS -Wno-suggest-override)
+16
View File
@@ -1,6 +1,7 @@
// This file is part of OpenCV project. // This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory // It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html // of this distribution and at http://opencv.org/license.html
// Copyright (C) 2026, Intel Corporation, all rights reserved.
#ifndef __IPP_HAL_UTILS_HPP__ #ifndef __IPP_HAL_UTILS_HPP__
#define __IPP_HAL_UTILS_HPP__ #define __IPP_HAL_UTILS_HPP__
@@ -23,7 +24,22 @@
# include "ipp.h" # include "ipp.h"
#endif #endif
// IPP call instrumentation for the standalone IPP HAL.
//
// The HAL is built as a separate static library that does not include the
// internal core/private.hpp, so by default its IPP calls never appear in the
// cv::instr trace (reported IPP weight = 0%). When the parent build enables
// ENABLE_INSTRUMENTATION, the shared instrumentation.private.hpp provides the
// exact same CV_INSTRUMENT_FUN_IPP macro used by core (backed by symbols exported
// from libopencv_core, resolved at link time), so HAL IPP calls are traced
// identically to in-module ones. Otherwise the no-op passthrough is used.
#if !defined(CV_INSTRUMENT_FUN_IPP)
#if defined(ENABLE_INSTRUMENTATION)
#include "opencv2/core/utils/instrumentation.private.hpp"
#else
#define CV_INSTRUMENT_FUN_IPP(FUN, ...) ((FUN)(__VA_ARGS__)) #define CV_INSTRUMENT_FUN_IPP(FUN, ...) ((FUN)(__VA_ARGS__))
#endif // defined(ENABLE_INSTRUMENTATION)
#endif // !defined(CV_INSTRUMENT_FUN_IPP)
#define CV_HAL_CHECK_USE_IPP() if(!cv::ipp::useIPP()) return CV_HAL_ERROR_NOT_IMPLEMENTED; #define CV_HAL_CHECK_USE_IPP() if(!cv::ipp::useIPP()) return CV_HAL_ERROR_NOT_IMPLEMENTED;
+9
View File
@@ -99,9 +99,18 @@ int fast_atan_64(const double* y, const double* x, double* dst, size_t n, bool a
/* ############ split ############ */ /* ############ split ############ */
int split8u(const uchar* src, uchar** dst, int len, int cn); int split8u(const uchar* src, uchar** dst, int len, int cn);
int split16u(const ushort* src, ushort** dst, int len, int cn);
int split32s(const int* src, int** dst, int len, int cn);
int split64s(const int64* src, int64** dst, int len, int cn);
#undef cv_hal_split8u #undef cv_hal_split8u
#define cv_hal_split8u cv::rvv_hal::core::split8u #define cv_hal_split8u cv::rvv_hal::core::split8u
#undef cv_hal_split16u
#define cv_hal_split16u cv::rvv_hal::core::split16u
#undef cv_hal_split32s
#define cv_hal_split32s cv::rvv_hal::core::split32s
#undef cv_hal_split64s
#define cv_hal_split64s cv::rvv_hal::core::split64s
/* ############ sqrt ############ */ /* ############ sqrt ############ */
+21 -2
View File
@@ -30,8 +30,27 @@ static int copyToMasked_e##X##c1(const uchar *src_data, size_t src_step, const u
return CV_HAL_ERROR_OK; \ return CV_HAL_ERROR_OK; \
} }
CV_HAL_RVV_COPY_MASK_eXc1(8, 8) #define CV_HAL_RVV_COPY_MASK_MERGE_eXc1(X, data_lmul, mask_lmul) \
CV_HAL_RVV_COPY_MASK_eXc1(16, 4) static int copyToMasked_e##X##c1(const uchar *src_data, size_t src_step, const uchar *mask_data, size_t mask_step, \
uchar *dst_data, size_t dst_step, int width, int height) { \
for (; height--; mask_data += mask_step, src_data += src_step, dst_data += dst_step) { \
const uint##X##_t *src = (const uint##X##_t*)src_data; \
uint##X##_t *dst = (uint##X##_t*)dst_data; \
int vl; \
for (int i = 0; i < width; i += vl) { \
vl = __riscv_vsetvl_e##X##m##data_lmul(width - i); \
auto m = __riscv_vmsne(__riscv_vle8_v_u8m##mask_lmul(mask_data + i, vl), 0, vl); \
auto src_v = __riscv_vle##X##_v_u##X##m##data_lmul(src + i, vl); \
auto dst_v = __riscv_vle##X##_v_u##X##m##data_lmul(dst + i, vl); \
__riscv_vse##X##_v_u##X##m##data_lmul(dst + i, __riscv_vmerge(dst_v, src_v, m, vl), vl); \
} \
} \
return CV_HAL_ERROR_OK; \
}
CV_HAL_RVV_COPY_MASK_MERGE_eXc1(8, 8, 8)
CV_HAL_RVV_COPY_MASK_MERGE_eXc1(16, 8, 4)
CV_HAL_RVV_COPY_MASK_eXc1(32, 2) CV_HAL_RVV_COPY_MASK_eXc1(32, 2)
CV_HAL_RVV_COPY_MASK_eXc1(64, 1) CV_HAL_RVV_COPY_MASK_eXc1(64, 1)
+135 -98
View File
@@ -28,6 +28,12 @@
#define __riscv_vcreate_v_u16m4x2(v0, v1) OPENCV_HAL_IMPL_RVV_VCREATE_x2(u16, 4, v0, v1) #define __riscv_vcreate_v_u16m4x2(v0, v1) OPENCV_HAL_IMPL_RVV_VCREATE_x2(u16, 4, v0, v1)
#define __riscv_vcreate_v_u16m2x3(v0, v1, v2) OPENCV_HAL_IMPL_RVV_VCREATE_x3(u16, 2, v0, v1, v2) #define __riscv_vcreate_v_u16m2x3(v0, v1, v2) OPENCV_HAL_IMPL_RVV_VCREATE_x3(u16, 2, v0, v1, v2)
#define __riscv_vcreate_v_u16m2x4(v0, v1, v2, v3) OPENCV_HAL_IMPL_RVV_VCREATE_x4(u16, 2, v0, v1, v2, v3) #define __riscv_vcreate_v_u16m2x4(v0, v1, v2, v3) OPENCV_HAL_IMPL_RVV_VCREATE_x4(u16, 2, v0, v1, v2, v3)
#define __riscv_vcreate_v_i32m4x2(v0, v1) OPENCV_HAL_IMPL_RVV_VCREATE_x2(i32, 4, v0, v1)
#define __riscv_vcreate_v_i32m2x3(v0, v1, v2) OPENCV_HAL_IMPL_RVV_VCREATE_x3(i32, 2, v0, v1, v2)
#define __riscv_vcreate_v_i32m2x4(v0, v1, v2, v3) OPENCV_HAL_IMPL_RVV_VCREATE_x4(i32, 2, v0, v1, v2, v3)
#define __riscv_vcreate_v_i64m4x2(v0, v1) OPENCV_HAL_IMPL_RVV_VCREATE_x2(i64, 4, v0, v1)
#define __riscv_vcreate_v_i64m2x3(v0, v1, v2) OPENCV_HAL_IMPL_RVV_VCREATE_x3(i64, 2, v0, v1, v2)
#define __riscv_vcreate_v_i64m2x4(v0, v1, v2, v3) OPENCV_HAL_IMPL_RVV_VCREATE_x4(i64, 2, v0, v1, v2, v3)
#endif // clang < 18 #endif // clang < 18
namespace cv { namespace rvv_hal { namespace core { namespace cv { namespace rvv_hal { namespace core {
@@ -204,146 +210,177 @@ int merge16u(const ushort** src, ushort* dst, int len, int cn ) {
return CV_HAL_ERROR_OK; return CV_HAL_ERROR_OK;
} }
#if defined __GNUC__ && !defined(__clang__)
__attribute__((optimize("no-tree-vectorize")))
#endif
int merge32s(const int** src, int* dst, int len, int cn ) { int merge32s(const int** src, int* dst, int len, int cn ) {
int k = cn % 4 ? cn % 4 : 4; int vl = 0;
int i, j; if (cn == 1)
if( k == 1 )
{ {
const int* src0 = src[0]; const int* src0 = src[0];
#if defined(__clang__) for (int i = 0; i < len; i += vl)
#pragma clang loop vectorize(disable)
#endif
for( i = j = 0; i < len; i++, j += cn )
dst[j] = src0[i];
}
else if( k == 2 )
{
const int *src0 = src[0], *src1 = src[1];
i = j = 0;
#if defined(__clang__)
#pragma clang loop vectorize(disable)
#endif
for( ; i < len; i++, j += cn )
{ {
dst[j] = src0[i]; vl = __riscv_vsetvl_e32m8(len - i);
dst[j+1] = src1[i]; __riscv_vse32_v_i32m8(dst + i, __riscv_vle32_v_i32m8(src0 + i, vl), vl);
} }
} }
else if( k == 3 ) else if (cn == 2)
{
const int *src0 = src[0], *src1 = src[1];
for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e32m4(len - i);
vint32m4x2_t seg = __riscv_vcreate_v_i32m4x2(
__riscv_vle32_v_i32m4(src0 + i, vl),
__riscv_vle32_v_i32m4(src1 + i, vl)
);
__riscv_vsseg2e32_v_i32m4x2(dst + i * cn, seg, vl);
}
}
else if (cn == 3)
{ {
const int *src0 = src[0], *src1 = src[1], *src2 = src[2]; const int *src0 = src[0], *src1 = src[1], *src2 = src[2];
i = j = 0; for (int i = 0; i < len; i += vl)
#if defined(__clang__)
#pragma clang loop vectorize(disable)
#endif
for( ; i < len; i++, j += cn )
{ {
dst[j] = src0[i]; vl = __riscv_vsetvl_e32m2(len - i);
dst[j+1] = src1[i]; vint32m2x3_t seg = __riscv_vcreate_v_i32m2x3(
dst[j+2] = src2[i]; __riscv_vle32_v_i32m2(src0 + i, vl),
__riscv_vle32_v_i32m2(src1 + i, vl),
__riscv_vle32_v_i32m2(src2 + i, vl)
);
__riscv_vsseg3e32_v_i32m2x3(dst + i * cn, seg, vl);
}
}
else if (cn == 4)
{
const int *src0 = src[0], *src1 = src[1], *src2 = src[2], *src3 = src[3];
for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e32m2(len - i);
vint32m2x4_t seg = __riscv_vcreate_v_i32m2x4(
__riscv_vle32_v_i32m2(src0 + i, vl),
__riscv_vle32_v_i32m2(src1 + i, vl),
__riscv_vle32_v_i32m2(src2 + i, vl),
__riscv_vle32_v_i32m2(src3 + i, vl)
);
__riscv_vsseg4e32_v_i32m2x4(dst + i * cn, seg, vl);
} }
} }
else else
{ {
const int *src0 = src[0], *src1 = src[1], *src2 = src[2], *src3 = src[3]; int k = 0;
i = j = 0; for (; k <= cn - 4; k += 4)
#if defined(__clang__)
#pragma clang loop vectorize(disable)
#endif
for( ; i < len; i++, j += cn )
{ {
dst[j] = src0[i]; dst[j+1] = src1[i]; const int *src0 = src[k], *src1 = src[k + 1], *src2 = src[k + 2], *src3 = src[k + 3];
dst[j+2] = src2[i]; dst[j+3] = src3[i]; for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e32m2(len - i);
vint32m2x4_t seg = __riscv_vcreate_v_i32m2x4(
__riscv_vle32_v_i32m2(src0 + i, vl),
__riscv_vle32_v_i32m2(src1 + i, vl),
__riscv_vle32_v_i32m2(src2 + i, vl),
__riscv_vle32_v_i32m2(src3 + i, vl)
);
__riscv_vssseg4e32_v_i32m2x4(dst + k + i * cn, cn * sizeof(int), seg, vl);
}
} }
} for (; k < cn; ++k)
#if defined(__clang__)
#pragma clang loop vectorize(disable)
#endif
for( ; k < cn; k += 4 )
{
const int *src0 = src[k], *src1 = src[k+1], *src2 = src[k+2], *src3 = src[k+3];
for( i = 0, j = k; i < len; i++, j += cn )
{ {
dst[j] = src0[i]; dst[j+1] = src1[i]; const int* srcK = src[k];
dst[j+2] = src2[i]; dst[j+3] = src3[i]; for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e32m2(len - i);
vint32m2_t seg = __riscv_vle32_v_i32m2(srcK + i, vl);
__riscv_vsse32_v_i32m2(dst + k + i * cn, cn * sizeof(int), seg, vl);
}
} }
} }
return CV_HAL_ERROR_OK; return CV_HAL_ERROR_OK;
} }
#if defined __GNUC__ && !defined(__clang__)
__attribute__((optimize("no-tree-vectorize")))
#endif
int merge64s(const int64** src, int64* dst, int len, int cn ) { int merge64s(const int64** src, int64* dst, int len, int cn ) {
int k = cn % 4 ? cn % 4 : 4; int vl = 0;
int i, j; if (cn == 1)
if( k == 1 )
{ {
const int64* src0 = src[0]; const int64* src0 = src[0];
#if defined(__clang__) for (int i = 0; i < len; i += vl)
#pragma clang loop vectorize(disable)
#endif
for( i = j = 0; i < len; i++, j += cn )
dst[j] = src0[i];
}
else if( k == 2 )
{
const int64 *src0 = src[0], *src1 = src[1];
i = j = 0;
#if defined(__clang__)
#pragma clang loop vectorize(disable)
#endif
for( ; i < len; i++, j += cn )
{ {
dst[j] = src0[i]; vl = __riscv_vsetvl_e64m8(len - i);
dst[j+1] = src1[i]; __riscv_vse64_v_i64m8(dst + i, __riscv_vle64_v_i64m8(src0 + i, vl), vl);
} }
} }
else if( k == 3 ) else if (cn == 2)
{
const int64 *src0 = src[0], *src1 = src[1];
for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e64m4(len - i);
vint64m4x2_t seg = __riscv_vcreate_v_i64m4x2(
__riscv_vle64_v_i64m4(src0 + i, vl),
__riscv_vle64_v_i64m4(src1 + i, vl)
);
__riscv_vsseg2e64_v_i64m4x2(dst + i * cn, seg, vl);
}
}
else if (cn == 3)
{ {
const int64 *src0 = src[0], *src1 = src[1], *src2 = src[2]; const int64 *src0 = src[0], *src1 = src[1], *src2 = src[2];
i = j = 0; for (int i = 0; i < len; i += vl)
#if defined(__clang__)
#pragma clang loop vectorize(disable)
#endif
for( ; i < len; i++, j += cn )
{ {
dst[j] = src0[i]; vl = __riscv_vsetvl_e64m2(len - i);
dst[j+1] = src1[i]; vint64m2x3_t seg = __riscv_vcreate_v_i64m2x3(
dst[j+2] = src2[i]; __riscv_vle64_v_i64m2(src0 + i, vl),
__riscv_vle64_v_i64m2(src1 + i, vl),
__riscv_vle64_v_i64m2(src2 + i, vl)
);
__riscv_vsseg3e64_v_i64m2x3(dst + i * cn, seg, vl);
}
}
else if (cn == 4)
{
const int64 *src0 = src[0], *src1 = src[1], *src2 = src[2], *src3 = src[3];
for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e64m2(len - i);
vint64m2x4_t seg = __riscv_vcreate_v_i64m2x4(
__riscv_vle64_v_i64m2(src0 + i, vl),
__riscv_vle64_v_i64m2(src1 + i, vl),
__riscv_vle64_v_i64m2(src2 + i, vl),
__riscv_vle64_v_i64m2(src3 + i, vl)
);
__riscv_vsseg4e64_v_i64m2x4(dst + i * cn, seg, vl);
} }
} }
else else
{ {
const int64 *src0 = src[0], *src1 = src[1], *src2 = src[2], *src3 = src[3]; int k = 0;
i = j = 0; for (; k <= cn - 4; k += 4)
#if defined(__clang__)
#pragma clang loop vectorize(disable)
#endif
for( ; i < len; i++, j += cn )
{ {
dst[j] = src0[i]; dst[j+1] = src1[i]; const int64 *src0 = src[k], *src1 = src[k + 1], *src2 = src[k + 2], *src3 = src[k + 3];
dst[j+2] = src2[i]; dst[j+3] = src3[i]; for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e64m2(len - i);
vint64m2x4_t seg = __riscv_vcreate_v_i64m2x4(
__riscv_vle64_v_i64m2(src0 + i, vl),
__riscv_vle64_v_i64m2(src1 + i, vl),
__riscv_vle64_v_i64m2(src2 + i, vl),
__riscv_vle64_v_i64m2(src3 + i, vl)
);
__riscv_vssseg4e64_v_i64m2x4(dst + k + i * cn, cn * sizeof(int64), seg, vl);
}
} }
} for (; k < cn; ++k)
#if defined(__clang__)
#pragma clang loop vectorize(disable)
#endif
for( ; k < cn; k += 4 )
{
const int64 *src0 = src[k], *src1 = src[k+1], *src2 = src[k+2], *src3 = src[k+3];
for( i = 0, j = k; i < len; i++, j += cn )
{ {
dst[j] = src0[i]; dst[j+1] = src1[i]; const int64* srcK = src[k];
dst[j+2] = src2[i]; dst[j+3] = src3[i]; for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e64m2(len - i);
vint64m2_t seg = __riscv_vle64_v_i64m2(srcK + i, vl);
__riscv_vsse64_v_i64m2(dst + k + i * cn, cn * sizeof(int64), seg, vl);
}
} }
} }
return CV_HAL_ERROR_OK; return CV_HAL_ERROR_OK;
} }
#endif // CV_HAL_RVV_1P0_ENABLED #endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core }}} // cv::rvv_hal::core
+84 -76
View File
@@ -8,84 +8,92 @@ namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED #if CV_HAL_RVV_1P0_ENABLED
int split8u(const uchar* src, uchar** dst, int len, int cn) #define OPENCV_HAL_IMPL_RVV_SPLIT(func, T, vtype, suffix, width) \
{ int func(const T* src, T** dst, int len, int cn) \
int vl = 0; { \
if (cn == 1) int vl = 0; \
{ if (cn == 1) \
uchar* dst0 = dst[0]; { \
for (int i = 0; i < len; i += vl) T* dst0 = dst[0]; \
{ for (int i = 0; i < len; i += vl) \
vl = __riscv_vsetvl_e8m8(len - i); { \
__riscv_vse8_v_u8m8(dst0 + i, __riscv_vle8_v_u8m8(src + i, vl), vl); vl = __riscv_vsetvl_e##width##m8(len - i); \
} __riscv_vse##width##_v_##suffix##m8(dst0 + i, __riscv_vle##width##_v_##suffix##m8(src + i, vl), vl); \
} } \
else if (cn == 2) } \
{ else if (cn == 2) \
uchar *dst0 = dst[0], *dst1 = dst[1]; { \
for (int i = 0; i < len; i += vl) T *dst0 = dst[0], *dst1 = dst[1]; \
{ for (int i = 0; i < len; i += vl) \
vl = __riscv_vsetvl_e8m4(len - i); { \
vuint8m4x2_t seg = __riscv_vlseg2e8_v_u8m4x2(src + i * cn, vl); vl = __riscv_vsetvl_e##width##m4(len - i); \
__riscv_vse8_v_u8m4(dst0 + i, __riscv_vget_v_u8m4x2_u8m4(seg, 0), vl); v##vtype##m4x2_t seg = __riscv_vlseg2e##width##_v_##suffix##m4x2(src + i * cn, vl); \
__riscv_vse8_v_u8m4(dst1 + i, __riscv_vget_v_u8m4x2_u8m4(seg, 1), vl); __riscv_vse##width##_v_##suffix##m4(dst0 + i, __riscv_vget_v_##suffix##m4x2_##suffix##m4(seg, 0), vl); \
} __riscv_vse##width##_v_##suffix##m4(dst1 + i, __riscv_vget_v_##suffix##m4x2_##suffix##m4(seg, 1), vl); \
} } \
else if (cn == 3) } \
{ else if (cn == 3) \
uchar *dst0 = dst[0], *dst1 = dst[1], *dst2 = dst[2]; { \
for (int i = 0; i < len; i += vl) T *dst0 = dst[0], *dst1 = dst[1], *dst2 = dst[2]; \
{ for (int i = 0; i < len; i += vl) \
vl = __riscv_vsetvl_e8m2(len - i); { \
vuint8m2x3_t seg = __riscv_vlseg3e8_v_u8m2x3(src + i * cn, vl); vl = __riscv_vsetvl_e##width##m2(len - i); \
__riscv_vse8_v_u8m2(dst0 + i, __riscv_vget_v_u8m2x3_u8m2(seg, 0), vl); v##vtype##m2x3_t seg = __riscv_vlseg3e##width##_v_##suffix##m2x3(src + i * cn, vl); \
__riscv_vse8_v_u8m2(dst1 + i, __riscv_vget_v_u8m2x3_u8m2(seg, 1), vl); __riscv_vse##width##_v_##suffix##m2(dst0 + i, __riscv_vget_v_##suffix##m2x3_##suffix##m2(seg, 0), vl); \
__riscv_vse8_v_u8m2(dst2 + i, __riscv_vget_v_u8m2x3_u8m2(seg, 2), vl); __riscv_vse##width##_v_##suffix##m2(dst1 + i, __riscv_vget_v_##suffix##m2x3_##suffix##m2(seg, 1), vl); \
} __riscv_vse##width##_v_##suffix##m2(dst2 + i, __riscv_vget_v_##suffix##m2x3_##suffix##m2(seg, 2), vl); \
} } \
else if (cn == 4) } \
{ else if (cn == 4) \
uchar *dst0 = dst[0], *dst1 = dst[1], *dst2 = dst[2], *dst3 = dst[3]; { \
for (int i = 0; i < len; i += vl) T *dst0 = dst[0], *dst1 = dst[1], *dst2 = dst[2], *dst3 = dst[3]; \
{ for (int i = 0; i < len; i += vl) \
vl = __riscv_vsetvl_e8m2(len - i); { \
vuint8m2x4_t seg = __riscv_vlseg4e8_v_u8m2x4(src + i * cn, vl); vl = __riscv_vsetvl_e##width##m2(len - i); \
__riscv_vse8_v_u8m2(dst0 + i, __riscv_vget_v_u8m2x4_u8m2(seg, 0), vl); v##vtype##m2x4_t seg = __riscv_vlseg4e##width##_v_##suffix##m2x4(src + i * cn, vl); \
__riscv_vse8_v_u8m2(dst1 + i, __riscv_vget_v_u8m2x4_u8m2(seg, 1), vl); __riscv_vse##width##_v_##suffix##m2(dst0 + i, __riscv_vget_v_##suffix##m2x4_##suffix##m2(seg, 0), vl); \
__riscv_vse8_v_u8m2(dst2 + i, __riscv_vget_v_u8m2x4_u8m2(seg, 2), vl); __riscv_vse##width##_v_##suffix##m2(dst1 + i, __riscv_vget_v_##suffix##m2x4_##suffix##m2(seg, 1), vl); \
__riscv_vse8_v_u8m2(dst3 + i, __riscv_vget_v_u8m2x4_u8m2(seg, 3), vl); __riscv_vse##width##_v_##suffix##m2(dst2 + i, __riscv_vget_v_##suffix##m2x4_##suffix##m2(seg, 2), vl); \
} __riscv_vse##width##_v_##suffix##m2(dst3 + i, __riscv_vget_v_##suffix##m2x4_##suffix##m2(seg, 3), vl); \
} } \
else } \
{ else \
int k = 0; { \
for (; k <= cn - 4; k += 4) int k = 0; \
{ for (; k <= cn - 4; k += 4) \
uchar *dst0 = dst[k], *dst1 = dst[k + 1], *dst2 = dst[k + 2], *dst3 = dst[k + 3]; { \
for (int i = 0; i < len; i += vl) T *dst0 = dst[k], *dst1 = dst[k + 1], *dst2 = dst[k + 2], *dst3 = dst[k + 3]; \
{ for (int i = 0; i < len; i += vl) \
vl = __riscv_vsetvl_e8m2(len - i); { \
vuint8m2x4_t seg = __riscv_vlsseg4e8_v_u8m2x4(src + k + i * cn, cn, vl); vl = __riscv_vsetvl_e##width##m2(len - i); \
__riscv_vse8_v_u8m2(dst0 + i, __riscv_vget_v_u8m2x4_u8m2(seg, 0), vl); v##vtype##m2x4_t seg = __riscv_vlsseg4e##width##_v_##suffix##m2x4(src + k + i * cn, cn * sizeof(T), vl); \
__riscv_vse8_v_u8m2(dst1 + i, __riscv_vget_v_u8m2x4_u8m2(seg, 1), vl); __riscv_vse##width##_v_##suffix##m2(dst0 + i, __riscv_vget_v_##suffix##m2x4_##suffix##m2(seg, 0), vl); \
__riscv_vse8_v_u8m2(dst2 + i, __riscv_vget_v_u8m2x4_u8m2(seg, 2), vl); __riscv_vse##width##_v_##suffix##m2(dst1 + i, __riscv_vget_v_##suffix##m2x4_##suffix##m2(seg, 1), vl); \
__riscv_vse8_v_u8m2(dst3 + i, __riscv_vget_v_u8m2x4_u8m2(seg, 3), vl); __riscv_vse##width##_v_##suffix##m2(dst2 + i, __riscv_vget_v_##suffix##m2x4_##suffix##m2(seg, 2), vl); \
} __riscv_vse##width##_v_##suffix##m2(dst3 + i, __riscv_vget_v_##suffix##m2x4_##suffix##m2(seg, 3), vl); \
} } \
for (; k < cn; ++k) } \
{ for (; k < cn; ++k) \
uchar* dstK = dst[k]; { \
for (int i = 0; i < len; i += vl) T* dstK = dst[k]; \
{ for (int i = 0; i < len; i += vl) \
vl = __riscv_vsetvl_e8m2(len - i); { \
vuint8m2_t seg = __riscv_vlse8_v_u8m2(src + k + i * cn, cn, vl); vl = __riscv_vsetvl_e##width##m2(len - i); \
__riscv_vse8_v_u8m2(dstK + i, seg, vl); v##vtype##m2_t seg = __riscv_vlse##width##_v_##suffix##m2(src + k + i * cn, cn * sizeof(T), vl); \
} __riscv_vse##width##_v_##suffix##m2(dstK + i, seg, vl); \
} } \
} } \
return CV_HAL_ERROR_OK; } \
return CV_HAL_ERROR_OK; \
} }
OPENCV_HAL_IMPL_RVV_SPLIT(split8u, uchar, uint8, u8, 8)
OPENCV_HAL_IMPL_RVV_SPLIT(split16u, ushort, uint16, u16, 16)
OPENCV_HAL_IMPL_RVV_SPLIT(split32s, int, int32, i32, 32)
OPENCV_HAL_IMPL_RVV_SPLIT(split64s, int64, int64, i64, 64)
#undef OPENCV_HAL_IMPL_RVV_SPLIT
#endif // CV_HAL_RVV_1P0_ENABLED #endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core }}} // cv::rvv_hal::core
+2 -55
View File
@@ -690,23 +690,13 @@ public:
TLSData<InstrTLSStruct> tlsStruct; TLSData<InstrTLSStruct> tlsStruct;
}; };
class CV_EXPORTS IntrumentationRegion
{
public:
IntrumentationRegion(const char* funName, const char* fileName, int lineNum, void *retAddress, bool alwaysExpand, TYPE instrType = TYPE_GENERAL, IMPL implType = IMPL_PLAIN);
~IntrumentationRegion();
private:
bool m_disabled; // region status
uint64 m_regionTicks;
};
CV_EXPORTS InstrStruct& getInstrumentStruct(); CV_EXPORTS InstrStruct& getInstrumentStruct();
InstrTLSStruct& getInstrumentTLSStruct(); InstrTLSStruct& getInstrumentTLSStruct();
CV_EXPORTS InstrNode* getCurrentNode();
} }
} }
#include "opencv2/core/utils/instrumentation.private.hpp"
#ifdef _WIN32 #ifdef _WIN32
#define CV_INSTRUMENT_GET_RETURN_ADDRESS _ReturnAddress() #define CV_INSTRUMENT_GET_RETURN_ADDRESS _ReturnAddress()
#else #else
@@ -718,45 +708,6 @@ CV_EXPORTS InstrNode* getCurrentNode();
#define CV_INSTRUMENT_REGION_CUSTOM_META(NAME, ALWAYS_EXPAND, TYPE, IMPL)\ #define CV_INSTRUMENT_REGION_CUSTOM_META(NAME, ALWAYS_EXPAND, TYPE, IMPL)\
void *CVAUX_CONCAT(__curr_address__, __LINE__) = [&]() {return CV_INSTRUMENT_GET_RETURN_ADDRESS;}();\ void *CVAUX_CONCAT(__curr_address__, __LINE__) = [&]() {return CV_INSTRUMENT_GET_RETURN_ADDRESS;}();\
::cv::instr::IntrumentationRegion CVAUX_CONCAT(__instr_region__, __LINE__) (NAME, __FILE__, __LINE__, CVAUX_CONCAT(__curr_address__, __LINE__), false, ::cv::instr::TYPE_GENERAL, ::cv::instr::IMPL_PLAIN); ::cv::instr::IntrumentationRegion CVAUX_CONCAT(__instr_region__, __LINE__) (NAME, __FILE__, __LINE__, CVAUX_CONCAT(__curr_address__, __LINE__), false, ::cv::instr::TYPE_GENERAL, ::cv::instr::IMPL_PLAIN);
// Instrument functions with non-void return type
#define CV_INSTRUMENT_FUN_RT_META(TYPE, IMPL, ERROR_COND, FUN, ...) ([&]()\
{\
if(::cv::instr::useInstrumentation()){\
::cv::instr::IntrumentationRegion __instr__(#FUN, __FILE__, __LINE__, NULL, false, TYPE, IMPL);\
try{\
auto instrStatus = ((FUN)(__VA_ARGS__));\
if(ERROR_COND){\
::cv::instr::getCurrentNode()->m_payload.m_funError = true;\
CV_INSTRUMENT_MARK_META(IMPL, #FUN " - BadExit");\
}\
return instrStatus;\
}catch(...){\
::cv::instr::getCurrentNode()->m_payload.m_funError = true;\
CV_INSTRUMENT_MARK_META(IMPL, #FUN " - BadExit");\
throw;\
}\
}else{\
return ((FUN)(__VA_ARGS__));\
}\
}())
// Instrument functions with void return type
#define CV_INSTRUMENT_FUN_RV_META(TYPE, IMPL, FUN, ...) ([&]()\
{\
if(::cv::instr::useInstrumentation()){\
::cv::instr::IntrumentationRegion __instr__(#FUN, __FILE__, __LINE__, NULL, false, TYPE, IMPL);\
try{\
(FUN)(__VA_ARGS__);\
}catch(...){\
::cv::instr::getCurrentNode()->m_payload.m_funError = true;\
CV_INSTRUMENT_MARK_META(IMPL, #FUN "- BadExit");\
throw;\
}\
}else{\
(FUN)(__VA_ARGS__);\
}\
}())
// Instrumentation information marker
#define CV_INSTRUMENT_MARK_META(IMPL, NAME, ...) {::cv::instr::IntrumentationRegion __instr_mark__(NAME, __FILE__, __LINE__, NULL, false, ::cv::instr::TYPE_MARKER, IMPL);}
///// General instrumentation ///// General instrumentation
// General OpenCV region instrumentation macro // General OpenCV region instrumentation macro
@@ -769,10 +720,6 @@ CV_EXPORTS InstrNode* getCurrentNode();
///// IPP instrumentation ///// IPP instrumentation
// Wrapper region instrumentation macro // Wrapper region instrumentation macro
#define CV_INSTRUMENT_REGION_IPP(); CV_INSTRUMENT_REGION_META(__FUNCTION__, false, ::cv::instr::TYPE_WRAPPER, ::cv::instr::IMPL_IPP) #define CV_INSTRUMENT_REGION_IPP(); CV_INSTRUMENT_REGION_META(__FUNCTION__, false, ::cv::instr::TYPE_WRAPPER, ::cv::instr::IMPL_IPP)
// Function instrumentation macro
#define CV_INSTRUMENT_FUN_IPP(FUN, ...) CV_INSTRUMENT_FUN_RT_META(::cv::instr::TYPE_FUN, ::cv::instr::IMPL_IPP, instrStatus < 0, FUN, __VA_ARGS__)
// Diagnostic markers
#define CV_INSTRUMENT_MARK_IPP(NAME) CV_INSTRUMENT_MARK_META(::cv::instr::IMPL_IPP, NAME)
///// OpenCL instrumentation ///// OpenCL instrumentation
// Wrapper region instrumentation macro // Wrapper region instrumentation macro
@@ -0,0 +1,88 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
// Copyright (C) 2026, Intel Corporation, all rights reserved.
#ifndef OPENCV_CORE_UTILS_INSTRUMENTATION_PRIVATE_HPP
#define OPENCV_CORE_UTILS_INSTRUMENTATION_PRIVATE_HPP
#include "opencv2/core/utils/instrumentation.hpp"
// Region-based function-instrumentation primitives.
//
// Only meaningful when the build was configured with ENABLE_INSTRUMENTATION;
// otherwise this header contributes nothing and each includer provides its own
// no-op fallbacks. The IntrumentationRegion / getCurrentNode() definitions are
// compiled into and exported (CV_EXPORTS) from the core library, so the HAL only
// needs these declarations and resolves the symbols at link time.
#ifdef ENABLE_INSTRUMENTATION
namespace cv { namespace instr {
// Scoped region: records one instrumentation node on construction and closes it
// on destruction. Defined in modules/core/src/system.cpp.
class CV_EXPORTS IntrumentationRegion
{
public:
IntrumentationRegion(const char* funName, const char* fileName, int lineNum, void *retAddress,
bool alwaysExpand, TYPE instrType = TYPE_GENERAL, IMPL implType = IMPL_PLAIN);
~IntrumentationRegion();
private:
bool m_disabled; // region status
uint64 m_regionTicks;
};
CV_EXPORTS InstrNode* getCurrentNode();
}} // namespace cv::instr
// Instrumentation information marker
#define CV_INSTRUMENT_MARK_META(IMPL, NAME, ...) {::cv::instr::IntrumentationRegion __instr_mark__(NAME, __FILE__, __LINE__, NULL, false, ::cv::instr::TYPE_MARKER, IMPL);}
// Instrument functions with non-void return type
#define CV_INSTRUMENT_FUN_RT_META(TYPE, IMPL, ERROR_COND, FUN, ...) ([&]() \
{ \
if(::cv::instr::useInstrumentation()){ \
::cv::instr::IntrumentationRegion __instr__(#FUN, __FILE__, __LINE__, NULL, false, TYPE, IMPL); \
try{ \
auto instrStatus = ((FUN)(__VA_ARGS__)); \
if(ERROR_COND){ \
::cv::instr::getCurrentNode()->m_payload.m_funError = true; \
CV_INSTRUMENT_MARK_META(IMPL, #FUN " - BadExit"); \
} \
return instrStatus; \
}catch(...){ \
::cv::instr::getCurrentNode()->m_payload.m_funError = true; \
CV_INSTRUMENT_MARK_META(IMPL, #FUN " - BadExit"); \
throw; \
} \
}else{ \
return ((FUN)(__VA_ARGS__)); \
} \
}())
// Instrument functions with void return type
#define CV_INSTRUMENT_FUN_RV_META(TYPE, IMPL, FUN, ...) ([&]() \
{ \
if(::cv::instr::useInstrumentation()){ \
::cv::instr::IntrumentationRegion __instr__(#FUN, __FILE__, __LINE__, NULL, false, TYPE, IMPL); \
try{ \
(FUN)(__VA_ARGS__); \
}catch(...){ \
::cv::instr::getCurrentNode()->m_payload.m_funError = true; \
CV_INSTRUMENT_MARK_META(IMPL, #FUN " - BadExit"); \
throw; \
} \
}else{ \
(FUN)(__VA_ARGS__); \
} \
}())
// IPP function instrumentation macros
#define CV_INSTRUMENT_FUN_IPP(FUN, ...) CV_INSTRUMENT_FUN_RT_META(::cv::instr::TYPE_FUN, ::cv::instr::IMPL_IPP, instrStatus < 0, FUN, __VA_ARGS__)
#define CV_INSTRUMENT_MARK_IPP(NAME) CV_INSTRUMENT_MARK_META(::cv::instr::IMPL_IPP, NAME)
#endif // ENABLE_INSTRUMENTATION
#endif // OPENCV_CORE_UTILS_INSTRUMENTATION_PRIVATE_HPP
@@ -6,9 +6,9 @@
#define OPENCV_VERSION_HPP #define OPENCV_VERSION_HPP
#define CV_VERSION_MAJOR 4 #define CV_VERSION_MAJOR 4
#define CV_VERSION_MINOR 14 #define CV_VERSION_MINOR 15
#define CV_VERSION_REVISION 0 #define CV_VERSION_REVISION 0
#define CV_VERSION_STATUS "" #define CV_VERSION_STATUS "-dev"
#define CVAUX_STR_EXP(__A) #__A #define CVAUX_STR_EXP(__A) #__A
#define CVAUX_STR(__A) CVAUX_STR_EXP(__A) #define CVAUX_STR(__A) CVAUX_STR_EXP(__A)
+24
View File
@@ -30,4 +30,28 @@ PERF_TEST_P( Size_Depth_Channels, split,
SANITY_CHECK(mv, 2e-5); SANITY_CHECK(mv, 2e-5);
} }
typedef tuple<Size, int> Size_Channel_t;
typedef perf::TestBaseWithParam<Size_Channel_t> Size_Channel;
PERF_TEST_P( Size_Channel, extractChannel,
testing::Combine
(
testing::Values(TYPICAL_MAT_SIZES),
testing::Values(0, 1)
)
)
{
Size sz = get<0>(GetParam());
int channel = get<1>(GetParam());
Mat src(sz, CV_8UC2);
Mat dst(sz, CV_8UC1);
randu(src, 0, 255);
int runs = (sz.width <= 640) ? 8 : 1;
TEST_CYCLE_MULTIRUN(runs) extractChannel(src, dst, channel);
SANITY_CHECK(dst);
}
} // namespace } // namespace
+38
View File
@@ -418,6 +418,35 @@ static bool ipp_insertChannel(const Mat &src, Mat &dst, int channel)
} }
#endif #endif
namespace cv
{
template<int channel> static void extractChannel8uC2_(const Mat& src, Mat& dst)
{
for (int row = 0; row < src.rows; ++row)
{
const uchar* source = src.ptr<uchar>(row);
uchar* destination = dst.ptr<uchar>(row);
int column = 0;
#if (CV_SIMD || CV_SIMD_SCALABLE)
const int lanes = VTraits<v_uint8>::vlanes();
for (; column <= src.cols - lanes; column += lanes)
{
v_uint8 channel0, channel1;
v_load_deinterleave(source + column * 2, channel0, channel1);
v_store(destination + column, channel == 0 ? channel0 : channel1);
}
#endif
for (; column < src.cols; ++column)
destination[column] = source[column * 2 + channel];
}
#if (CV_SIMD || CV_SIMD_SCALABLE)
vx_cleanup();
#endif
}
}
void cv::extractChannel(InputArray _src, OutputArray _dst, int coi) void cv::extractChannel(InputArray _src, OutputArray _dst, int coi)
{ {
CV_INSTRUMENT_REGION(); CV_INSTRUMENT_REGION();
@@ -443,6 +472,15 @@ void cv::extractChannel(InputArray _src, OutputArray _dst, int coi)
CV_IPP_RUN_FAST(ipp_extractChannel(src, dst, coi)) CV_IPP_RUN_FAST(ipp_extractChannel(src, dst, coi))
if (src.dims <= 2 && src.type() == CV_8UC2)
{
if (coi == 0)
extractChannel8uC2_<0>(src, dst);
else
extractChannel8uC2_<1>(src, dst);
return;
}
mixChannels(&src, 1, &dst, 1, ch, 1); mixChannels(&src, 1, &dst, 1, ch, 1);
} }
+27
View File
@@ -1602,6 +1602,33 @@ TEST(Core_Arithm, scalar_handling_19599) // https://github.com/opencv/opencv/is
EXPECT_EQ(1, c.rows); EXPECT_EQ(1, c.rows);
} }
TEST(Core_ExtractChannel, twoChannel8uSubmatrix)
{
Mat sourceStorage(5, 37, CV_8UC2);
randu(sourceStorage, 0, 256);
Mat source = sourceStorage(Rect(3, 1, 31, 3));
ASSERT_FALSE(source.isContinuous());
for (int channel = 0; channel < 2; ++channel)
{
Mat destinationStorage(5, 37, CV_8UC1, Scalar::all(0));
Mat destination = destinationStorage(Rect(3, 1, source.cols, source.rows));
Mat expected(source.size(), CV_8UC1);
ASSERT_FALSE(destination.isContinuous());
for (int row = 0; row < source.rows; ++row)
{
const uchar* sourceRow = source.ptr<uchar>(row);
uchar* expectedRow = expected.ptr<uchar>(row);
for (int column = 0; column < source.cols; ++column)
expectedRow[column] = sourceRow[column * 2 + channel];
}
extractChannel(source, destination, channel);
EXPECT_EQ(0, cvtest::norm(expected, destination, NORM_INF));
}
}
// https://github.com/opencv/opencv/issues/24163 // https://github.com/opencv/opencv/issues/24163
typedef tuple<perf::MatDepth,int,int,int> Arith_Regression24163Param; typedef tuple<perf::MatDepth,int,int,int> Arith_Regression24163Param;
typedef testing::TestWithParam<Arith_Regression24163Param> Core_Arith_Regression24163; typedef testing::TestWithParam<Arith_Regression24163Param> Core_Arith_Regression24163;
+6 -6
View File
@@ -169,13 +169,13 @@ void icvCvt_Gray2BGR_16u_C1C3R( const ushort* gray, int gray_step,
ushort* bgr, int bgr_step, Size size ) ushort* bgr, int bgr_step, Size size )
{ {
int i; int i;
for( ; size.height--; gray += gray_step/sizeof(gray[0]) ) for( ; size.height--; gray += gray_step/(int)sizeof(gray[0]) )
{ {
for( i = 0; i < size.width; i++, bgr += 3 ) for( i = 0; i < size.width; i++, bgr += 3 )
{ {
bgr[0] = bgr[1] = bgr[2] = gray[i]; bgr[0] = bgr[1] = bgr[2] = gray[i];
} }
bgr += bgr_step/sizeof(bgr[0]) - size.width*3; bgr += bgr_step/(int)sizeof(bgr[0]) - size.width*3;
} }
} }
@@ -214,8 +214,8 @@ void icvCvt_BGRA2BGR_16u_C4C3R( const ushort* bgra, int bgra_step,
bgr[0] = t0; bgr[1] = t1; bgr[0] = t0; bgr[1] = t1;
t0 = bgra[swap_rb^2]; bgr[2] = t0; t0 = bgra[swap_rb^2]; bgr[2] = t0;
} }
bgr += bgr_step/sizeof(bgr[0]) - size.width*3; bgr += bgr_step/(int)sizeof(bgr[0]) - size.width*3;
bgra += bgra_step/sizeof(bgra[0]) - size.width*4; bgra += bgra_step/(int)sizeof(bgra[0]) - size.width*4;
} }
} }
@@ -252,8 +252,8 @@ void icvCvt_BGRA2RGBA_16u_C4R( const ushort* bgra, int bgra_step,
rgba[0] = t2; rgba[1] = t1; rgba[0] = t2; rgba[1] = t1;
rgba[2] = t0; rgba[3] = t3; rgba[2] = t0; rgba[3] = t3;
} }
bgra += bgra_step/sizeof(bgra[0]) - size.width*4; bgra += bgra_step/(int)sizeof(bgra[0]) - size.width*4;
rgba += rgba_step/sizeof(rgba[0]) - size.width*4; rgba += rgba_step/(int)sizeof(rgba[0]) - size.width*4;
} }
} }
+22
View File
@@ -689,6 +689,28 @@ TEST(Imgcodecs_Tiff, readWrite_unsigned)
EXPECT_EQ(0, remove(filenameOutput.c_str())); EXPECT_EQ(0, remove(filenameOutput.c_str()));
} }
// See https://github.com/opencv/opencv/issues/29615
// Decoding a 16-bit 4-channel TIFF used to form an out of range pointer in
// icvCvt_BGRA2RGBA_16u_C4R because the byte step was divided by an unsigned
// sizeof and then had size.width*4 subtracted, which wraps around for a zero
// step. This just checks that a 16UC4 TIFF round-trips correctly; the value is
// mainly that the sanitizer builds no longer report the pointer overflow.
TEST(Imgcodecs_Tiff, regression_29615_16UC4)
{
Mat img(4, 3, CV_16UC4);
randu(img, Scalar::all(0), Scalar::all(65535));
vector<uchar> buf;
ASSERT_NO_THROW(ASSERT_TRUE(imencode(".tiff", img, buf)));
Mat decoded;
ASSERT_NO_THROW(decoded = imdecode(buf, IMREAD_UNCHANGED));
ASSERT_FALSE(decoded.empty());
ASSERT_EQ(CV_16UC4, decoded.type());
ASSERT_EQ(img.size(), decoded.size());
EXPECT_EQ(0, cvtest::norm(img, decoded, NORM_INF));
}
TEST(Imgcodecs_Tiff, readWrite_32FC1) TEST(Imgcodecs_Tiff, readWrite_32FC1)
{ {
const string root = cvtest::TS::ptr()->get_data_path(); const string root = cvtest::TS::ptr()->get_data_path();
+7 -6
View File
@@ -437,8 +437,9 @@ __kernel void remap_2_32FC1(__global const uchar * srcptr, int src_step, int src
#if defined BORDER_CONSTANT #if defined BORDER_CONSTANT
float xf = map1[0], yf = map2[0]; float xf = map1[0], yf = map2[0];
int sx = (convert_int_sat_rtz(mad(xf, (float)INTER_TAB_SIZE, 0.5f)) >> INTER_BITS); // Coordinates can be negative, so truncation toward zero gives incorrect indices.
int sy = (convert_int_sat_rtz(mad(yf, (float)INTER_TAB_SIZE, 0.5f)) >> INTER_BITS); int sx = (convert_int_sat_rte(xf * (float)INTER_TAB_SIZE) >> INTER_BITS);
int sy = (convert_int_sat_rte(yf * (float)INTER_TAB_SIZE) >> INTER_BITS);
#if WARP_RELATIVE #if WARP_RELATIVE
sx += x; sx += x;
sy += y; sy += y;
@@ -464,7 +465,7 @@ __kernel void remap_2_32FC1(__global const uchar * srcptr, int src_step, int src
#else #else
#pragma unroll #pragma unroll
for (int xp = 0; xp < 2; ++xp) for (int xp = 0; xp < 2; ++xp)
xsum = fma(CONVERT_TO_WT(loadpix(srcptr + mad24(xp, TSIZE, src_index))), coeffs_x[xp], xsum); xsum = fma(CONVERT_TO_WT(loadpix(srcptr + mad24(xp, TSIZE, src_index))), (WT)(coeffs_x[xp]), xsum);
#endif #endif
} }
else else
@@ -472,12 +473,12 @@ __kernel void remap_2_32FC1(__global const uchar * srcptr, int src_step, int src
#pragma unroll #pragma unroll
for (int xp = 0; xp < 2; ++xp) for (int xp = 0; xp < 2; ++xp)
xsum = fma(sx + xp >= 0 && sx + xp < src_cols ? xsum = fma(sx + xp >= 0 && sx + xp < src_cols ?
CONVERT_TO_WT(loadpix(srcptr + mad24(xp, TSIZE, src_index))) : scalar, coeffs_x[xp], xsum); CONVERT_TO_WT(loadpix(srcptr + mad24(xp, TSIZE, src_index))) : scalar, (WT)(coeffs_x[xp]), xsum);
} }
sum = fma(xsum, coeffs_y[yp], sum); sum = fma(xsum, (WT)(coeffs_y[yp]), sum);
} }
else else
sum = fma(scalar, coeffs_y[yp], sum); sum = fma(scalar, (WT)(coeffs_y[yp]), sum);
} }
storepix(CONVERT_TO_T(sum), dst); storepix(CONVERT_TO_T(sum), dst);
+277
View File
@@ -52,8 +52,12 @@
//M*/ //M*/
#include "../test_precomp.hpp" #include "../test_precomp.hpp"
#include "opencv2/core/types.hpp"
#include "opencv2/ts/ocl_test.hpp" #include "opencv2/ts/ocl_test.hpp"
#include <cmath>
#include <limits>
#ifdef HAVE_OPENCL #ifdef HAVE_OPENCL
namespace opencv_test { namespace opencv_test {
@@ -458,6 +462,279 @@ OCL_TEST_P(Remap_INTER_LINEAR, Mat)
} }
} }
template <typename T>
class RemapBorderConstant : public ::testing::Test
{
public:
RemapBorderConstant()
{
constexpr float k1 = -0.08f;
constexpr float coordinate_offset = -0.03f;
undistortedCanvas = calculateUndistortedCanvas(source_size, k1);
mapx.create(undistortedCanvas.size());
mapy.create(undistortedCanvas.size());
for (int y = 0; y < undistortedCanvas.height; ++y)
{
for (int x = 0; x < undistortedCanvas.width; ++x)
{
const Point2f undistorted(undistortedCanvas.tl() + cv::Point2i(x, y));
const Point2f distorted = barrelDistort(undistorted, source_size,
k1);
mapx.at<float>(y, x) = x == 0 ? coordinate_offset : distorted.x;
mapy.at<float>(y, x) = y == 0 ? coordinate_offset : distorted.y;
}
}
}
protected:
void runTensorProductTest()
{
const Mat_<T> source = createTensorProductImage(source_size);
runTest(createBarrelDistortedImage(source, barrel_coefficient));
}
void runCheckerboardTest()
{
const Mat_<T> source = createCheckerboardImage(source_size);
runTest(createBarrelDistortedImage(source, barrel_coefficient));
}
private:
static const Size source_size;
static constexpr float barrel_coefficient = -0.08f;
void runTest(const Mat_<T>& src)
{
constexpr float border_value = 2.0f;
constexpr float epsilon = 0.02f;
const Mat_<T> expected = remapReference(src, mapx, mapy,
border_value);
Mat_<T> cpuResult;
OCL_OFF(cv::remap(src, cpuResult, mapx, mapy, INTER_LINEAR,
BORDER_CONSTANT, Scalar::all(border_value)));
UMat usrc, umapx, umapy, uResult;
OCL_ON(src.copyTo(usrc));
OCL_ON(mapx.copyTo(umapx));
OCL_ON(mapy.copyTo(umapy));
OCL_ON(cv::remap(usrc, uResult, umapx, umapy, INTER_LINEAR,
BORDER_CONSTANT, Scalar::all(border_value)));
Mat_<T> oclResult;
uResult.copyTo(oclResult);
EXPECT_MAT_NEAR(expected, cpuResult, epsilon);
EXPECT_MAT_NEAR(expected, oclResult, epsilon);
EXPECT_MAT_NEAR(cpuResult, oclResult, epsilon);
}
static Mat_<T> createTensorProductImage(const Size& image_size)
{
constexpr float first_coordinate = 0.0f;
constexpr float last_coordinate = 1.0f;
Mat_<T> image(image_size);
for (int y = 0; y < image.rows; ++y)
{
const T yValue = first_coordinate +
static_cast<T>(y) * (last_coordinate - first_coordinate) /
static_cast<T>(image.rows - 1);
for (int x = 0; x < image.cols; ++x)
{
const T xValue = first_coordinate +
static_cast<T>(x) * (last_coordinate - first_coordinate) /
static_cast<T>(image.cols - 1);
image.template at<T>(y, x) = xValue * yValue;
}
}
return image;
}
static Mat_<T> createCheckerboardImage(const Size& image_size)
{
constexpr int checkerboard_period = 2;
constexpr float first_coordinate = 0.0f;
constexpr float last_coordinate = 1.0f;
Mat_<T> image(image_size);
for (int y = 0; y < image.rows; ++y)
{
for (int x = 0; x < image.cols; ++x)
{
image.template at<T>(y, x) = (x + y) % checkerboard_period == 0 ?
first_coordinate : last_coordinate;
}
}
return image;
}
static Mat_<T> remapReference(const Mat_<T>& src, const Mat1f& mapx,
const Mat1f& mapy, T borderValue)
{
CV_Assert(src.type() == DataType<T>::type);
CV_Assert(mapx.size() == mapy.size());
Mat_<T> dst(mapx.size());
for (int y = 0; y < dst.rows; ++y)
{
for (int x = 0; x < dst.cols; ++x)
{
const float fx = mapx.at<float>(y, x);
const float fy = mapy.at<float>(y, x);
const int scaledX = static_cast<int>(std::floor(fx * INTER_TAB_SIZE + 0.5f));
const int scaledY = static_cast<int>(std::floor(fy * INTER_TAB_SIZE + 0.5f));
const int sx = scaledX >> INTER_BITS;
const int sy = scaledY >> INTER_BITS;
const T wx = static_cast<T>(scaledX & (INTER_TAB_SIZE - 1)) /
static_cast<T>(INTER_TAB_SIZE);
const T wy = static_cast<T>(scaledY & (INTER_TAB_SIZE - 1)) /
static_cast<T>(INTER_TAB_SIZE);
T value = 0;
for (int yp = 0; yp < 2; ++yp)
{
for (int xp = 0; xp < 2; ++xp)
{
const int sourceX = sx + xp;
const int sourceY = sy + yp;
const bool inBounds = sourceX >= 0 && sourceX < src.cols &&
sourceY >= 0 && sourceY < src.rows;
const T sourceValue = inBounds ? src.template at<T>(sourceY, sourceX) : borderValue;
const T xWeight = xp == 0 ? 1 - wx : wx;
const T yWeight = yp == 0 ? 1 - wy : wy;
value += sourceValue * xWeight * yWeight;
}
}
dst.template at<T>(y, x) = value;
}
}
return dst;
}
static Point2f barrelDistort(const Point2f& point, const Size& imageSize, float k1)
{
const Point2f center = cv::Point2i(imageSize - cv::Size(1, 1)) / 2.0f;
const float scale = std::max(center.x, center.y);
const Point2f normalized = (point - center) / scale;
const float radiusSquared = normalized.dot(normalized);
const float factor = 1.0f + k1 * radiusSquared;
return center + normalized * scale * factor;
}
static Point2f barrelUndistort(const Point2f& point, const Size& imageSize, float k1)
{
const Point2f center = cv::Point2i(imageSize - cv::Size(1, 1)) / 2.0f;
const float scale = std::max(center.x, center.y);
const Point2f normalized = (point - center) / scale;
const float distortedRadius = std::hypot(normalized.x, normalized.y);
if (std::fpclassify(distortedRadius) == FP_ZERO)
return point;
float undistortedRadius = distortedRadius;
constexpr int inverse_iterations = 8;
for (int i = 0; i < inverse_iterations; ++i)
{
const float radiusSquared = undistortedRadius * undistortedRadius;
const float function = undistortedRadius * (1.0f + k1 * radiusSquared) -
distortedRadius;
const float derivative = 1.0f + 3.0f * k1 * radiusSquared;
undistortedRadius -= function / derivative;
}
const float radialScale = undistortedRadius / distortedRadius;
return center + normalized * radialScale * scale;
}
static Rect calculateUndistortedCanvas(const Size& sourceSize, float k1)
{
const Point2f corners[] = {
Point2f(0.0f, 0.0f),
Point2f(static_cast<float>(sourceSize.width - 1), 0.0f),
Point2f(0.0f, static_cast<float>(sourceSize.height - 1)),
Point2f(static_cast<float>(sourceSize.width - 1),
static_cast<float>(sourceSize.height - 1))
};
float minX = std::numeric_limits<float>::max();
float minY = std::numeric_limits<float>::max();
float maxX = std::numeric_limits<float>::lowest();
float maxY = std::numeric_limits<float>::lowest();
for (const Point2f& corner : corners)
{
const Point2f undistortedCorner = barrelUndistort(corner, sourceSize, k1);
minX = std::min(minX, undistortedCorner.x);
minY = std::min(minY, undistortedCorner.y);
maxX = std::max(maxX, undistortedCorner.x);
maxY = std::max(maxY, undistortedCorner.y);
}
const int left = static_cast<int>(std::floor(minX));
const int top = static_cast<int>(std::floor(minY));
const int right = static_cast<int>(std::ceil(maxX));
const int bottom = static_cast<int>(std::ceil(maxY));
return Rect(left, top, right - left + 1, bottom - top + 1);
}
static Mat_<T> createBarrelDistortedImage(const Mat_<T>& image, float k1)
{
Mat1f mapx(image.size());
Mat1f mapy(image.size());
for (int y = 0; y < image.rows; ++y)
{
for (int x = 0; x < image.cols; ++x)
{
const Point2f undistorted = barrelUndistort(Point2i(x, y),
image.size(), k1);
mapx.at<float>(y, x) = undistorted.x;
mapy.at<float>(y, x) = undistorted.y;
}
}
constexpr float first_coordinate = 0.0f;
return remapReference(image, mapx, mapy, first_coordinate);
}
Mat1f mapx;
Mat1f mapy;
Rect undistortedCanvas;
};
template<class T>
const Size RemapBorderConstant<T>::source_size{30, 20};
template<class T>
constexpr float RemapBorderConstant<T>::barrel_coefficient;
using RemapBorderConstantTypes = ::testing::Types<float, double>;
TYPED_TEST_CASE(RemapBorderConstant, RemapBorderConstantTypes);
// The smooth tensor-product image exposes artifacts at the image edges.
TYPED_TEST(RemapBorderConstant, tensor_product)
{
this->runTensorProductTest();
}
// The checkerboard image exposes interpolation artifacts within the image.
TYPED_TEST(RemapBorderConstant, checkerboard)
{
this->runCheckerboardTest();
}
///////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////
// remap relative // remap relative
+5 -1
View File
@@ -1839,12 +1839,14 @@ int DTreesImpl::readSplit( const FileNode& fn )
Split split; Split split;
int vi = (int)fn["var"]; int vi = (int)fn["var"];
CV_Assert( 0 <= vi && vi <= (int)varType.size() ); CV_Assert( 0 <= vi && vi < (int)varMapping.size() );
vi = varMapping[vi]; // convert to varIdx if needed vi = varMapping[vi]; // convert to varIdx if needed
CV_Assert( 0 <= vi && vi < (int)varType.size() );
split.varIdx = vi; split.varIdx = vi;
if( varType[vi] == VAR_CATEGORICAL ) // split on categorical var if( varType[vi] == VAR_CATEGORICAL ) // split on categorical var
{ {
CV_Assert( vi < (int)catOfs.size() );
int i, val, ssize = getSubsetSize(vi); int i, val, ssize = getSubsetSize(vi);
split.subsetOfs = (int)subsets.size(); split.subsetOfs = (int)subsets.size();
for( i = 0; i < ssize; i++ ) for( i = 0; i < ssize; i++ )
@@ -1860,6 +1862,7 @@ int DTreesImpl::readSplit( const FileNode& fn )
if( fns.isInt() ) if( fns.isInt() )
{ {
val = (int)fns; val = (int)fns;
CV_Assert( 0 <= val && (val >> 5) < ssize );
subset[val >> 5] |= 1 << (val & 31); subset[val >> 5] |= 1 << (val & 31);
} }
else else
@@ -1869,6 +1872,7 @@ int DTreesImpl::readSplit( const FileNode& fn )
for( i = 0; i < n; i++, ++it ) for( i = 0; i < n; i++, ++it )
{ {
val = (int)*it; val = (int)*it;
CV_Assert( 0 <= val && (val >> 5) < ssize );
subset[val >> 5] |= 1 << (val & 31); subset[val >> 5] |= 1 << (val & 31);
} }
} }
+55
View File
@@ -96,6 +96,61 @@ ML_Legacy_Param param_list[] = {
INSTANTIATE_TEST_CASE_P(/**/, ML_Legacy_Params, testing::ValuesIn(param_list)); INSTANTIATE_TEST_CASE_P(/**/, ML_Legacy_Params, testing::ValuesIn(param_list));
TEST(ML_DTrees, load_bad_categorical_split)
{
// Train a tree with a categorical input so the model carries a
// categorical split serialized as an "in"/"not_in" value list.
const int n = 40;
Mat samples(n, 1, CV_32F);
Mat responses(n, 1, CV_32S);
for (int i = 0; i < n; i++)
{
int cat = i % 4;
samples.at<float>(i, 0) = (float)cat;
responses.at<int>(i, 0) = (cat == 1 || cat == 2) ? 1 : 0;
}
Mat varType(2, 1, CV_8U);
varType.at<uchar>(0) = ml::VAR_CATEGORICAL;
varType.at<uchar>(1) = ml::VAR_CATEGORICAL;
Ptr<ml::TrainData> td = ml::TrainData::create(samples, ml::ROW_SAMPLE, responses,
noArray(), noArray(), noArray(), varType);
Ptr<ml::DTrees> dt = ml::DTrees::create();
dt->setMaxDepth(4);
dt->setCVFolds(0);
dt->setMaxCategories(4);
dt->setMinSampleCount(1);
dt->train(td);
const string filename = cv::tempfile(".yml");
dt->save(filename);
string model;
{
std::ifstream in(filename.c_str());
std::stringstream ss;
ss << in.rdbuf();
model = ss.str();
}
// Category values in the split list index a per-split subset bitmask.
// Injecting a value larger than the number of categories used to write
// past that bitmask; loading such a model must be rejected, not crash.
size_t pos = model.find("in:");
ASSERT_NE(pos, string::npos);
size_t br = model.find('[', pos);
ASSERT_NE(br, string::npos);
model.insert(br + 1, "1000000,");
{
std::ofstream out(filename.c_str());
out << model;
}
Ptr<ml::DTrees> bad;
EXPECT_THROW(bad = ml::DTrees::load(filename), Exception);
remove(filename.c_str());
}
/*TEST(ML_SVM, throw_exception_when_save_untrained_model) /*TEST(ML_SVM, throw_exception_when_save_untrained_model)
{ {
Ptr<cv::ml::SVM> svm; Ptr<cv::ml::SVM> svm;
+1 -1
View File
@@ -723,7 +723,7 @@ void HOGCache::init(const HOGDescriptor* _descriptor,
#if CV_SIMD128 #if CV_SIMD128
idx = v_float32x4(0.0f, 1.0f, 2.0f, 3.0f); idx = v_float32x4(0.0f, 1.0f, 2.0f, 3.0f);
for (; j <= blockSize.height - 4; j += 4) for (; j <= blockSize.width - 4; j += 4)
{ {
v_float32x4 t = v_sub(idx, _bw); v_float32x4 t = v_sub(idx, _bw);
t = v_mul(t, t); t = v_mul(t, t);
@@ -1364,4 +1364,22 @@ TEST(Objdetect_CascadeDetector, small_img)
} }
} }
// See https://github.com/opencv/opencv/issues/23580
// HOGDescriptor::compute() overflowed the gaussian weights buffer when the block
// was taller than it was wide: the SIMD store loop for the width buffer (_dj) was
// bounded by blockSize.height instead of blockSize.width. The block is chosen wide
// enough that the buffer is heap allocated, so the overflow is a real out-of-bounds
// write. "Done" is simply that compute() runs without crashing.
TEST(Objdetect_HOGDescriptor, issue_23580_tall_block_no_overflow)
{
Size winSize(272, 2048); // height > width, width > AutoBuffer stack size
HOGDescriptor hog(winSize, /*blockSize*/ winSize, /*blockStride*/ Size(8, 8),
/*cellSize*/ Size(8, 8), /*nbins*/ 9);
Mat src(winSize, CV_8UC1, Scalar::all(0));
std::vector<float> descriptors;
ASSERT_NO_THROW(hog.compute(src, descriptors));
EXPECT_FALSE(descriptors.empty());
}
}} // namespace }} // namespace