From 005f38fb453fbcf593ab25fe0fa0c2d87e47862e Mon Sep 17 00:00:00 2001 From: Dmitry Kurtaev Date: Mon, 3 Feb 2020 18:54:59 +0300 Subject: [PATCH] Fix dnn::ResizeLayer to manage varying input shapes --- modules/dnn/src/layers/resize_layer.cpp | 91 ++++--------------------- modules/dnn/test/test_layers.cpp | 31 +++++++++ 2 files changed, 45 insertions(+), 77 deletions(-) diff --git a/modules/dnn/src/layers/resize_layer.cpp b/modules/dnn/src/layers/resize_layer.cpp index 88ad078fe0..593a896042 100644 --- a/modules/dnn/src/layers/resize_layer.cpp +++ b/modules/dnn/src/layers/resize_layer.cpp @@ -19,7 +19,9 @@ namespace cv { namespace dnn { class ResizeLayerImpl : public ResizeLayer { public: - ResizeLayerImpl(const LayerParams& params) : zoomFactorWidth(0), zoomFactorHeight(0), scaleWidth(0), scaleHeight(0) + ResizeLayerImpl(const LayerParams& params) : zoomFactorWidth(params.get("zoom_factor_x", params.get("zoom_factor", 0))), + zoomFactorHeight(params.get("zoom_factor_y", params.get("zoom_factor", 0))), + scaleWidth(0), scaleHeight(0) { setParamsFrom(params); outWidth = params.get("width", 0); @@ -27,13 +29,10 @@ public: if (params.has("zoom_factor")) { CV_Assert(!params.has("zoom_factor_x") && !params.has("zoom_factor_y")); - zoomFactorWidth = zoomFactorHeight = params.get("zoom_factor"); } else if (params.has("zoom_factor_x") || params.has("zoom_factor_y")) { CV_Assert(params.has("zoom_factor_x") && params.has("zoom_factor_y")); - zoomFactorWidth = params.get("zoom_factor_x"); - zoomFactorHeight = params.get("zoom_factor_y"); } interpolation = params.get("interpolation"); CV_Assert(interpolation == "nearest" || interpolation == "bilinear"); @@ -48,8 +47,8 @@ public: { CV_Assert_N(inputs.size() == 1, inputs[0].size() == 4); outputs.resize(1, inputs[0]); - outputs[0][2] = outHeight > 0 ? outHeight : (outputs[0][2] * zoomFactorHeight); - outputs[0][3] = outWidth > 0 ? outWidth : (outputs[0][3] * zoomFactorWidth); + outputs[0][2] = zoomFactorHeight > 0 ? (outputs[0][2] * zoomFactorHeight) : outHeight; + outputs[0][3] = zoomFactorWidth > 0 ? (outputs[0][3] * zoomFactorWidth) : outWidth; // We can work in-place (do nothing) if input shape == output shape. return (outputs[0][2] == inputs[0][2]) && (outputs[0][3] == inputs[0][3]); } @@ -73,11 +72,8 @@ public: inputs_arr.getMatVector(inputs); outputs_arr.getMatVector(outputs); - if (!outWidth && !outHeight) - { - outHeight = outputs[0].size[2]; - outWidth = outputs[0].size[3]; - } + outHeight = outputs[0].size[2]; + outWidth = outputs[0].size[3]; if (alignCorners && outHeight > 1) scaleHeight = static_cast(inputs[0].size[2] - 1) / (outHeight - 1); else @@ -184,7 +180,7 @@ public: ieLayer.setType("Interp"); ieLayer.getParameters()["pad_beg"] = 0; ieLayer.getParameters()["pad_end"] = 0; - ieLayer.getParameters()["align_corners"] = false; + ieLayer.getParameters()["align_corners"] = alignCorners; } else CV_Error(Error::StsNotImplemented, "Unsupported interpolation: " + interpolation); @@ -208,7 +204,7 @@ public: attrs.pads_begin.push_back(0); attrs.pads_end.push_back(0); attrs.axes = ngraph::AxisSet{2, 3}; - attrs.align_corners = false; + attrs.align_corners = alignCorners; if (interpolation == "nearest") { attrs.mode = "nearest"; @@ -227,7 +223,8 @@ public: #endif // HAVE_DNN_NGRAPH protected: - int outWidth, outHeight, zoomFactorWidth, zoomFactorHeight; + int outWidth, outHeight; + const int zoomFactorWidth, zoomFactorHeight; String interpolation; float scaleWidth, scaleHeight; bool alignCorners; @@ -251,78 +248,18 @@ public: { CV_Assert_N(inputs.size() == 1, inputs[0].size() == 4); outputs.resize(1, inputs[0]); - outputs[0][2] = outHeight > 0 ? outHeight : (1 + zoomFactorHeight * (outputs[0][2] - 1)); - outputs[0][3] = outWidth > 0 ? outWidth : (1 + zoomFactorWidth * (outputs[0][3] - 1)); + outputs[0][2] = zoomFactorHeight > 0 ? (1 + zoomFactorHeight * (outputs[0][2] - 1)) : outHeight; + outputs[0][3] = zoomFactorWidth > 0 ? (1 + zoomFactorWidth * (outputs[0][3] - 1)) : outWidth; // We can work in-place (do nothing) if input shape == output shape. return (outputs[0][2] == inputs[0][2]) && (outputs[0][3] == inputs[0][3]); } - - virtual bool supportBackend(int backendId) CV_OVERRIDE - { -#ifdef HAVE_INF_ENGINE - if (backendId == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 - || backendId == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) - return true; -#endif - return backendId == DNN_BACKEND_OPENCV; - } - - virtual void finalize(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr) CV_OVERRIDE - { - std::vector inputs, outputs; - inputs_arr.getMatVector(inputs); - outputs_arr.getMatVector(outputs); - - if (!outWidth && !outHeight) - { - outHeight = outputs[0].size[2]; - outWidth = outputs[0].size[3]; - } - int inpHeight = inputs[0].size[2]; - int inpWidth = inputs[0].size[3]; - scaleHeight = (outHeight > 1) ? (static_cast(inpHeight - 1) / (outHeight - 1)) : 0.f; - scaleWidth = (outWidth > 1) ? (static_cast(inpWidth - 1) / (outWidth - 1)) : 0.f; - } - -#ifdef HAVE_INF_ENGINE - virtual Ptr initInfEngine(const std::vector >&) CV_OVERRIDE - { - InferenceEngine::Builder::Layer ieLayer(name); - ieLayer.setName(name); - ieLayer.setType("Interp"); - ieLayer.getParameters()["pad_beg"] = 0; - ieLayer.getParameters()["pad_end"] = 0; - ieLayer.getParameters()["width"] = outWidth; - ieLayer.getParameters()["height"] = outHeight; - ieLayer.setInputPorts(std::vector(1)); - ieLayer.setOutputPorts(std::vector(1)); - return Ptr(new InfEngineBackendNode(ieLayer)); - } -#endif // HAVE_INF_ENGINE - -#ifdef HAVE_DNN_NGRAPH - virtual Ptr initNgraph(const std::vector >& inputs, - const std::vector >& nodes) CV_OVERRIDE - { - auto& ieInpNode = nodes[0].dynamicCast()->node; - ngraph::op::InterpolateAttrs attrs; - attrs.pads_begin.push_back(0); - attrs.pads_end.push_back(0); - attrs.axes = ngraph::AxisSet{2, 3}; - attrs.mode = "linear"; - std::vector shape = {outHeight, outWidth}; - auto out_shape = std::make_shared(ngraph::element::i64, ngraph::Shape{2}, shape.data()); - auto interp = std::make_shared(ieInpNode, out_shape, attrs); - return Ptr(new InfEngineNgraphNode(interp)); - } -#endif // HAVE_DNN_NGRAPH - }; Ptr InterpLayer::create(const LayerParams& params) { LayerParams lp(params); lp.set("interpolation", "bilinear"); + lp.set("align_corners", true); return Ptr(new InterpLayerImpl(lp)); } diff --git a/modules/dnn/test/test_layers.cpp b/modules/dnn/test/test_layers.cpp index 0d61f7af1b..72b0a555b3 100644 --- a/modules/dnn/test/test_layers.cpp +++ b/modules/dnn/test/test_layers.cpp @@ -1715,4 +1715,35 @@ INSTANTIATE_TEST_CASE_P(/**/, Layer_Test_Eltwise_unequal, Combine( dnnBackendsAndTargets() )); +typedef testing::TestWithParam > Layer_Test_Resize; +TEST_P(Layer_Test_Resize, change_input) +{ + int backendId = get<0>(GetParam()); + int targetId = get<1>(GetParam()); + + Net net; + LayerParams lp; + lp.type = "Resize"; + lp.name = "testLayer"; + lp.set("zoom_factor", 2); + lp.set("interpolation", "nearest"); + net.addLayerToPrev(lp.name, lp.type, lp); + + for (int i = 0; i < 2; ++i) + { + Mat inp(4 + i, 5 + i, CV_8UC3), ref; + randu(inp, 0, 255); + resize(inp, ref, Size(0, 0), 2, 2, INTER_NEAREST); + ref = blobFromImage(ref); + + net.setInput(blobFromImage(inp)); + net.setPreferableBackend(backendId); + net.setPreferableTarget(targetId); + Mat out = net.forward(); + normAssert(out, ref); + } +} + +INSTANTIATE_TEST_CASE_P(/**/, Layer_Test_Resize, dnnBackendsAndTargets()); + }} // namespace