// 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. // // Copyright (C) 2018 Intel Corporation #include "test_precomp.hpp" #include "gapi_fluid_test_kernels.hpp" #include "common/gapi_tests_common.hpp" namespace opencv_test { using namespace cv::gapi_test_kernels; G_TYPED_KERNEL(TCopy, , "test.fluid.copy") { static GMatDesc outMeta(const cv::GMatDesc &in) { return in; } }; GAPI_FLUID_KERNEL(FCopy, TCopy, false) { static const int Window = 1; static void run(const cv::gapi::fluid::View &in, cv::gapi::fluid::Buffer &out) { const uint8_t* in_row = in .InLine (0); uint8_t* out_row = out.OutLine(); for (int i = 0, w = in.length(); i < w; i++) { //std::cout << std::setw(4) << int(in_row[i]); out_row[i] = in_row[i]; } //std::cout << std::endl; } }; GAPI_FLUID_KERNEL(FResizeNN1Lpi, cv::gapi::core::GResize, false) { static const int Window = 1; static const auto Kind = GFluidKernel::Kind::Resize; static void run(const cv::gapi::fluid::View& in, cv::Size /*sz*/, double /*fx*/, double /*fy*/, int /*interp*/, cv::gapi::fluid::Buffer& out) { auto length = out.length(); double vRatio = (double)in.meta().size.height / out.meta().size.height; double hRatio = (double)in.length() / length; auto y = out.y(); auto inY = in.y(); for (int l = 0; l < out.lpi(); l++) { auto sy = static_cast((y+l) * vRatio); int idx = sy - inY; const auto src = in.InLine (idx); auto dst = out.OutLine(l); for (int x = 0; x < length; x++) { auto inX = static_cast(x * hRatio); dst[x] = src[inX]; } } } }; namespace { namespace func { template void initScratch(const cv::GMatDesc& in, cv::Size outSz, cv::gapi::fluid::Buffer &scratch) { CV_Assert(in.depth == CV_8U && in.chan == 1); cv::Size scratch_size{static_cast(outSz.width * sizeof(typename Mapper::Unit)), 1}; cv::GMatDesc desc; desc.chan = 1; desc.depth = CV_8UC1; desc.size = scratch_size; cv::gapi::fluid::Buffer buffer(desc); scratch = std::move(buffer); auto mapX = scratch.OutLine(); double hRatio = (double)in.size.width / outSz.width; for (int x = 0, w = outSz.width; x < w; x++) { mapX[x] = Mapper::map(hRatio, 0, in.size.width, x); } } template inline void calcRow(const cv::gapi::fluid::View& in, cv::gapi::fluid::Buffer& out, cv::gapi::fluid::Buffer &scratch) { double vRatio = (double)in.meta().size.height / out.meta().size.height; auto mapX = scratch.OutLine(); auto inY = in.y(); auto inH = in.meta().size.height; auto outY = out.y(); auto length = out.length(); for (int l = 0; l < out.lpi(); l++) { auto mapY = Mapper::map(vRatio, inY, inH, outY + l); const auto src0 = in.InLine (mapY.s0); const auto src1 = in.InLine (mapY.s1); auto dst = out.OutLine(l); for (int x = 0; x < length; x++) { auto alpha0 = mapX[x].alpha0; auto alpha1 = mapX[x].alpha1; auto sx0 = mapX[x].s0; auto sx1 = mapX[x].s1; int res0 = src0[sx0]*alpha0 + src0[sx1]*alpha1; int res1 = src1[sx0]*alpha0 + src1[sx1]*alpha1; dst[x] = uchar(( ((mapY.alpha0 * (res0 >> 4)) >> 16) + ((mapY.alpha1 * (res1 >> 4)) >> 16) + 2)>>2); } } } } // namespace func constexpr static const int INTER_RESIZE_COEF_BITS = 11; constexpr static const int INTER_RESIZE_COEF_SCALE = 1 << INTER_RESIZE_COEF_BITS; namespace linear { struct Mapper { struct Unit { short alpha0; short alpha1; int s0; int s1; }; static inline Unit map(double ratio, int start, int max, int outCoord) { auto f = static_cast((outCoord + 0.5f) * ratio - 0.5f); int s = cvFloor(f); f -= s; Unit u; u.s0 = std::max(s - start, 0); u.s1 = ((f == 0.0) || s + 1 >= max) ? s - start : s - start + 1; u.alpha0 = saturate_cast((1.0f - f) * INTER_RESIZE_COEF_SCALE); u.alpha1 = saturate_cast((f) * INTER_RESIZE_COEF_SCALE); return u; } }; } // namespace linear namespace areaUpscale { struct Mapper { struct Unit { short alpha0; short alpha1; int s0; int s1; }; static inline Unit map(double ratio, int start, int max, int outCoord) { int s = cvFloor(outCoord*ratio); float f = (float)((outCoord+1) - (s+1)/ratio); f = f <= 0 ? 0.f : f - cvFloor(f); Unit u; u.s0 = std::max(s - start, 0); u.s1 = ((f == 0.0) || s + 1 >= max) ? s - start : s - start + 1; u.alpha0 = saturate_cast((1.0f - f) * INTER_RESIZE_COEF_SCALE); u.alpha1 = saturate_cast((f) * INTER_RESIZE_COEF_SCALE); return u; } }; } // namespace areaUpscale } // anonymous namespace GAPI_FLUID_KERNEL(FResizeLinear1Lpi, cv::gapi::core::GResize, true) { static const int Window = 1; static const auto Kind = GFluidKernel::Kind::Resize; static void initScratch(const cv::GMatDesc& in, cv::Size outSz, double /*fx*/, double /*fy*/, int /*interp*/, cv::gapi::fluid::Buffer &scratch) { func::initScratch(in, outSz, scratch); } static void resetScratch(cv::gapi::fluid::Buffer& /*scratch*/) {} static void run(const cv::gapi::fluid::View& in, cv::Size /*sz*/, double /*fx*/, double /*fy*/, int /*interp*/, cv::gapi::fluid::Buffer& out, cv::gapi::fluid::Buffer &scratch) { func::calcRow(in, out, scratch); } }; namespace { // FIXME // Move to some common place (to reuse/align with ResizeAgent) auto startInCoord = [](int outCoord, double ratio) { return static_cast(outCoord * ratio + 1e-3); }; auto endInCoord = [](int outCoord, double ratio) { return static_cast(std::ceil((outCoord + 1) * ratio - 1e-3)); }; } // namespace GAPI_FLUID_KERNEL(FResizeArea1Lpi, cv::gapi::core::GResize, false) { static const int Window = 1; static const auto Kind = GFluidKernel::Kind::Resize; static void run(const cv::gapi::fluid::View& in, cv::Size /*sz*/, double /*fx*/, double /*fy*/, int /*interp*/, cv::gapi::fluid::Buffer& out) { auto firstOutLineIdx = out.y(); auto firstViewLineIdx = in.y(); auto length = out.length(); double vRatio = (double)in.meta().size.height / out.meta().size.height; double hRatio = (double)in.length() / length; for (int l = 0; l < out.lpi(); l++) { int outY = firstOutLineIdx + l; int startY = startInCoord(outY, vRatio); int endY = endInCoord (outY, vRatio); auto dst = out.OutLine(l); for (int x = 0; x < length; x++) { float res = 0.0; int startX = startInCoord(x, hRatio); int endX = endInCoord (x, hRatio); for (int inY = startY; inY < endY; inY++) { double startCoordY = inY / vRatio; double endCoordY = startCoordY + 1/vRatio; if (startCoordY < outY) startCoordY = outY; if (endCoordY > outY + 1) endCoordY = outY + 1; float fracY = static_cast((inY == startY || inY == endY - 1) ? endCoordY - startCoordY : 1/vRatio); const auto src = in.InLine (inY - firstViewLineIdx); float rowSum = 0.0f; for (int inX = startX; inX < endX; inX++) { double startCoordX = inX / hRatio; double endCoordX = startCoordX + 1/hRatio; if (startCoordX < x) startCoordX = x; if (endCoordX > x + 1) endCoordX = x + 1; float fracX = static_cast((inX == startX || inX == endX - 1) ? endCoordX - startCoordX : 1/hRatio); rowSum += src[inX] * fracX; } res += rowSum * fracY; } dst[x] = static_cast(std::rint(res)); } } } }; GAPI_FLUID_KERNEL(FResizeAreaUpscale1Lpi, cv::gapi::core::GResize, true) { static const int Window = 1; static const auto Kind = GFluidKernel::Kind::Resize; static void initScratch(const cv::GMatDesc& in, cv::Size outSz, double /*fx*/, double /*fy*/, int /*interp*/, cv::gapi::fluid::Buffer &scratch) { func::initScratch(in, outSz, scratch); } static void resetScratch(cv::gapi::fluid::Buffer& /*scratch*/) {} static void run(const cv::gapi::fluid::View& in, cv::Size /*sz*/, double /*fx*/, double /*fy*/, int /*interp*/, cv::gapi::fluid::Buffer& out, cv::gapi::fluid::Buffer &scratch) { func::calcRow(in, out, scratch); } }; #define ADD_RESIZE_KERNEL_WITH_LPI(interp, lpi, scratch) \ struct Resize##interp##lpi##LpiHelper : public FResize##interp##1Lpi { static const int LPI = lpi; }; \ struct FResize##interp##lpi##Lpi : public cv::GFluidKernelImpl{}; ADD_RESIZE_KERNEL_WITH_LPI(NN, 2, false) ADD_RESIZE_KERNEL_WITH_LPI(NN, 3, false) ADD_RESIZE_KERNEL_WITH_LPI(NN, 4, false) ADD_RESIZE_KERNEL_WITH_LPI(Linear, 2, true) ADD_RESIZE_KERNEL_WITH_LPI(Linear, 3, true) ADD_RESIZE_KERNEL_WITH_LPI(Linear, 4, true) ADD_RESIZE_KERNEL_WITH_LPI(Area, 2, false) ADD_RESIZE_KERNEL_WITH_LPI(Area, 3, false) ADD_RESIZE_KERNEL_WITH_LPI(Area, 4, false) ADD_RESIZE_KERNEL_WITH_LPI(AreaUpscale, 2, true) ADD_RESIZE_KERNEL_WITH_LPI(AreaUpscale, 3, true) ADD_RESIZE_KERNEL_WITH_LPI(AreaUpscale, 4, true) #undef ADD_RESIZE_KERNEL_WITH_LPI static auto fluidResizeTestPackage = [](int interpolation, cv::Size szIn, cv::Size szOut, int lpi = 1) { using namespace cv; using namespace cv::gapi; bool upscale = szIn.width < szOut.width || szIn.height < szOut.height; #define RESIZE_CASE(interp, lpi) \ case lpi: pkg = kernels(); break; #define RESIZE_SWITCH(interp) \ switch(lpi) \ { \ RESIZE_CASE(interp, 1) \ RESIZE_CASE(interp, 2) \ RESIZE_CASE(interp, 3) \ RESIZE_CASE(interp, 4) \ default: CV_Assert(false); \ } GKernelPackage pkg; switch (interpolation) { case INTER_NEAREST: RESIZE_SWITCH(NN); break; case INTER_LINEAR: RESIZE_SWITCH(Linear); break; case INTER_AREA: { if (upscale) { RESIZE_SWITCH(AreaUpscale) } else { RESIZE_SWITCH(Area); } }break; default: CV_Assert(false); } return combine(pkg, fluidTestPackage); #undef RESIZE_SWITCH #undef RESIZE_CASE }; struct ResizeTestFluid : public TestWithParam, int, double>> {}; TEST_P(ResizeTestFluid, SanityTest) { int type = 0, interp = 0; cv::Size sz_in, sz_out; int lpi = 0; double tolerance = 0.0; cv::Rect outRoi; std::tuple outSizeAndRoi; std::tie(type, interp, sz_in, outSizeAndRoi, lpi, tolerance) = GetParam(); std::tie(sz_out, outRoi) = outSizeAndRoi; if (outRoi == cv::Rect{}) outRoi = {0,0,sz_out.width,sz_out.height}; if (outRoi.width == 0) outRoi.width = sz_out.width; double fx = 0, fy = 0; cv::Mat in_mat1 (sz_in, type ); cv::Scalar mean = cv::Scalar(127); cv::Scalar stddev = cv::Scalar(40.f); cv::randn(in_mat1, mean, stddev); cv::Mat out_mat = cv::Mat::zeros(sz_out, type); cv::Mat out_mat_ocv = cv::Mat::zeros(sz_out, type); cv::GMat in; auto mid = TBlur3x3::on(in, cv::BORDER_REPLICATE, {}); auto out = cv::gapi::resize(mid, sz_out, fx, fy, interp); cv::GComputation c(in, out); c.apply(in_mat1, out_mat, cv::compile_args(GFluidOutputRois{{outRoi}}, fluidResizeTestPackage(interp, sz_in, sz_out, lpi))); cv::Mat mid_mat; cv::blur(in_mat1, mid_mat, {3,3}, {-1,-1}, cv::BORDER_REPLICATE); cv::resize(mid_mat, out_mat_ocv, sz_out, fx, fy, interp); EXPECT_LE(cvtest::norm(out_mat(outRoi), out_mat_ocv(outRoi), NORM_INF), tolerance); } INSTANTIATE_TEST_CASE_P(ResizeTestCPU, ResizeTestFluid, Combine(Values(CV_8UC1), Values(cv::INTER_NEAREST, cv::INTER_LINEAR), Values(cv::Size(8, 7), cv::Size(8, 8), cv::Size(8, 64), cv::Size(8, 25), cv::Size(16, 8), cv::Size(16, 7)), Values(std::make_tuple(cv::Size(5, 4), cv::Rect{}), std::make_tuple(cv::Size(5, 4), cv::Rect{0, 0, 0, 2}), std::make_tuple(cv::Size(5, 4), cv::Rect{0, 1, 0, 2}), std::make_tuple(cv::Size(5, 4), cv::Rect{0, 2, 0, 2}), std::make_tuple(cv::Size(7, 7), cv::Rect{}), std::make_tuple(cv::Size(7, 7), cv::Rect{0, 0, 0, 3}), std::make_tuple(cv::Size(7, 7), cv::Rect{0, 2, 0, 2}), std::make_tuple(cv::Size(7, 7), cv::Rect{0, 4, 0, 3}), std::make_tuple(cv::Size(8, 4), cv::Rect{}), std::make_tuple(cv::Size(8, 4), cv::Rect{0, 0, 0, 3}), std::make_tuple(cv::Size(8, 4), cv::Rect{0, 1, 0, 2}), std::make_tuple(cv::Size(8, 4), cv::Rect{0, 3, 0, 1})), Values(1, 2, 3, 4), // lpi Values(0.0))); INSTANTIATE_TEST_CASE_P(ResizeAreaTestCPU, ResizeTestFluid, Combine(Values(CV_8UC1), Values(cv::INTER_AREA), Values(cv::Size(8, 7), cv::Size(8, 8), cv::Size(8, 64), cv::Size(8, 25), cv::Size(16, 8), cv::Size(16, 7)), Values(std::make_tuple(cv::Size(5, 4), cv::Rect{}), std::make_tuple(cv::Size(5, 4), cv::Rect{0, 0, 0, 2}), std::make_tuple(cv::Size(5, 4), cv::Rect{0, 1, 0, 2}), std::make_tuple(cv::Size(5, 4), cv::Rect{0, 2, 0, 2}), std::make_tuple(cv::Size(7, 7), cv::Rect{}), std::make_tuple(cv::Size(7, 7), cv::Rect{0, 0, 0, 3}), std::make_tuple(cv::Size(7, 7), cv::Rect{0, 2, 0, 2}), std::make_tuple(cv::Size(7, 7), cv::Rect{0, 4, 0, 3}), std::make_tuple(cv::Size(8, 4), cv::Rect{}), std::make_tuple(cv::Size(8, 4), cv::Rect{0, 0, 0, 3}), std::make_tuple(cv::Size(8, 4), cv::Rect{0, 1, 0, 2}), std::make_tuple(cv::Size(8, 4), cv::Rect{0, 3, 0, 1})), Values(1, 2, 3, 4), // lpi // Actually this tolerance only for cases where OpenCV // uses ResizeAreaFast Values(1.0))); INSTANTIATE_TEST_CASE_P(ResizeUpscaleTestCPU, ResizeTestFluid, Combine(Values(CV_8UC1), Values(cv::INTER_NEAREST, cv::INTER_LINEAR, cv::INTER_AREA), Values(cv::Size(1, 5), cv::Size(3, 5), cv::Size(7, 5), cv::Size(1, 7), cv::Size(3, 7), cv::Size(7, 7)), Values(std::make_tuple(cv::Size(8, 8), cv::Rect{0,0,8,2}), std::make_tuple(cv::Size(8, 8), cv::Rect{0,2,8,2}), std::make_tuple(cv::Size(8, 8), cv::Rect{0,4,8,2}), std::make_tuple(cv::Size(8, 8), cv::Rect{0,6,8,2}), std::make_tuple(cv::Size(8, 8), cv::Rect{0,0,8,8}), std::make_tuple(cv::Size(16, 8), cv::Rect{}), std::make_tuple(cv::Size(16, 64), cv::Rect{0, 0,16,16}), std::make_tuple(cv::Size(16, 64), cv::Rect{0,16,16,16}), std::make_tuple(cv::Size(16, 64), cv::Rect{0,32,16,16}), std::make_tuple(cv::Size(16, 64), cv::Rect{0,48,16,16}), std::make_tuple(cv::Size(16, 64), cv::Rect{0, 0,16,64}), std::make_tuple(cv::Size(16, 25), cv::Rect{0, 0,16, 7}), std::make_tuple(cv::Size(16, 25), cv::Rect{0, 7,16, 6}), std::make_tuple(cv::Size(16, 25), cv::Rect{0,13,16, 6}), std::make_tuple(cv::Size(16, 25), cv::Rect{0,19,16, 6}), std::make_tuple(cv::Size(16, 25), cv::Rect{0, 0,16, 7}), std::make_tuple(cv::Size(16, 25), cv::Rect{0, 7,16, 7}), std::make_tuple(cv::Size(16, 25), cv::Rect{0,14,16, 7}), std::make_tuple(cv::Size(16, 25), cv::Rect{0,21,16, 4}), std::make_tuple(cv::Size(16, 25), cv::Rect{0, 0,16,25}), std::make_tuple(cv::Size(16, 7), cv::Rect{}), std::make_tuple(cv::Size(16, 8), cv::Rect{})), Values(1, 2, 3, 4), // lpi Values(0.0))); INSTANTIATE_TEST_CASE_P(ResizeUpscaleOneDimDownscaleAnother, ResizeTestFluid, Combine(Values(CV_8UC1), Values(cv::INTER_NEAREST, cv::INTER_LINEAR, cv::INTER_AREA), Values(cv::Size(6, 6), cv::Size(8, 7), cv::Size(8, 8), cv::Size(8, 10), cv::Size(10, 8), cv::Size(10, 7)), Values(std::make_tuple(cv::Size(11, 5), cv::Rect{}), std::make_tuple(cv::Size(11, 5), cv::Rect{0, 0, 0, 2}), std::make_tuple(cv::Size(11, 5), cv::Rect{0, 2, 0, 2}), std::make_tuple(cv::Size(11, 5), cv::Rect{0, 4, 0, 1}), std::make_tuple(cv::Size(12, 2), cv::Rect{}), std::make_tuple(cv::Size(12, 2), cv::Rect{0, 0, 0, 1}), std::make_tuple(cv::Size(12, 2), cv::Rect{0, 1, 0, 1}), std::make_tuple(cv::Size(23, 3), cv::Rect{}), std::make_tuple(cv::Size(23, 3), cv::Rect{0, 0, 0, 1}), std::make_tuple(cv::Size(23, 3), cv::Rect{0, 1, 0, 1}), std::make_tuple(cv::Size(23, 3), cv::Rect{0, 2, 0, 1}), std::make_tuple(cv::Size(3, 24), cv::Rect{}), std::make_tuple(cv::Size(3, 24), cv::Rect{0, 0, 0, 6}), std::make_tuple(cv::Size(3, 24), cv::Rect{0, 6, 0, 6}), std::make_tuple(cv::Size(3, 24), cv::Rect{0, 12, 0, 6}), std::make_tuple(cv::Size(3, 24), cv::Rect{0, 18, 0, 6}), std::make_tuple(cv::Size(5, 11), cv::Rect{}), std::make_tuple(cv::Size(5, 11), cv::Rect{0, 0, 0, 3}), std::make_tuple(cv::Size(5, 11), cv::Rect{0, 3, 0, 3}), std::make_tuple(cv::Size(5, 11), cv::Rect{0, 6, 0, 3}), std::make_tuple(cv::Size(5, 11), cv::Rect{0, 9, 0, 2})), Values(1, 2, 3, 4), // lpi Values(0.0))); INSTANTIATE_TEST_CASE_P(Resize400_384TestCPU, ResizeTestFluid, Combine(Values(CV_8UC1), Values(cv::INTER_NEAREST, cv::INTER_LINEAR, cv::INTER_AREA), Values(cv::Size(128, 400)), Values(std::make_tuple(cv::Size(128, 384), cv::Rect{})), Values(1, 2, 3, 4), // lpi Values(0.0))); INSTANTIATE_TEST_CASE_P(Resize220_400TestCPU, ResizeTestFluid, Combine(Values(CV_8UC1), Values(cv::INTER_LINEAR), Values(cv::Size(220, 220)), Values(std::make_tuple(cv::Size(400, 400), cv::Rect{})), Values(1, 2, 3, 4), // lpi Values(0.0))); static auto cvBlur = [](const cv::Mat& in, cv::Mat& out, int kernelSize) { if (kernelSize == 1) { out = in; } else { cv::blur(in, out, {kernelSize, kernelSize}); } }; using SizesWithRois = std::tuple; struct ResizeAndAnotherReaderTest : public TestWithParam>{}; TEST_P(ResizeAndAnotherReaderTest, SanityTest) { bool readFromInput = false; int interp = -1, kernelSize = -1; SizesWithRois sizesWithRois; std::tie(interp, kernelSize, readFromInput, sizesWithRois) = GetParam(); cv::Size sz, resizedSz; cv::Rect roi, resizedRoi; std::tie(sz, roi, resizedSz, resizedRoi) = sizesWithRois; cv::Mat in_mat(sz, CV_8UC1); cv::Scalar mean = cv::Scalar(127); cv::Scalar stddev = cv::Scalar(40.f); cv::randn(in_mat, mean, stddev); cv::Mat gapi_resize_out = cv::Mat::zeros(resizedSz, CV_8UC1); cv::Mat gapi_blur_out = cv::Mat::zeros(sz, CV_8UC1); auto blur = kernelSize == 1 ? &TBlur1x1::on : kernelSize == 3 ? &TBlur3x3::on : &TBlur5x5::on; cv::GMat in, resize_out, blur_out; if (readFromInput) { resize_out = gapi::resize(in, resizedSz, 0, 0, interp); blur_out = blur(in, cv::BORDER_DEFAULT, {}); } else { auto mid = TCopy::on(in); resize_out = gapi::resize(mid, resizedSz, 0, 0, interp); blur_out = blur(mid, cv::BORDER_DEFAULT, {}); } cv::GComputation c(GIn(in), GOut(resize_out, blur_out)); c.apply(gin(in_mat), gout(gapi_resize_out, gapi_blur_out), cv::compile_args(GFluidOutputRois{{resizedRoi, roi}}, fluidResizeTestPackage(interp, sz, resizedSz))); cv::Mat ocv_resize_out = cv::Mat::zeros(resizedSz, CV_8UC1); cv::resize(in_mat, ocv_resize_out, resizedSz, 0, 0, interp); cv::Mat ocv_blur_out = cv::Mat::zeros(sz, CV_8UC1); cvBlur(in_mat, ocv_blur_out, kernelSize); EXPECT_EQ(0, cvtest::norm(gapi_resize_out(resizedRoi), ocv_resize_out(resizedRoi), NORM_INF)); EXPECT_EQ(0, cvtest::norm(gapi_blur_out(roi), ocv_blur_out(roi), NORM_INF)); } INSTANTIATE_TEST_CASE_P(ResizeTestCPU, ResizeAndAnotherReaderTest, Combine(Values(cv::INTER_NEAREST, cv::INTER_LINEAR), Values(1, 3, 5), testing::Bool(), // Read from input directly or place a copy node at start Values(std::make_tuple(cv::Size{8,8}, cv::Rect{0,0,8,8}, cv::Size{4,4}, cv::Rect{0,0,4,4}), std::make_tuple(cv::Size{8,8}, cv::Rect{0,0,8,2}, cv::Size{4,4}, cv::Rect{0,0,4,1}), std::make_tuple(cv::Size{8,8}, cv::Rect{0,2,8,4}, cv::Size{4,4}, cv::Rect{0,1,4,2}), std::make_tuple(cv::Size{8,8}, cv::Rect{0,4,8,4}, cv::Size{4,4}, cv::Rect{0,2,4,2}), std::make_tuple(cv::Size{64,64}, cv::Rect{0, 0,64,64}, cv::Size{49,49}, cv::Rect{0, 0,49,49}), std::make_tuple(cv::Size{64,64}, cv::Rect{0, 0,64,15}, cv::Size{49,49}, cv::Rect{0, 0,49,11}), std::make_tuple(cv::Size{64,64}, cv::Rect{0,11,64,23}, cv::Size{49,49}, cv::Rect{0, 9,49,17}), std::make_tuple(cv::Size{64,64}, cv::Rect{0,50,64,14}, cv::Size{49,49}, cv::Rect{0,39,49,10})))); struct BlursAfterResizeTest : public TestWithParam>>{}; TEST_P(BlursAfterResizeTest, SanityTest) { bool readFromInput = false; int interp = -1, kernelSize1 = -1, kernelSize2 = -1; std::tuple sizesWithRoi; std::tie(interp, kernelSize1, kernelSize2, readFromInput, sizesWithRoi) = GetParam(); cv::Size inSz, outSz; cv::Rect outRoi; std::tie(inSz, outSz, outRoi) = sizesWithRoi; cv::Mat in_mat(inSz, CV_8UC1); cv::Scalar mean = cv::Scalar(127); cv::Scalar stddev = cv::Scalar(40.f); cv::randn(in_mat, mean, stddev); cv::Mat gapi_out1 = cv::Mat::zeros(outSz, CV_8UC1); cv::Mat gapi_out2 = cv::Mat::zeros(outSz, CV_8UC1); auto blur1 = kernelSize1 == 1 ? &TBlur1x1::on : kernelSize1 == 3 ? &TBlur3x3::on : &TBlur5x5::on; auto blur2 = kernelSize2 == 1 ? &TBlur1x1::on : kernelSize2 == 3 ? &TBlur3x3::on : &TBlur5x5::on; cv::GMat in, out1, out2; if (readFromInput) { auto resized = gapi::resize(in, outSz, 0, 0, interp); out1 = blur1(resized, cv::BORDER_DEFAULT, {}); out2 = blur2(resized, cv::BORDER_DEFAULT, {}); } else { auto mid = TCopy::on(in); auto resized = gapi::resize(mid, outSz, 0, 0, interp); out1 = blur1(resized, cv::BORDER_DEFAULT, {}); out2 = blur2(resized, cv::BORDER_DEFAULT, {}); } cv::GComputation c(GIn(in), GOut(out1, out2)); c.apply(gin(in_mat), gout(gapi_out1, gapi_out2), cv::compile_args(GFluidOutputRois{{outRoi, outRoi}}, fluidResizeTestPackage(interp, inSz, outSz))); cv::Mat ocv_out1 = cv::Mat::zeros(outSz, CV_8UC1); cv::Mat ocv_out2 = cv::Mat::zeros(outSz, CV_8UC1); cv::Mat resized = cv::Mat::zeros(outSz, CV_8UC1); cv::resize(in_mat, resized, outSz, 0, 0, interp); cvBlur(resized, ocv_out1, kernelSize1); cvBlur(resized, ocv_out2, kernelSize2); EXPECT_EQ(0, cvtest::norm(gapi_out1(outRoi), ocv_out1(outRoi), NORM_INF)); EXPECT_EQ(0, cvtest::norm(gapi_out2(outRoi), ocv_out2(outRoi), NORM_INF)); } INSTANTIATE_TEST_CASE_P(ResizeTestCPU, BlursAfterResizeTest, Combine(Values(cv::INTER_NEAREST, cv::INTER_LINEAR), Values(1, 3, 5), Values(1, 3, 5), testing::Bool(), // Read from input directly or place a copy node at start Values(std::make_tuple(cv::Size{8,8}, cv::Size{4,4}, cv::Rect{0,0,4,4}), std::make_tuple(cv::Size{8,8}, cv::Size{4,4}, cv::Rect{0,0,4,1}), std::make_tuple(cv::Size{8,8}, cv::Size{4,4}, cv::Rect{0,1,4,2}), std::make_tuple(cv::Size{8,8}, cv::Size{4,4}, cv::Rect{0,2,4,2}), std::make_tuple(cv::Size{64,64}, cv::Size{49,49}, cv::Rect{0, 0,49,49}), std::make_tuple(cv::Size{64,64}, cv::Size{49,49}, cv::Rect{0, 0,49,11}), std::make_tuple(cv::Size{64,64}, cv::Size{49,49}, cv::Rect{0, 9,49,17}), std::make_tuple(cv::Size{64,64}, cv::Size{49,49}, cv::Rect{0,39,49,10})))); struct NV12PlusResizeTest : public TestWithParam > {}; TEST_P(NV12PlusResizeTest, Test) { cv::Size y_sz, out_sz; cv::Rect roi; std::tie(y_sz, out_sz, roi) = GetParam(); int interp = cv::INTER_LINEAR; cv::Size uv_sz(y_sz.width / 2, y_sz.height / 2); cv::Size in_sz(y_sz.width, y_sz.height*3/2); cv::Mat in_mat = cv::Mat(in_sz, CV_8UC1); cv::Scalar mean = cv::Scalar(127.0f); cv::Scalar stddev = cv::Scalar(40.f); cv::randn(in_mat, mean, stddev); cv::Mat y_mat = cv::Mat(y_sz, CV_8UC1, in_mat.data); cv::Mat uv_mat = cv::Mat(uv_sz, CV_8UC2, in_mat.data + in_mat.step1() * y_sz.height); cv::Mat out_mat, out_mat_ocv; cv::GMat y, uv; auto rgb = cv::gapi::NV12toRGB(y, uv); auto out = cv::gapi::resize(rgb, out_sz, 0, 0, interp); cv::GComputation c(cv::GIn(y, uv), cv::GOut(out)); auto pkg = cv::gapi::combine(fluidTestPackage, cv::gapi::core::fluid::kernels()); c.apply(cv::gin(y_mat, uv_mat), cv::gout(out_mat) ,cv::compile_args(pkg, cv::GFluidOutputRois{{roi}})); cv::Mat rgb_mat; cv::cvtColor(in_mat, rgb_mat, cv::COLOR_YUV2RGB_NV12); cv::resize(rgb_mat, out_mat_ocv, out_sz, 0, 0, interp); EXPECT_TRUE(Tolerance_FloatRel_IntAbs(1e-5, 1).to_compare_f()(out_mat(roi), out_mat_ocv(roi))); } INSTANTIATE_TEST_CASE_P(Fluid, NV12PlusResizeTest, Values(std::make_tuple(cv::Size{8, 8}, cv::Size{4, 4}, cv::Rect{0, 0, 4, 4}) ,std::make_tuple(cv::Size{8, 8}, cv::Size{4, 4}, cv::Rect{0, 0, 4, 1}) ,std::make_tuple(cv::Size{8, 8}, cv::Size{4, 4}, cv::Rect{0, 1, 4, 2}) ,std::make_tuple(cv::Size{8, 8}, cv::Size{4, 4}, cv::Rect{0, 2, 4, 2}) ,std::make_tuple(cv::Size{64, 64}, cv::Size{49, 49}, cv::Rect{0, 0, 49, 49}) ,std::make_tuple(cv::Size{64, 64}, cv::Size{49, 49}, cv::Rect{0, 0, 49, 12}) ,std::make_tuple(cv::Size{64, 64}, cv::Size{49, 49}, cv::Rect{0, 11, 49, 15}) ,std::make_tuple(cv::Size{64, 64}, cv::Size{49, 49}, cv::Rect{0, 39, 49, 10}) ,std::make_tuple(cv::Size{1920, 1080}, cv::Size{ 320, 256}, cv::Rect{0, 0, 320, 64}) ,std::make_tuple(cv::Size{1920, 1080}, cv::Size{ 320, 256}, cv::Rect{0, 64, 320, 64}) ,std::make_tuple(cv::Size{1920, 1080}, cv::Size{ 320, 256}, cv::Rect{0, 128, 320, 64}) ,std::make_tuple(cv::Size{1920, 1080}, cv::Size{ 320, 256}, cv::Rect{0, 192, 320, 64}) ,std::make_tuple(cv::Size{256, 400}, cv::Size{ 32, 64}, cv::Rect{0, 0, 32, 16}) ,std::make_tuple(cv::Size{256, 400}, cv::Size{ 32, 64}, cv::Rect{0, 16, 32, 16}) ,std::make_tuple(cv::Size{256, 400}, cv::Size{ 32, 64}, cv::Rect{0, 32, 32, 16}) ,std::make_tuple(cv::Size{256, 400}, cv::Size{ 32, 64}, cv::Rect{0, 48, 32, 16}) )); struct Preproc4lpiTest : public TestWithParam >{}; TEST_P(Preproc4lpiTest, Test) { using namespace gapi_test_kernels; cv::Size y_sz, out_sz; cv::Rect roi; std::tie(y_sz, out_sz, roi) = GetParam(); int interp = cv::INTER_LINEAR; cv::Size uv_sz(y_sz.width / 2, y_sz.height / 2); cv::Size in_sz(y_sz.width, y_sz.height*3/2); cv::Mat in_mat = cv::Mat(in_sz, CV_8UC1); cv::randn(in_mat, cv::Scalar::all(127.0f), cv::Scalar::all(40.f)); cv::Mat y_mat = cv::Mat(y_sz, CV_8UC1, in_mat.data); cv::Mat uv_mat = cv::Mat(uv_sz, CV_8UC2, in_mat.data + in_mat.step1() * y_sz.height); cv::Mat out_mat, out_mat_ocv; cv::GMat y, uv; auto rgb = cv::gapi::NV12toRGB(y, uv); auto splitted = split3_4lpi(rgb); cv::GMat resized[3] = { cv::gapi::resize(std::get<0>(splitted), out_sz, 0, 0, interp) , cv::gapi::resize(std::get<1>(splitted), out_sz, 0, 0, interp) , cv::gapi::resize(std::get<2>(splitted), out_sz, 0, 0, interp) }; auto out = merge3_4lpi(resized[0], resized[1], resized[2]); cv::GComputation c(cv::GIn(y, uv), cv::GOut(out)); auto pkg = cv::gapi::combine(cv::gapi::core::fluid::kernels(), fluidResizeTestPackage(interp, in_sz, out_sz, 4)); c.apply(cv::gin(y_mat, uv_mat), cv::gout(out_mat) ,cv::compile_args(pkg, cv::GFluidOutputRois{{roi}})); cv::Mat rgb_mat; cv::cvtColor(in_mat, rgb_mat, cv::COLOR_YUV2RGB_NV12); cv::resize(rgb_mat, out_mat_ocv, out_sz, 0, 0, interp); EXPECT_EQ(0, cvtest::norm(out_mat(roi), out_mat_ocv(roi), NORM_INF)); } INSTANTIATE_TEST_CASE_P(Fluid, Preproc4lpiTest, Values(std::make_tuple(cv::Size{8, 8}, cv::Size{4, 4}, cv::Rect{0, 0, 4, 4}) ,std::make_tuple(cv::Size{8, 8}, cv::Size{4, 4}, cv::Rect{0, 0, 4, 1}) ,std::make_tuple(cv::Size{8, 8}, cv::Size{4, 4}, cv::Rect{0, 1, 4, 2}) ,std::make_tuple(cv::Size{8, 8}, cv::Size{4, 4}, cv::Rect{0, 2, 4, 2}) ,std::make_tuple(cv::Size{24, 24}, cv::Size{12, 12}, cv::Rect{0, 0, 12, 3}) ,std::make_tuple(cv::Size{24, 24}, cv::Size{12, 12}, cv::Rect{0, 3, 12, 3}) ,std::make_tuple(cv::Size{64, 64}, cv::Size{49, 49}, cv::Rect{0, 0, 49, 49}) ,std::make_tuple(cv::Size{64, 64}, cv::Size{49, 49}, cv::Rect{0, 0, 49, 12}) ,std::make_tuple(cv::Size{64, 64}, cv::Size{49, 49}, cv::Rect{0, 11, 49, 15}) ,std::make_tuple(cv::Size{64, 64}, cv::Size{49, 49}, cv::Rect{0, 39, 49, 10}) ,std::make_tuple(cv::Size{640, 480}, cv::Size{300, 199}, cv::Rect{0, 0, 300, 50}) ,std::make_tuple(cv::Size{640, 480}, cv::Size{300, 199}, cv::Rect{0, 50, 300, 50}) ,std::make_tuple(cv::Size{640, 480}, cv::Size{300, 199}, cv::Rect{0, 100, 300, 50}) ,std::make_tuple(cv::Size{640, 480}, cv::Size{300, 199}, cv::Rect{0, 150, 300, 49}) )); } // namespace opencv_test