diff --git a/modules/core/perf/perf_arithm.cpp b/modules/core/perf/perf_arithm.cpp index cd5a750cc5..d8b65e1a08 100644 --- a/modules/core/perf/perf_arithm.cpp +++ b/modules/core/perf/perf_arithm.cpp @@ -436,7 +436,22 @@ PERF_TEST_P_(BinaryOpTest, transpose2d) SANITY_CHECK_NOTHING(); } -PERF_TEST_P_(BinaryOpTest, transposeND) +static cv::Mat makeTransposeNDOutput(const cv::Mat& src, const std::vector& order) +{ + std::vector new_sz(order.size()); + for (size_t i = 0; i < order.size(); ++i) + new_sz[i] = src.size[order[i]]; + return Mat(static_cast(new_sz.size()), new_sz.data(), src.type()); +} + +static cv::Mat makeTransposeNDInput3D(Size sz, int type) +{ + const int channels = CV_MAT_CN(type); + int dims[] = { sz.height, sz.width, channels }; + return Mat(3, dims, CV_MAKETYPE(CV_MAT_DEPTH(type), 1)); +} + +PERF_TEST_P_(BinaryOpTest, transposeND_identity_order) { Size sz = get<0>(GetParam()); int type = get<1>(GetParam()); @@ -444,14 +459,64 @@ PERF_TEST_P_(BinaryOpTest, transposeND) std::vector order(a.dims); std::iota(order.begin(), order.end(), 0); - std::reverse(order.begin(), order.end()); - std::vector new_sz(a.dims); - std::copy(a.size.p, a.size.p + a.dims, new_sz.begin()); - std::reverse(new_sz.begin(), new_sz.end()); - cv::Mat b = Mat(new_sz, type); + cv::Mat b = makeTransposeNDOutput(a, order); - declare.in(a,WARMUP_RNG).out(b); + declare.in(a, WARMUP_RNG).out(b); + + TEST_CYCLE() cv::transposeND(a, order, b); + + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P_(BinaryOpTest, transposeND_2d_swap_order) +{ + Size sz = get<0>(GetParam()); + int type = get<1>(GetParam()); + cv::Mat a = Mat(sz, type).reshape(1); + + std::vector order{1, 0}; + + cv::Mat b = makeTransposeNDOutput(a, order); + + declare.in(a, WARMUP_RNG).out(b); + + TEST_CYCLE() cv::transposeND(a, order, b); + + SANITY_CHECK_NOTHING(); +} + + +PERF_TEST_P_(BinaryOpTest, transposeND_generic_keep_tail_order) +{ + Size sz = get<0>(GetParam()); + int type = get<1>(GetParam()); + cv::Mat a = makeTransposeNDInput3D(sz, type); + + std::vector order{1, 0, 2}; + + cv::Mat b = makeTransposeNDOutput(a, order); + + randu(a, 0, 255); + declare.in(a).out(b); + + TEST_CYCLE() cv::transposeND(a, order, b); + + SANITY_CHECK_NOTHING(); +} + +PERF_TEST_P_(BinaryOpTest, transposeND_generic_move_tail_order) +{ + Size sz = get<0>(GetParam()); + int type = get<1>(GetParam()); + cv::Mat a = makeTransposeNDInput3D(sz, type); + + std::vector order{2, 0, 1}; + + cv::Mat b = makeTransposeNDOutput(a, order); + + randu(a, 0, 255); + declare.in(a).out(b); TEST_CYCLE() cv::transposeND(a, order, b); diff --git a/modules/core/src/matrix_transform.cpp b/modules/core/src/matrix_transform.cpp index e53462fdf8..fd9485d271 100644 --- a/modules/core/src/matrix_transform.cpp +++ b/modules/core/src/matrix_transform.cpp @@ -551,6 +551,33 @@ void transposeND(InputArray src_, const std::vector& order, OutputArray dst CV_CheckEQ(inp.channels(), 1, "Input array should be single-channel"); CV_CheckEQ(order.size(), static_cast(inp.dims), "Number of dimensions shouldn't change"); + bool isIdentityOrder = true; + for (size_t i = 0; i < order.size(); ++i) + { + if (order[i] != static_cast(i)) + { + isIdentityOrder = false; + break; + } + } + if (isIdentityOrder) + { + dst_.create(inp.dims, inp.size.p, inp.type()); + Mat out = dst_.getMat(); + CV_Assert(out.isContinuous()); + + if (inp.data != out.data) + inp.copyTo(out); + return; + } + + const bool is2DSwap = inp.dims == 2 && order.size() == 2 && order[0] == 1 && order[1] == 0; + if (is2DSwap) + { + transpose(inp, dst_); + return; + } + auto order_ = order; std::sort(order_.begin(), order_.end()); for (size_t i = 0; i < order_.size(); ++i)