Added TF nearest neighbour resize behaviour alignment
authorAnastasia Murzova <anastasia.murzova@xperience.ai>
Thu, 10 Dec 2020 11:27:23 +0000 (14:27 +0300)
committerAnastasia Murzova <anastasia.murzova@xperience.ai>
Thu, 10 Dec 2020 12:53:24 +0000 (15:53 +0300)
Relates to OpenCV issue #18721

modules/dnn/src/layers/resize_layer.cpp
modules/dnn/test/test_tf_importer.cpp

index 792d84d..a41e20a 100644 (file)
@@ -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<float>(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<float>(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];
index a5a736d..f8b0904 100644 (file)
@@ -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");