Merge pull request #30506 from sshivensolanki:fix-sort-new-depths

core: support 5.x depths in sort and sortIdx - #30506

Fixes #30505

### Problem

The kernel tables of `cv::sort` and `cv::sortIdx` (`modules/core/src/matrix_operations.cpp`) only have entries for `CV_8U` to `CV_64F`, so every depth added in 5.x fails with `func != 0`.

### Fix

Both tables now use the existing `sort_<T>` / `sortIdx_<T>` templates for:

- `CV_16F` → `hfloat`, `CV_16BF` → `bfloat`, `CV_8F_E4M3FN` → `fp8_t`, `CV_8F_E4M3FNUZ` → `fp8a_t` (compared through their `float` conversion);
- `CV_Bool` → `uchar`, the same kernel as `CV_8U`;
- `CV_64U` → `uint64_t`, `CV_64S` → `int64_t`, `CV_32U` → `uint32_t`.

### Tests

- `Core/sortIdx.simple` now also runs on `CV_16U`, `CV_16F`, `CV_16BF`, `CV_Bool`, `CV_64U`, `CV_64S`, `CV_32U` and both fp8 depths (`CV_16U` was already supported but not tested), and also checks `cv::sort` against sorting a `CV_64F` copy of the same data; there was no `cv::sort` test before.
- New `Core_sort.large_integers` checks exact `sort` / `sortIdx` results for `CV_32S`, `CV_32U`, `CV_64S` and `CV_64U` with values that need the full type: `INT_MIN` / `INT_MAX`, the unsigned high bit (`0x80000000`, `UINT_MAX`, `2^63`, `UINT64_MAX`) and `2^53` vs `2^53 + 1`. With signed kernels for `CV_32U` / `CV_64U` it fails, while the random `sortIdx` test still passes.

The new cases fail on current 5.x and pass with this patch. All `sortIdx` / `sort` tests in `opencv_test_core` pass locally on Apple M1 Pro (242 tests), with OpenCL enabled and with `OPENCV_OPENCL_DEVICE=disabled`. The full `opencv_test_core` passes, except 7 tests that need `opencv_extra` test data, which I didn't have locally (FileStorage base64 and globbing).

### 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.
- [ ] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
Shiven Solanki authored and GitHub committed 2026-10-26 10:05:01 +03:00
1 parent f98c0a46fa
commit 46dba3df6e
2 files changed
+49 -3

No files matched your search

+6 -2
View File
@@ -1312,7 +1312,9 @@ void cv::sort( InputArray _src, OutputArray _dst, int flags )
static SortFunc tab[CV_DEPTH_MAX] =
{
sort_<uchar>, sort_<schar>, sort_<ushort>, sort_<short>,
sort_<int>, sort_<float>, sort_<double>, 0
sort_<int>, sort_<float>, sort_<double>, sort_<hfloat>,
sort_<bfloat>, sort_<uchar>, sort_<uint64_t>, sort_<int64_t>,
sort_<uint32_t>, sort_<fp8_t>, sort_<fp8a_t>
};
SortFunc func = tab[src.depth()];
CV_Assert( func != 0 );
@@ -1339,7 +1341,9 @@ void cv::sortIdx( InputArray _src, OutputArray _dst, int flags )
static SortFunc tab[CV_DEPTH_MAX] =
{
sortIdx_<uchar>, sortIdx_<schar>, sortIdx_<ushort>, sortIdx_<short>,
sortIdx_<int>, sortIdx_<float>, sortIdx_<double>, 0
sortIdx_<int>, sortIdx_<float>, sortIdx_<double>, sortIdx_<hfloat>,
sortIdx_<bfloat>, sortIdx_<uchar>, sortIdx_<uint64_t>, sortIdx_<int64_t>,
sortIdx_<uint32_t>, sortIdx_<fp8_t>, sortIdx_<fp8a_t>
};
SortFunc func = tab[src.depth()];
CV_Assert( func != 0 );
+43 -1
View File
@@ -1465,10 +1465,19 @@ PARAM_TEST_CASE(sortIdx, MatDepth, SortRowCol, SortOrder, Size, bool)
{
case CV_8U: check_<uchar>(values_row, idx_row); break;
case CV_8S: check_<char>(values_row, idx_row); break;
case CV_16U: check_<ushort>(values_row, idx_row); break;
case CV_16S: check_<short>(values_row, idx_row); break;
case CV_32S: check_<int>(values_row, idx_row); break;
case CV_32F: check_<float>(values_row, idx_row); break;
case CV_64F: check_<double>(values_row, idx_row); break;
case CV_16F: check_<hfloat>(values_row, idx_row); break;
case CV_16BF: check_<bfloat>(values_row, idx_row); break;
case CV_Bool: check_<uchar>(values_row, idx_row); break;
case CV_64U: check_<uint64_t>(values_row, idx_row); break;
case CV_64S: check_<int64_t>(values_row, idx_row); break;
case CV_32U: check_<uint32_t>(values_row, idx_row); break;
case CV_8F_E4M3FN: check_<fp8_t>(values_row, idx_row); break;
case CV_8F_E4M3FNUZ: check_<fp8a_t>(values_row, idx_row); break;
default: ASSERT_FALSE(true) << "Unsupported type: " << type;
}
}
@@ -1483,17 +1492,50 @@ TEST_P(sortIdx, simple)
cv::sortIdx(src_roi, dst_roi, flags);
validate();
// cv::sort must give the same values as sorting a CV_64F copy
Mat sorted, sorted64f, ref64f, src64f;
cv::sort(src_roi, sorted, flags);
src_roi.convertTo(src64f, CV_64F);
cv::sort(src64f, ref64f, flags);
sorted.convertTo(sorted64f, CV_64F);
EXPECT_EQ(0, cvtest::norm(sorted64f, ref64f, NORM_INF));
}
}
INSTANTIATE_TEST_CASE_P(Core, sortIdx, Combine(
Values(CV_8U, CV_8S, CV_16S, CV_32S, CV_32F, CV_64F), // depth
Values(CV_8U, CV_8S, CV_16U, CV_16S, CV_32S, CV_32F, CV_64F,
CV_16F, CV_16BF, CV_Bool, CV_64U, CV_64S, CV_32U,
CV_8F_E4M3FN, CV_8F_E4M3FNUZ), // depth
Values(SORT_EVERY_COLUMN, SORT_EVERY_ROW),
Values(SORT_ASCENDING, SORT_DESCENDING),
Values(Size(3, 3), Size(16, 8)),
::testing::Bool()
));
// Values that need the full integer type: the high bit of the unsigned types,
// and 64-bit neighbours above 2^53 that a double cannot tell apart.
template<typename T>
static void checkSortExact(int depth, const std::vector<T>& values, const std::vector<int>& expectedIdx)
{
Mat src(1, (int)values.size(), depth, const_cast<T*>(values.data()));
Mat idx, sorted;
cv::sortIdx(src, idx, SORT_EVERY_ROW | SORT_ASCENDING);
cv::sort(src, sorted, SORT_EVERY_ROW | SORT_ASCENDING);
for (size_t i = 0; i < values.size(); i++)
{
EXPECT_EQ(expectedIdx[i], idx.at<int>((int)i)) << "i=" << i;
EXPECT_EQ(values[expectedIdx[i]], sorted.at<T>((int)i)) << "i=" << i;
}
}
TEST(Core_sort, large_integers)
{
checkSortExact<int>(CV_32S, { INT_MAX, INT_MIN, -1, 0, 1 }, { 1, 2, 3, 4, 0 });
checkSortExact<uint32_t>(CV_32U, { UINT_MAX, 0, 0x80000000u, 1, 0x7fffffffu }, { 1, 3, 4, 2, 0 });
checkSortExact<int64_t>(CV_64S, { INT64_MAX, INT64_MIN, -1, (1LL << 53) + 1, 1LL << 53 }, { 1, 2, 4, 3, 0 });
checkSortExact<uint64_t>(CV_64U, { UINT64_MAX, 0, 1ULL << 63, (1ULL << 53) + 1, 1ULL << 53 }, { 1, 4, 3, 2, 0 });
}
TEST(Core_sortIdx, regression_8941)
{