Skip to content

Commit 437ca0b

Browse files
committed
Merge pull request opencv#8949 from alalek:fix_sortIdx
2 parents 2c30f35 + d3ebe66 commit 437ca0b

File tree

5 files changed

+175
-29
lines changed

5 files changed

+175
-29
lines changed

modules/core/src/matrix.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4384,11 +4384,10 @@ static bool ipp_sortIdx( const Mat& src, Mat& dst, int flags )
43844384
{
43854385
CV_INSTRUMENT_REGION_IPP()
43864386

4387-
bool sortRows = (flags & 1) == CV_SORT_EVERY_ROW;
4388-
bool sortDescending = (flags & CV_SORT_DESCENDING) != 0;
4387+
bool sortRows = (flags & 1) == SORT_EVERY_ROW;
4388+
bool sortDescending = (flags & SORT_DESCENDING) != 0;
43894389
int depth = src.depth();
43904390
IppDataType type = ippiGetDataType(depth);
4391-
Ipp32s elemSize = (Ipp32s)src.elemSize1();
43924391

43934392
IppSortIndexFunc ippsSortRadixIndex = getSortIndexFunc(depth, sortDescending);
43944393
if(!ippsSortRadixIndex)
@@ -4405,7 +4404,7 @@ static bool ipp_sortIdx( const Mat& src, Mat& dst, int flags )
44054404

44064405
for(int i = 0; i < src.rows; i++)
44074406
{
4408-
if(CV_INSTRUMENT_FUN_IPP(ippsSortRadixIndex, (void*)src.ptr(i), elemSize, (Ipp32s*)dst.ptr(i), src.cols, buffer) < 0)
4407+
if(CV_INSTRUMENT_FUN_IPP(ippsSortRadixIndex, (const void*)src.ptr(i), (Ipp32s)src.step[1], (Ipp32s*)dst.ptr(i), src.cols, buffer) < 0)
44094408
return false;
44104409
}
44114410
}
@@ -4422,13 +4421,13 @@ static bool ipp_sortIdx( const Mat& src, Mat& dst, int flags )
44224421

44234422
buffer.allocate(bufferSize);
44244423

4425-
Ipp32s pixStride = elemSize*dst.cols;
4424+
Ipp32s srcStep = (Ipp32s)src.step[0];
44264425
for(int i = 0; i < src.cols; i++)
44274426
{
44284427
subRect.x = i;
44294428
dstSub = Mat(dst, subRect);
44304429

4431-
if(CV_INSTRUMENT_FUN_IPP(ippsSortRadixIndex, (void*)src.ptr(0, i), pixStride, (Ipp32s*)dstRow.ptr(), src.rows, buffer) < 0)
4430+
if(CV_INSTRUMENT_FUN_IPP(ippsSortRadixIndex, (const void*)src.ptr(0, i), srcStep, (Ipp32s*)dstRow.ptr(), src.rows, buffer) < 0)
44324431
return false;
44334432

44344433
dstRow = dstRow.reshape(1, dstSub.rows);

modules/core/test/test_operations.cpp

Lines changed: 147 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,10 @@
4141
//M*/
4242

4343
#include "test_precomp.hpp"
44+
#include "opencv2/ts/ocl_test.hpp" // T-API like tests
4445

45-
#include <string>
46-
#include <iostream>
47-
#include <fstream>
48-
#include <iterator>
49-
#include <limits>
50-
#include <numeric>
51-
52-
using namespace cv;
53-
using namespace std;
54-
46+
namespace cvtest {
47+
namespace {
5548

5649
class CV_OperationsTest : public cvtest::BaseTest
5750
{
@@ -1120,8 +1113,8 @@ void CV_OperationsTest::run( int /* start_from */)
11201113
if (!TestTemplateMat())
11211114
return;
11221115

1123-
/* if (!TestMatND())
1124-
return;*/
1116+
if (!TestMatND())
1117+
return;
11251118

11261119
if (!TestSparseMat())
11271120
return;
@@ -1254,3 +1247,145 @@ TEST(MatTestRoi, adjustRoiOverflow)
12541247

12551248
ASSERT_EQ(roi.rows, m.rows);
12561249
}
1250+
1251+
1252+
CV_ENUM(SortRowCol, SORT_EVERY_COLUMN, SORT_EVERY_ROW)
1253+
CV_ENUM(SortOrder, SORT_ASCENDING, SORT_DESCENDING)
1254+
1255+
PARAM_TEST_CASE(sortIdx, MatDepth, SortRowCol, SortOrder, Size, bool)
1256+
{
1257+
int type;
1258+
Size size;
1259+
int flags;
1260+
bool use_roi;
1261+
1262+
Mat src, src_roi;
1263+
Mat dst, dst_roi;
1264+
1265+
virtual void SetUp()
1266+
{
1267+
int depth = GET_PARAM(0);
1268+
int rowFlags = GET_PARAM(1);
1269+
int orderFlags = GET_PARAM(2);
1270+
size = GET_PARAM(3);
1271+
use_roi = GET_PARAM(4);
1272+
1273+
type = CV_MAKE_TYPE(depth, 1);
1274+
1275+
flags = rowFlags | orderFlags;
1276+
}
1277+
1278+
void generateTestData()
1279+
{
1280+
Border srcBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
1281+
randomSubMat(src, src_roi, size, srcBorder, type, -100, 100);
1282+
1283+
Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
1284+
randomSubMat(dst, dst_roi, size, dstBorder, CV_32S, 5, 16);
1285+
}
1286+
1287+
template<typename T>
1288+
void check_(const cv::Mat& values_, const cv::Mat_<int>& idx_)
1289+
{
1290+
cv::Mat_<T>& values = (cv::Mat_<T>&)values_;
1291+
cv::Mat_<int>& idx = (cv::Mat_<int>&)idx_;
1292+
size_t N = values.total();
1293+
std::vector<bool> processed(N, false);
1294+
int prevIdx = idx(0);
1295+
T prevValue = values(prevIdx);
1296+
processed[prevIdx] = true;
1297+
for (size_t i = 1; i < N; i++)
1298+
{
1299+
int nextIdx = idx((int)i);
1300+
T value = values(nextIdx);
1301+
ASSERT_EQ(false, processed[nextIdx]) << "Indexes must be unique. i=" << i << " idx=" << nextIdx << std::endl << idx;
1302+
processed[nextIdx] = true;
1303+
if ((flags & SORT_DESCENDING) == SORT_DESCENDING)
1304+
ASSERT_GE(prevValue, value) << "i=" << i << " prevIdx=" << prevIdx << " idx=" << nextIdx;
1305+
else
1306+
ASSERT_LE(prevValue, value) << "i=" << i << " prevIdx=" << prevIdx << " idx=" << nextIdx;
1307+
prevValue = value;
1308+
prevIdx = nextIdx;
1309+
}
1310+
}
1311+
1312+
void validate()
1313+
{
1314+
ASSERT_EQ(CV_32SC1, dst_roi.type());
1315+
ASSERT_EQ(size, dst_roi.size());
1316+
bool isColumn = (flags & SORT_EVERY_COLUMN) == SORT_EVERY_COLUMN;
1317+
size_t N = isColumn ? src_roi.cols : src_roi.rows;
1318+
Mat values_row((int)N, 1, type), idx_row((int)N, 1, CV_32S);
1319+
for (size_t i = 0; i < N; i++)
1320+
{
1321+
SCOPED_TRACE(cv::format("row/col=%d", (int)i));
1322+
if (isColumn)
1323+
{
1324+
src_roi.col((int)i).copyTo(values_row);
1325+
dst_roi.col((int)i).copyTo(idx_row);
1326+
}
1327+
else
1328+
{
1329+
src_roi.row((int)i).copyTo(values_row);
1330+
dst_roi.row((int)i).copyTo(idx_row);
1331+
}
1332+
switch(type)
1333+
{
1334+
case CV_8U: check_<uchar>(values_row, idx_row); break;
1335+
case CV_8S: check_<char>(values_row, idx_row); break;
1336+
case CV_16S: check_<short>(values_row, idx_row); break;
1337+
case CV_32S: check_<int>(values_row, idx_row); break;
1338+
case CV_32F: check_<float>(values_row, idx_row); break;
1339+
case CV_64F: check_<double>(values_row, idx_row); break;
1340+
default: ASSERT_FALSE(true) << "Unsupported type: " << type;
1341+
}
1342+
}
1343+
}
1344+
};
1345+
1346+
TEST_P(sortIdx, simple)
1347+
{
1348+
for (int j = 0; j < 5; j++)
1349+
{
1350+
generateTestData();
1351+
1352+
cv::sortIdx(src_roi, dst_roi, flags);
1353+
validate();
1354+
}
1355+
}
1356+
1357+
INSTANTIATE_TEST_CASE_P(Core, sortIdx, Combine(
1358+
Values(CV_8U, CV_8S, CV_16S, CV_32S, CV_32F, CV_64F), // depth
1359+
Values(SORT_EVERY_COLUMN, SORT_EVERY_ROW),
1360+
Values(SORT_ASCENDING, SORT_DESCENDING),
1361+
Values(Size(3, 3), Size(16, 8)),
1362+
::testing::Bool()
1363+
));
1364+
1365+
1366+
TEST(Core_sortIdx, regression_8941)
1367+
{
1368+
cv::Mat src = (cv::Mat_<int>(3, 3) <<
1369+
1, 2, 3,
1370+
0, 9, 5,
1371+
8, 1, 6
1372+
);
1373+
cv::Mat expected = (cv::Mat_<int>(3, 1) <<
1374+
1,
1375+
0,
1376+
2
1377+
);
1378+
1379+
cv::Mat result;
1380+
cv::sortIdx(src.col(0), result, CV_SORT_EVERY_COLUMN | CV_SORT_ASCENDING);
1381+
#if 0
1382+
std::cout << src.col(0) << std::endl;
1383+
std::cout << result << std::endl;
1384+
#endif
1385+
ASSERT_EQ(expected.size(), result.size());
1386+
EXPECT_EQ(0, cvtest::norm(expected, result, NORM_INF)) <<
1387+
"result=" << std::endl << result << std::endl <<
1388+
"expected=" << std::endl << expected;
1389+
}
1390+
1391+
}} // namespace

modules/ts/include/opencv2/ts.hpp

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@
66

77
#include "cvconfig.h"
88

9+
#include <string>
10+
#include <iostream>
11+
#include <fstream>
12+
#include <sstream>
13+
#include <iterator>
14+
#include <limits>
15+
#include <numeric>
16+
917
#ifdef WINRT
1018
#pragma warning(disable:4447) // Disable warning 'main' signature found without threading model
1119
#endif
@@ -46,14 +54,10 @@ namespace cvtest
4654

4755
using std::vector;
4856
using std::string;
49-
using cv::RNG;
50-
using cv::Mat;
51-
using cv::Scalar;
52-
using cv::Size;
53-
using cv::Point;
54-
using cv::Rect;
55-
using cv::InputArray;
56-
using cv::noArray;
57+
using namespace cv;
58+
using testing::Values;
59+
using testing::Combine;
60+
5761

5862
class SkipTestException: public cv::Exception
5963
{
@@ -632,10 +636,12 @@ int main(int argc, char **argv) \
632636

633637
} //namespace cvtest
634638

635-
#endif // OPENCV_TS_HPP
636-
637639
#include "opencv2/ts/ts_perf.hpp"
638640

641+
namespace cvtest {
642+
using perf::MatDepth;
643+
}
644+
639645
#ifdef WINRT
640646
#ifndef __FSTREAM_EMULATED__
641647
#define __FSTREAM_EMULATED__
@@ -734,3 +740,5 @@ class ofstream : public stringstream
734740
} // namespace std
735741
#endif // __FSTREAM_EMULATED__
736742
#endif // WINRT
743+
744+
#endif // OPENCV_TS_HPP

modules/ts/include/opencv2/ts/cuda_test.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ namespace cvtest
109109

110110
CV_EXPORTS testing::AssertionResult assertMatNear(const char* expr1, const char* expr2, const char* eps_expr, cv::InputArray m1, cv::InputArray m2, double eps);
111111

112+
#undef EXPECT_MAT_NEAR
112113
#define EXPECT_MAT_NEAR(m1, m2, eps) EXPECT_PRED_FORMAT3(cvtest::assertMatNear, m1, m2, eps)
113114
#define ASSERT_MAT_NEAR(m1, m2, eps) ASSERT_PRED_FORMAT3(cvtest::assertMatNear, m1, m2, eps)
114115

@@ -153,6 +154,7 @@ namespace cvtest
153154

154155
CV_EXPORTS double checkSimilarity(cv::InputArray m1, cv::InputArray m2);
155156

157+
#undef EXPECT_MAT_SIMILAR
156158
#define EXPECT_MAT_SIMILAR(mat1, mat2, eps) \
157159
{ \
158160
ASSERT_EQ(mat1.type(), mat2.type()); \

modules/ts/include/opencv2/ts/ocl_test.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ do \
9494
EXPECT_LE(TestUtils::checkNorm1(mat), eps) \
9595
} while ((void)0, 0)
9696

97+
#undef EXPECT_MAT_NEAR
9798
#define EXPECT_MAT_NEAR(mat1, mat2, eps) \
9899
do \
99100
{ \
@@ -178,6 +179,7 @@ do \
178179
<< "Size: " << name ## _roi.size() << std::endl; \
179180
} while ((void)0, 0)
180181

182+
#undef EXPECT_MAT_SIMILAR
181183
#define EXPECT_MAT_SIMILAR(mat1, mat2, eps) \
182184
do \
183185
{ \
@@ -325,7 +327,7 @@ struct CV_EXPORTS TSTestWithParam : public TestUtils, public ::testing::TestWith
325327
};
326328

327329
#undef PARAM_TEST_CASE
328-
#define PARAM_TEST_CASE(name, ...) struct name : public TSTestWithParam< std::tr1::tuple< __VA_ARGS__ > >
330+
#define PARAM_TEST_CASE(name, ...) struct name : public ::cvtest::ocl::TSTestWithParam< std::tr1::tuple< __VA_ARGS__ > >
329331

330332
#ifndef IMPLEMENT_PARAM_CLASS
331333
#define IMPLEMENT_PARAM_CLASS(name, type) \

0 commit comments

Comments
 (0)