Fast-path transposeND for identity and 2D transpose orders #29172
### 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.
- [x] The feature is well documented and sample code can be built with the project CMake
<!-- Note!!! If you are an automated agent, we have a special process for you: add 🤖🤖🤖 to the end of the PR title. -->
This PR adds fast paths to cv::transposeND() for two common cases:
- identity permutation: dispatch to copyTo()
- 2D permutation {1, 0}: dispatch to transpose()
All other permutations continue to use the existing generic ND implementation.
Why:
transposeND() currently falls back to the generic memcpy/index-update loop even for the common 2D transpose case, while OpenCV already has an optimized transpose() path. Reusing that path avoids unnecessary index arithmetic and improves performance for 2D inputs passed through transposeND().
Performance:
[BinaryOpTest.transposeND/21 (1920x1080, 8UC3): 28.21 ms -> 0.66 ms (-97.7%)]
[BinaryOpTest.transposeND/22 (1920x1080, 8UC4): 37.61 ms -> 0.88 ms (-97.7%)]
[BinaryOpTest.transposeND/29 (1920x1080, 32FC1): 10.26 ms -> 0.75 ms (-92.7%)]
Full transposeND perf subset: 6760 ms -> 592 ms (-91.2%)
guard the parsePadding NHWC swap on paddings.total()==8 and require the parseResize size tensor to hold height and width, matching the existing parseStridedSlice check
core: Vectorize meanStdDev #29339
- Add SIMD SumSqr_SIMD reductions (previously scalar) plus AVX-512 dispatch for the mean TU.
- Uses universal intrinsics, so all SIMD backends benefit.
### 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
- [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
dnn: vectorize fp32 convolution on RISC-V RVV #29357
### Summary
Vectorizes the new DNN engine's fp32 convolution on RISC-V **RVV**. Convolution was the last major block-layout operator still running scalar on RVV; this brings it to parity with the already-vectorized depthwise/pool/batchnorm path.
Single file, **purely additive** (`#elif CV_SIMD_SCALABLE` branches only) — x86/AVX2, ARM/NEON and AArch64 codegen are unchanged.
### Background
- **#28585** introduced block-layout conv with fp32 kernels specialized for AVX2 (`C0=8`) and NEON, scalar `#else` for everything else, and explicitly noted *"we could add the respective kernels later."*
- On RVV that `#else` meant conv ran **scalar at every VLEN** — the C0=8 fixed width approach doesn't transfer to a variable-VLEN ISA.
- **#29304** made the block size track the hardware width (`C0 = vlanes()`), fixing the VLEN≥256 assertion but leaving conv scalar.
- **This PR** supplies the deferred RVV conv vectorization, on top of that `C0=vlanes()` foundation.
### Approach
- Re-enable the `SPAT_BLOCK_SIZE=10` **blocked path** on RVV. Because `K0 == vlanes()`, one `v_float32` accumulator covers a full output-channel block, so 10 accumulators process 10 output positions together. A single K0-wide weight `vx_load` is reused across all 10 — amortizing the per-output-point load that bottlenecks the scalar path (this is what enables multi-core scaling; the scalar/per-FMA-load path is bandwidth-bound).
- Vectorize the **scalar tail** (the `<10`-position remainder) the same way.
- **Vector-length-agnostic:** `C0` is runtime, the kernel is written in terms of `v_float32`/`vlanes()`, so the same binary runs at full width on VLEN 128/256/512/1024 with no recompile. No per-VLEN kernels.
- The six `C0=8` specialized kernels stay `#if !CV_SIMD_SCALABLE`-gated (they can't run at `C0=vlanes()`); on RVV all shapes use the generic kernel.
### Performance
Convolution throughput, blocked (this PR) vs scalar, same machine/engine (VLEN=256, 8× rv64 @ 2.4 GHz), GFLOP/s:
| layer | scalar 1T | this 1T | scalar 8T | this 8T | 8T speedup |
|---|---|---|---|---|---|
| 3×3, 256→256, 64² | 1.13 | 13.23 | 8.28 | 75.62 | **9.1×** |
| 1×1, 256→256, 64² | 1.08 | 11.73 | 8.02 | 71.70 | 8.9× |
| 3×3, 128→128, 128² | 1.10 | 13.02 | 8.45 | 89.14 | **10.6×** |
≈ **12× single-thread, 9–11× at 8 threads**. Convolution dominates CNN inference time, so this is a large end-to-end win on RVV hardware.
### Validation
K3-class RVV board, VLEN=256: `Test_ONNX_layers` **264/264**, `Test_ONNX_conformance` **1641/1641**, **0 assertions**. Output is bit-identical to the scalar path (same accumulation order, just vectorized over `K0`).
Vector-length-agnosticism confirmed by running the VLEN=256 binary unchanged at **VLEN=1024**.
### 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
FileNode::operator double() and operator float() read an INT node via readInt()
(32-bit), truncating values above INT_MAX -- e.g. an integer 6662329666 from an
externally-produced json/yaml/xml is read back as -1927604926. The node stores
the value as int64 (operator int64_t() already reads it correctly via readLong),
so use readLong() for the floating-point conversions too. Values that fit in
int32 are unchanged (sign-extended); larger ones are now correct.
Reader side of #29363 (the writer side was #29364).
dnn: optimize blobFromImages using NEON intrinsics on ARM64 #29316
- This PR optimizes the HWC-to-NCHW conversion in blobFromImages() by adding NEON implementation.
- On x64, the MSVC compiler automatically vectorizes the existing scalar implementation, resulting in significantly better performance.
- On Windows ARM64, MSVC does not auto-vectorize this stride-3 access pattern, leading to a noticeable performance gap compared to x64.
- Added CV_NEON macro guard to ensure SIMD optimization is enabled on ARM64 architecture, leaving behavior on other platforms completely unchanged.
**Performance Improvements**
- This optimization significantly improves the performance of HWC-to-NCHW conversion on Windows ARM64.
<img width="823" height="254" alt="image" src="https://github.com/user-attachments/assets/84b22deb-22da-4607-8009-3405c2529b80" />
- [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
Extended support for Resize and Split layers #29323
Merge with: https://github.com/opencv/opencv_extra/pull/1379
Key changes:
Resize layer:
_antialias_ (linear & cubic) :- PIL-style separable resampling with stretched filter support and edge-clamped, renormalized weights.
_axes_ (incl. reversed [3,2]) :- getOutShape, the scale override, and runtime _tf_crop_and_resize_ ROI parsing now map 2-element sizes/scales/roi by the axes order instead of assuming [2,3].
_keep_aspect_ratio_policy_ (not_larger/not_smaller) :- output size from min/max per-axis scale.
_half_pixel_symmetric_ :- new coordinate-transform mode + importer mapping.
_align_corners_ downsampling :- coordinate scale uses the unfloored scaled length (in−1)/(in·x_scale−1).
Split Layer:
_convertTo empty 1-D Mat:_ the empty-Mat branch collapsed a 1-D [0] to 2-D [1,0] via cv::Size(); now uses allowTransposed like the non-empty path.
### 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
predictOptimalVectorWidth() built its vectorWidths table with 8 entries
(depths CV_8U..CV_16F), but checkOptimalVectorWidth() indexes it by depth.
The 5.x depths CV_16BF, CV_Bool, CV_64U, CV_64S and CV_32U therefore read
past the end of the array; the garbage value can slip past the ckercn <= 0
guard, and the divider normalization loop then shifts the divider to zero,
so "offsets[i] % dividers[i]" raises SIGFPE. The failure is allocation
dependent and shows up as a sequence-dependent crash, e.g. in the OpenCL
Norm tests for CV_32U (cv::norm on a UMat reaches this via ocl_sum, which
calls predictOptimalVectorWidth before its own depth guard bails out).
Size the table to CV_DEPTH_MAX so every depth is in bounds and map the new
fixed-size integer depths to their natural OpenCL vector widths; CV_16BF
has no OpenCL vector type and stays scalar. Add a regression test covering
all depths.
MlasThreadedBufAlloc() and its ThreadedBufHolder guarded the
_aligned_malloc / _aligned_free path on _MSC_VER. Non-MSVC Windows
toolchains (MinGW, clang) therefore fell through to posix_memalign(),
which the Windows CRT does not provide, so the build failed with
"'posix_memalign' was not declared in this scope".
Guard the aligned-allocation path on _WIN32 instead, in both the holder
declaration (mlasi.h) and definition (platform.cpp) so the unique_ptr
deleter type stays consistent across translation units, and include
<malloc.h> on Windows since MinGW only declares the _aligned_* functions
there. The non-Windows posix_memalign / aligned_alloc fallback is
unchanged.
Fixes#29350
- Replace the fixed-128-bit per-depth minMaxIdx kernels with a single templated universal-intrinsic core
- added simd dispatch AVX-512 dispatch
- A dual-accumulator inner loop added
Uses universal intrinsics, so all SIMD backends benefit.
Follow-up to the recent "reject under-length raw exif profile" change.
The declared length in a PNG raw exif profile (tEXt/zTXt "Raw profile type
exif" chunk) is fully attacker controlled. The < 6 guard stops the underflow,
but a large positive value still passes it and reaches HexStringToBytes(),
which does raw_data.resize(expected_length) before reading anything. So a few
bytes in a text chunk can force a ~2GB allocation -> easy memory-amplification
DoS while decoding an otherwise small PNG.
The payload is hex encoded (two characters per byte), so a valid length can
never exceed the profile text carrying it. Reject any declared length greater
than profile_len. This bounds the allocation to the input size and doesn't
reject any valid profile; the valid decode path is unchanged.
imgproc: optimized LUT and equalizeHist with SIMD #29250
- optimized lut with SIMD
- support equalizeHist with v_lut
### 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
- [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
Improved color convert and AVX512 dispatch added #28992
### 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
- [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
Optimization ArUco: get border errors in one pass for both normal and inverted markers #29329
This PR is a follow up to optimization in https://github.com/opencv/opencv/pull/29267.
## Context:
When detecting inverted markers, we call `_getBorderErrors` twice:
- `int borderErrors = _getBorderErrors(cellPixelRatio, ...);`
- `Mat invCellPixelRatio = 1.f - cellPixelRatio;`
- `int invBError = _getBorderErrors(invCellPixelRatio, ...);`
meaning:
1. Scan border cells once.
2. Allocate a new Mat.
3. Invert the entire `cellPixelRatio` matrix, not just the border.
4. Scan border cells again on the inverted matrix.
5. If inverted marker is better, copy the full inverted matrix back
## Solution
only call `_getBorderErrors` once and compute both
- borderErrors: `cellPixelRatio > validBitIdThreshold`
- invBorderErrors: `1 - cellPixelRatio > validBitIdThreshold`
This saves:
1. full invert into temporary Mat: (`Mat invCellPixelRatio = 1.f - cellPixelRatio;`)
2. scan temporary border: the second `_getBorderErrors`
3. copy temporary Mat back into `cellPixelRatio`: `invCellPixelRatio.copyTo(cellPixelRatio);`
Note that the solution does not implement:
```
if(params.detectInvertedMarker) {
_getBorderErrorsBoth(...);
} else {
borderErrors = _getBorderErrors(...);
}
```
because the extra cost to computing invBorderErrors: `if(1.f - ratio > validBitIdThreshold) invBorderErrors++;` is negligible. this also avoids having to maintain two functions: `_getBorderErrorsBoth` and `_getBorderErrors`
## Tests:
No visible results when testing the full marker detection pipeline because this step is not expensive. There is a roughly 8% noise when re-running the marker detections making it hard to spot small speed diffs.
When testing only this specific step with a float matrix of size: `(markerSize + 2*border)^2` on a AMD Ryzen 7 (8 cores / 16 threads):
- The new code is 30-45× faster at this stage depending on the marker size and whether the candidate was actually an inverted one, saving ~530-580 ns per candidate, mainly because we removed `Mat invCellPixelRatio = 1.f - cellPixelRatio`
- The new code is equivalent when detecting non-inverted markers +/- 3 ns
---
### 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
- [ ] 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
Restricting the condition with _M_IX86/_M_X64 so it only applies to x86/x64 MSVC builds. MSVC ARM64 now falls through to the existing `#else` branch, which already has a portable CV_SIMD-based exp32f/exp64f implementation
**Performance Benchmarks:**
<img width="976" height="486" alt="image" src="https://github.com/user-attachments/assets/62daf2c3-34ac-4fc7-92d0-268073f746f3" />
- [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
Fix ONNXRuntime dll path mismatch #29309
**1. C2664 build error in `net_impl_backend.cpp`**
`EnableProfiling()` expects `const wchar_t*` on Windows (`ORTCHAR_T`), but was passed `const char*`.
Fixed by converting to `std::wstring`, as suggested in #29278
---
**2. Wrong ORT DLL loaded at runtime (`modules/dnn/CMakeLists.txt`)**
With `DOWNLOAD_ONNXRUNTIME=ON`, the DLL glob only searched `bin/` but the downloaded package places DLLs in `lib/`. This left the build tree with no ORT DLL, causing Windows to fall back to the stale `System32\onnxruntime.dll` (1.17.1), crashing against the ORT 1.25.1 API.
Fixed by adding `lib/` as fallback and staging DLLs into the build bin directory at configure time.
Closes : #29278
### 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
More use of AutoBuffer #28907
When possible, AutoBuffer should be faster than std::vector<>, and should not be worse if it requires a heap allocation rather than a stack allocation.
### 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
- [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.
- [ ] The feature is well documented and sample code can be built with the project CMake
dnn: fix new-engine block layout for RVV when VLEN > 128 #29304
### 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
<!-- Note!!! If you are an automated agent, we have a special process for you: add 🤖🤖🤖 to the end of the PR title. -->
#### Problem
Fixes#28852. The new DNN engine packs activations in a blocked NCHWc layout with a fixed channel-block size `C0 = 8`. The blocked-layout kernels (MaxPool, AveragePool, BatchNorm, depthwise Conv, ConvTranspose, generic Conv) load one block into a SIMD vector and assert: `C0 == nlanes || C0 == nlanes*2 || C0 % (nlanes*4) == 0`
On RISC-V the universal intrinsics are **scalable with LMUL=2**, so `nlanes = (VLEN/32)*2` — **16 at VLEN=256, 64 at VLEN=1024** — which exceeds the fixed `C0=8`. The assertion fails with `-215` and the ONNX pooling/conv conformance tests abort. #29180 worked around it by disabling the RVV SIMD path in those kernels.
#### Fix
Make the block size track the hardware vector width on RVV instead of assuming 8:
- `net_impl.cpp`: `defaultC0 = max(8, VTraits<v_float32>::vlanes())` (16/64 on RVV).
- The fp32 blocked kernels read `C0` at runtime and size scratch buffers by `max_nlanes` (bounded by the compile-time `CV_RVV_MAX_VLEN`, default 1024).
- All changes are guarded by `CV_SIMD_SCALABLE`, so **x86/NEON are unchanged**.
- The int8 quantized kernels are hardwired to `C0=8` (VNNI/NEON packing + per-channel quant) and are scalar on RVV, so quantized graphs are pinned to `C0=8` in `prepareForInference()` (detected via a `CV_8S` arg); only fp32 graphs use the wider block.
#### Validation (native RISC-V)
I have already conducted tests on the Spacemit K3, covering both the X100 (VLEN=256) and the A100 (VLEN=1024).
`opencv_test_dnn`, ENGINE_AUTO (new engine), no assertions:
| VLEN | Test_ONNX_conformance | Test_ONNX_layers (conv/pool/depthwise/quantized/MobileNet_v4) |
|------|-----------------------|--------------------------------------------------------------|
| 256 | 1641 / 1641 | all pass (incl. `Quantized_Convolution`) |
| 1024 | 1641 / 1641 | all pass (incl. `Quantized_Convolution`) |
Reject initializers whose declared shape claims more elements than the tensor payload (raw_data or a typed *_data field) actually holds, before the Mat copy/convert reads them.