mirror of
https://github.com/opencv/opencv.git
synced 2026-10-28 08:35:30 +08:00
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:
1 parent
f98c0a46fa
commit
46dba3df6e
2 files changed
+49
-3
No files matched your search
@@ -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 );
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user