// This file is part of OpenCV project. // It is subject to the license terms in the LICENSE file found in the top-level directory // of this distribution and at http://opencv.org/license.html. #include "test_precomp.hpp" namespace opencv_test { namespace { template class GpuMatNDTest : public ::testing::Test { public: using MatType = Mat_; using CnType = typename Mat_::channel_type; static constexpr int cn = DataType::channels; using SizeArray = GpuMatND::SizeArray; static MatType RandomMat(const SizeArray& size) { const auto dims = static_cast(size.size()); MatType ret(dims, size.data()); for (ElemType& elem : ret) for (int i = 0; i < cn; ++i) elem[i] = cv::randu(); return ret; } static std::vector RandomRange(const SizeArray& size) { const auto dims = static_cast(size.size()); std::vector ret; const auto margin = cv::randu() & 0x1 + 1; // 1 or 2 for (int s : size) if (s > margin * 2) ret.emplace_back(margin, s-margin); else ret.push_back(Range::all()); if (dims == 1) { // Mat expects two ranges even in this case ret.push_back(Range::all()); } return ret; } static std::vector RandomRange2D(const SizeArray& size) { const auto dims = static_cast(size.size()); std::vector ret = RandomRange(size); for (int i = 0; i < dims - 2; ++i) { const auto start = cv::randu() % size[i]; ret[i] = Range(static_cast(start), static_cast(start) + 1); } return ret; } static void doTest1(const SizeArray& size) { const MatType gold = RandomMat(size); MatType dst; GpuMatND gmat; // simple upload, download test for GpuMatND gmat.upload(gold); gmat.download(dst); EXPECT_TRUE(std::equal(gold.begin(), gold.end(), dst.begin())); } static void doTest2(const SizeArray& size) { const MatType gold = RandomMat(size); const std::vector ranges = RandomRange(size); const MatType goldSub = gold(ranges); MatType dst; GpuMatND gmat; // upload partial mat, download it, and compare gmat.upload(goldSub); gmat.download(dst); EXPECT_TRUE(std::equal(goldSub.begin(), goldSub.end(), dst.begin())); // upload full mat, extract partial mat from it, download it, and compare gmat.upload(gold); gmat = gmat(ranges); gmat.download(dst); EXPECT_TRUE(std::equal(goldSub.begin(), goldSub.end(), dst.begin())); } static void doTest3(const SizeArray& size) { if (std::is_same::value) // GpuMat::convertTo is not implemented for CV_16F return; const MatType gold = RandomMat(size); const std::vector ranges = RandomRange2D(size); MatType dst; GpuMatND gmat; // Test GpuMatND to GpuMat conversion: // extract a 2D-plane and set its elements in the extracted region to 1 // compare the values of the full mat between Mat and GpuMatND gmat.upload(gold); GpuMat plane = gmat(ranges).createGpuMatHeader(); EXPECT_TRUE(!plane.refcount); // plane points to externally allocated memory(a part of gmat) const GpuMat dummy = plane.clone(); EXPECT_TRUE(dummy.refcount); // dummy is clone()-ed from plane, so it manages its memory // currently, plane(GpuMat) points to a sub-matrix of gmat(GpuMatND) // in this case, dummy and plane have same size and type, // so plane does not get reallocated inside convertTo, // so this convertTo sets a sub-matrix region of gmat to 1 dummy.convertTo(plane, -1, 0, 1); EXPECT_TRUE(!plane.refcount); // plane still points to externally allocated memory(a part of gmat) gmat.download(dst); // set a sub-matrix region of gold to 1 Mat plane_ = gold(ranges); const Mat dummy_ = plane_.clone(); dummy_.convertTo(plane_, -1, 0, 1); EXPECT_TRUE(std::equal(gold.begin(), gold.end(), dst.begin())); } static void doTest4(const SizeArray& size) { if (std::is_same::value) // GpuMat::convertTo is not implemented for CV_16F return; const MatType gold = RandomMat(size); const std::vector ranges = RandomRange2D(size); MatType dst; GpuMatND gmat; // Test handling external memory gmat.upload(gold); const GpuMatND external(gmat.size, gmat.type(), gmat.getDevicePtr(), {gmat.step.begin(), gmat.step.end() - 1}); // set a sub-matrix region of external to 2 GpuMat plane = external(ranges).createGpuMatHeader(); const GpuMat dummy = plane.clone(); dummy.convertTo(plane, -1, 0, 2); external.download(dst); // set a sub-matrix region of gold to 2 Mat plane_ = gold(ranges); const Mat dummy_ = plane_.clone(); dummy_.convertTo(plane_, -1, 0, 2); EXPECT_TRUE(std::equal(gold.begin(), gold.end(), dst.begin())); } static void doTest5(const SizeArray& size) { if (std::is_same::value) // GpuMat::convertTo is not implemented for CV_16F return; const MatType gold = RandomMat(size); const std::vector ranges = RandomRange(size); MatType goldSub = gold(ranges); MatType dst; GpuMatND gmat; // Upload a sub-mat, set a sub-region of the sub-mat to 3, download, and compare gmat.upload(goldSub); const std::vector rangesInRanges = RandomRange2D(gmat.size); GpuMat plane = gmat(rangesInRanges).createGpuMatHeader(); const GpuMat dummy = plane.clone(); dummy.convertTo(plane, -1, 0, 3); gmat.download(dst); Mat plane_ = goldSub(rangesInRanges); const Mat dummy_ = plane_.clone(); dummy_.convertTo(plane_, -1, 0, 3); EXPECT_TRUE(std::equal(goldSub.begin(), goldSub.end(), dst.begin())); } }; using ElemTypes = ::testing::Types< Vec, Vec, Vec, Vec, // CV_8U Vec, Vec, Vec, Vec, // CV_8S Vec, Vec, Vec, Vec, // CV_16U Vec, Vec, Vec, Vec, // CV_16S Vec, Vec, Vec, Vec, // CV_32S Vec, Vec, Vec, Vec, // CV_32F Vec, Vec, Vec, Vec, //CV_64F Vec, Vec, Vec, Vec // CV_16F >; using SizeArray = GpuMatND::SizeArray; #define DIFFERENT_SIZES_ND std::vector{ \ SizeArray{2, 1}, SizeArray{3, 2, 1}, SizeArray{1, 3, 2, 1}, SizeArray{2, 1, 3, 2, 1}, SizeArray{3, 2, 1, 3, 2, 1}, \ SizeArray{1}, SizeArray{1, 1}, SizeArray{1, 1, 1}, SizeArray{1, 1, 1, 1}, \ SizeArray{4}, SizeArray{4, 4}, SizeArray{4, 4, 4}, SizeArray{4, 4, 4, 4}, \ SizeArray{11}, SizeArray{13, 11}, SizeArray{17, 13, 11}, SizeArray{19, 17, 13, 11}} TYPED_TEST_CASE(GpuMatNDTest, ElemTypes); TYPED_TEST(GpuMatNDTest, Test1) { for (auto& size : DIFFERENT_SIZES_ND) GpuMatNDTest::doTest1(size); } TYPED_TEST(GpuMatNDTest, Test2) { for (auto& size : DIFFERENT_SIZES_ND) GpuMatNDTest::doTest2(size); } TYPED_TEST(GpuMatNDTest, Test3) { for (auto& size : DIFFERENT_SIZES_ND) GpuMatNDTest::doTest3(size); } TYPED_TEST(GpuMatNDTest, Test4) { for (auto& size : DIFFERENT_SIZES_ND) GpuMatNDTest::doTest4(size); } TYPED_TEST(GpuMatNDTest, Test5) { for (auto& size : DIFFERENT_SIZES_ND) GpuMatNDTest::doTest5(size); } }} // namespace