From f2422ace7dc0c0e1f995d8f2c940997f81146cb7 Mon Sep 17 00:00:00 2001 From: Anastasia Murzova Date: Thu, 10 Dec 2020 14:27:23 +0300 Subject: [PATCH] Added TF nearest neighbour resize behaviour alignment Relates to OpenCV issue #18721 --- modules/dnn/src/layers/resize_layer.cpp | 50 ++++++++++++++++++++++++- modules/dnn/test/test_tf_importer.cpp | 13 +++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/modules/dnn/src/layers/resize_layer.cpp b/modules/dnn/src/layers/resize_layer.cpp index 792d84d357..a41e20a666 100644 --- a/modules/dnn/src/layers/resize_layer.cpp +++ b/modules/dnn/src/layers/resize_layer.cpp @@ -115,7 +115,7 @@ public: Mat& inp = inputs[0]; Mat& out = outputs[0]; - if (interpolation == "nearest" || interpolation == "opencv_linear" || (interpolation == "bilinear" && halfPixelCenters)) + if ((interpolation == "nearest" && !alignCorners && !halfPixelCenters) || interpolation == "opencv_linear" || (interpolation == "bilinear" && halfPixelCenters)) { InterpolationFlags mode = interpolation == "nearest" ? INTER_NEAREST : INTER_LINEAR; for (size_t n = 0; n < inputs[0].size[0]; ++n) @@ -127,6 +127,54 @@ public: } } } + else if (interpolation == "nearest") + { + const int inpHeight = inp.size[2]; + const int inpWidth = inp.size[3]; + const int inpSpatialSize = inpHeight * inpWidth; + const int outSpatialSize = outHeight * outWidth; + const int numPlanes = inp.size[0] * inp.size[1]; + CV_Assert_N(inp.isContinuous(), out.isContinuous()); + + Mat inpPlanes = inp.reshape(1, numPlanes * inpHeight); + Mat outPlanes = out.reshape(1, numPlanes * outHeight); + + float heightOffset = 0.0f; + float widthOffset = 0.0f; + + if (halfPixelCenters) + { + heightOffset = 0.5f * scaleHeight; + widthOffset = 0.5f * scaleWidth; + } + + for (int y = 0; y < outHeight; ++y) + { + float input_y = y * scaleHeight + heightOffset; + int y0 = halfPixelCenters ? std::floor(input_y) : lroundf(input_y); + y0 = std::min(y0, inpHeight - 1); + + const float* inpData_row = inpPlanes.ptr(y0); + + for (int x = 0; x < outWidth; ++x) + { + float input_x = x * scaleWidth + widthOffset; + int x0 = halfPixelCenters ? std::floor(input_x) : lroundf(input_x); + x0 = std::min(x0, inpWidth - 1); + + float* outData = outPlanes.ptr(y, x); + const float* inpData_row_c = inpData_row; + + for (int c = 0; c < numPlanes; ++c) + { + *outData = inpData_row_c[x0]; + + inpData_row_c += inpSpatialSize; + outData += outSpatialSize; + } + } + } + } else if (interpolation == "bilinear") { const int inpHeight = inp.size[2]; diff --git a/modules/dnn/test/test_tf_importer.cpp b/modules/dnn/test/test_tf_importer.cpp index a5a736d08f..f8b09047c8 100644 --- a/modules/dnn/test/test_tf_importer.cpp +++ b/modules/dnn/test/test_tf_importer.cpp @@ -920,6 +920,19 @@ TEST_P(Test_TensorFlow_layers, resize_nearest_neighbor) runTensorFlowNet("keras_upsampling2d"); } +TEST_P(Test_TensorFlow_layers, resize_nearest_neighbor_align_corners) +{ + runTensorFlowNet("resize_nearest_neighbor", false, 0.0, 0.0, false, "_align_corners"); +} + +TEST_P(Test_TensorFlow_layers, resize_nearest_neighbor_half_pixel) +{ + if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) + applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_NGRAPH); + + runTensorFlowNet("resize_nearest_neighbor", false, 0.0, 0.0, false, "_half_pixel"); +} + TEST_P(Test_TensorFlow_layers, fused_resize_conv) { runTensorFlowNet("fused_resize_conv"); -- GitLab