diff --git a/modules/gapi/include/opencv2/gapi/own/assert.hpp b/modules/gapi/include/opencv2/gapi/own/assert.hpp index d50543fdac..4bd3eaaf50 100644 --- a/modules/gapi/include/opencv2/gapi/own/assert.hpp +++ b/modules/gapi/include/opencv2/gapi/own/assert.hpp @@ -43,7 +43,6 @@ namespace detail #define GAPI_Assert(expr) \ { if (!(expr)) ::detail::assert_abort(#expr, __LINE__, __FILE__, __func__); } - #ifdef NDEBUG # define GAPI_DbgAssert(expr) GAPI_DbgAssertNoOp(expr) #else diff --git a/modules/gapi/perf/cpu/gapi_imgproc_perf_tests_fluid.cpp b/modules/gapi/perf/cpu/gapi_imgproc_perf_tests_fluid.cpp index b5e72ae4ce..a768875f32 100644 --- a/modules/gapi/perf/cpu/gapi_imgproc_perf_tests_fluid.cpp +++ b/modules/gapi/perf/cpu/gapi_imgproc_perf_tests_fluid.cpp @@ -201,7 +201,7 @@ INSTANTIATE_TEST_CASE_P(RGB2LabPerfTestFluid, RGB2LabPerfTest, INSTANTIATE_TEST_CASE_P(ResizePerfTestFluid, ResizePerfTest, Combine(Values(Tolerance_FloatRel_IntAbs(1e-5, 1).to_compare_f()), - Values(CV_8UC3), + Values(CV_8UC3, CV_32FC1), Values(cv::INTER_LINEAR), Values(szSmall128, szVGA, sz720p, sz1080p), Values(cv::Size(64, 64), @@ -217,7 +217,7 @@ INSTANTIATE_TEST_CASE_P(BottleneckKernelsPerfTestFluid, BottleneckKernelsConstIn INSTANTIATE_TEST_CASE_P(ResizeInSimpleGraphPerfTestFluid, ResizeInSimpleGraphPerfTest, Combine(Values(Tolerance_FloatRel_IntAbs(1e-5, 1).to_compare_f()), - Values(CV_8UC3), + Values(CV_8UC3, CV_32FC1), Values(szSmall128, szVGA, sz720p, sz1080p), Values(0.5), Values(0.5), @@ -225,7 +225,7 @@ INSTANTIATE_TEST_CASE_P(ResizeInSimpleGraphPerfTestFluid, ResizeInSimpleGraphPer INSTANTIATE_TEST_CASE_P(ResizeFxFyPerfTestFluid, ResizeFxFyPerfTest, Combine(Values(Tolerance_FloatRel_IntAbs(1e-5, 1).to_compare_f()), - Values(CV_8UC3), + Values(CV_8UC3, CV_32FC1), Values(cv::INTER_LINEAR), Values(szSmall128, szVGA, sz720p, sz1080p), Values(0.5, 0.25, 2), diff --git a/modules/gapi/src/backends/fluid/gfluidimgproc.cpp b/modules/gapi/src/backends/fluid/gfluidimgproc.cpp index aca2dcca6f..a2805b35aa 100644 --- a/modules/gapi/src/backends/fluid/gfluidimgproc.cpp +++ b/modules/gapi/src/backends/fluid/gfluidimgproc.cpp @@ -1866,10 +1866,11 @@ static inline double ratio(int inSz, int outSz) { } template -static inline void initScratchLinear(const cv::GMatDesc& in, - const Size& outSz, - cv::gapi::fluid::Buffer& scratch, - int lpi) { +CV_ALWAYS_INLINE void initScratchLinear(const cv::GMatDesc& in, + const Size& outSz, + cv::gapi::fluid::Buffer& scratch, + int lpi) +{ using alpha_type = typename Mapper::alpha_type; static const auto unity = Mapper::unity; @@ -1895,7 +1896,8 @@ static inline void initScratchLinear(const cv::GMatDesc& in, auto *clone = scr.clone; auto *index = scr.mapsx; - for (int x = 0; x < outSz.width; x++) { + for (int x = 0; x < outSz.width; ++x) + { auto map = Mapper::map(hRatio, 0, in.size.width, x); auto alpha0 = map.alpha0; auto index0 = map.index0; @@ -1930,7 +1932,7 @@ static inline void initScratchLinear(const cv::GMatDesc& in, alpha[x] = alpha0; index[x] = index0; - for (int l = 0; l < 4; l++) { + for (int l = 0; l < 4; ++l) { clone[4*x + l] = alpha0; } } @@ -1952,10 +1954,18 @@ struct MapperUnit { I index0, index1; }; -inline static uint8_t calc(short alpha0, uint8_t src0, short alpha1, uint8_t src1) { +CV_ALWAYS_INLINE uint8_t resize_calc_revert_fixedpoint(short alpha0, uint8_t src0, short alpha1, uint8_t src1) +{ constexpr static const int half = 1 << 14; return (src0 * alpha0 + src1 * alpha1 + half) >> 15; } + +CV_ALWAYS_INLINE float resize_main_calculation(float alpha0, float src0, float alpha1, float src1) +{ + return src0 * alpha0 + src1 * alpha1; +} + +namespace linear { struct Mapper { constexpr static const int ONE = 1 << 15; typedef short alpha_type; @@ -1980,11 +1990,38 @@ struct Mapper { return u; } }; +} // namespace linear + +namespace linear32f { +struct Mapper { + typedef float alpha_type; + typedef int index_type; + constexpr static const float unity = 1; + + typedef MapperUnit Unit; + + static inline Unit map(double ratio, int start, int max, int outCoord) { + float f = static_cast((outCoord + 0.5) * ratio - 0.5); + int s = cvFloor(f); + f -= s; + + Unit u; + + u.index0 = std::max(s - start, 0); + u.index1 = ((std::fabs(f) <= FLT_EPSILON) || s + 1 >= max) ? s - start : s - start + 1; + + u.alpha0 = 1.f - f; + u.alpha1 = f; + + return u; + } +}; +} // namespace linear32f template -static void calcRowLinearC(const cv::gapi::fluid::View & in, - cv::gapi::fluid::Buffer& out, - cv::gapi::fluid::Buffer& scratch) { +CV_ALWAYS_INLINE void calcRowLinearC(const cv::gapi::fluid::View & in, + cv::gapi::fluid::Buffer& out, + cv::gapi::fluid::Buffer& scratch) { using alpha_type = typename Mapper::alpha_type; auto inSz = in.meta().size; @@ -2052,14 +2089,74 @@ static void calcRowLinearC(const cv::gapi::fluid::View & in, for (int c = 0; c < numChan; c++) { auto idx0 = numChan*sx0 + c; auto idx1 = numChan*sx1 + c; - T tmp0 = calc(beta0, src0[l][idx0], beta1, src1[l][idx0]); - T tmp1 = calc(beta0, src0[l][idx1], beta1, src1[l][idx1]); - dst[l][numChan * x + c] = calc(alpha0, tmp0, alpha1, tmp1); + T tmp0 = resize_calc_revert_fixedpoint(beta0, src0[l][idx0], beta1, src1[l][idx0]); + T tmp1 = resize_calc_revert_fixedpoint(beta0, src0[l][idx1], beta1, src1[l][idx1]); + dst[l][numChan * x + c] = resize_calc_revert_fixedpoint(alpha0, tmp0, alpha1, tmp1); } } } } +template +CV_ALWAYS_INLINE void calcRowLinear(const cv::gapi::fluid::View& in, + cv::gapi::fluid::Buffer& out, + cv::gapi::fluid::Buffer& scratch) +{ + GAPI_DbgAssert((out.meta().depth == CV_32F) && (out.meta().chan == 1)); + + auto inSz = in.meta().size; + auto outSz = out.meta().size; + + auto inY = in.y(); + int length = out.length(); + int outY = out.y(); + int lpi = out.lpi(); + GAPI_DbgAssert(outY + lpi <= outSz.height); + + GAPI_DbgAssert(lpi <= 4); + + LinearScratchDesc scr(inSz.width, inSz.height, outSz.width, + outSz.height, scratch.OutLineB()); + + const auto* alpha = scr.alpha; + const auto* mapsx = scr.mapsx; + const auto* beta0 = scr.beta; + const auto* mapsy = scr.mapsy; + + const auto* beta = beta0 + outY; + const float* src0[4]; + const float* src1[4]; + float* dst[4]; + + for (int l = 0; l < lpi; ++l) + { + auto index0 = mapsy[outY + l] - inY; + auto index1 = mapsy[outSz.height + outY + l] - inY; + src0[l] = in.InLine(index0); + src1[l] = in.InLine(index1); + dst[l] = out.OutLine(l); + } + + using alpha_type = typename Mapper::alpha_type; + for (int l = 0; l < lpi; ++l) + { + constexpr static const auto unity = Mapper::unity; + + auto b0 = beta[l]; + auto b1 = saturate_cast(unity - beta[l]); + + for (int x = 0; x < length; ++x) { + auto alpha0 = alpha[x]; + auto alpha1 = saturate_cast(unity - alpha[x]); + auto sx0 = mapsx[x]; + auto sx1 = sx0 + 1; + float tmp0 = resize_main_calculation(b0, src0[l][sx0], b1, src1[l][sx0]); + float tmp1 = resize_main_calculation(b0, src0[l][sx1], b1, src1[l][sx1]); + dst[l][x] = resize_main_calculation(alpha0, tmp0, alpha1, tmp1); + } + } +} + GAPI_FLUID_KERNEL(GFluidResize, cv::gapi::imgproc::GResize, true) { static const int Window = 1; @@ -2071,9 +2168,12 @@ GAPI_FLUID_KERNEL(GFluidResize, cv::gapi::imgproc::GResize, true) constexpr static const short ONE = INTER_RESIZE_COEF_SCALE; static void initScratch(const cv::GMatDesc& in, - cv::Size outSz, double fx, double fy, int /*interp*/, + cv::Size outSz, double fx, double fy, int interp, cv::gapi::fluid::Buffer &scratch) - { + { + GAPI_Assert((in.depth == CV_8U && in.chan == 3) || + (in.depth == CV_32F && in.chan == 1)); + GAPI_Assert(interp == cv::INTER_LINEAR); int outSz_w; int outSz_h; if (outSz.width == 0 || outSz.height == 0) @@ -2088,32 +2188,44 @@ GAPI_FLUID_KERNEL(GFluidResize, cv::gapi::imgproc::GResize, true) } cv::Size outSize(outSz_w, outSz_h); - if (in.chan == 3) + if (in.depth == CV_8U && in.chan == 3) { - initScratchLinear(in, outSize, scratch, LPI); + initScratchLinear(in, outSize, scratch, LPI); } - else if (in.chan == 4) + else if (in.depth == CV_32F && in.chan == 1) { - initScratchLinear(in, outSize, scratch, LPI); + initScratchLinear(in, outSize, scratch, LPI); } - } + else + { + CV_Error(cv::Error::StsBadArg, "unsupported combination of type and number of channel"); + } + } 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) { + 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) + { + GAPI_Assert((in.meta().depth == CV_8U && in.meta().chan == 3) || + (in.meta().depth == CV_32F && in.meta().chan == 1)); + GAPI_Assert(interp == cv::INTER_LINEAR); const int channels = in.meta().chan; - GAPI_Assert((channels == 3 || channels == 4) && (interp == cv::INTER_LINEAR)); + const int depth = in.meta().depth; - if (channels == 3) + if (depth == CV_8U && channels == 3) + { + calcRowLinearC(in, out, scratch); + } + else if (depth == CV_32F && channels == 1) { - calcRowLinearC(in, out, scratch); + calcRowLinear(in, out, scratch); } - else if (channels == 4) + else { - calcRowLinearC(in, out, scratch); + CV_Error(cv::Error::StsBadArg, "unsupported combination of type and number of channel"); } } };