COMPMID-1253: Nightly: Fix Canny Edge NEON failing

Change-Id: If0836522792717a843c1cab405afc9320ce53079
Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/137162
Tested-by: Jenkins <bsgcomp@arm.com>
Reviewed-by: Anthony Barbier <anthony.barbier@arm.com>
diff --git a/src/runtime/NEON/functions/NECannyEdge.cpp b/src/runtime/NEON/functions/NECannyEdge.cpp
index 1d73148..d72c98b 100644
--- a/src/runtime/NEON/functions/NECannyEdge.cpp
+++ b/src/runtime/NEON/functions/NECannyEdge.cpp
@@ -66,7 +66,7 @@
     ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(output, 1, DataType::U8);
     ARM_COMPUTE_ERROR_ON((1 != norm_type) && (2 != norm_type));
     ARM_COMPUTE_ERROR_ON((gradient_size != 3) && (gradient_size != 5) && (gradient_size != 7));
-    ARM_COMPUTE_ERROR_ON(lower_thr > upper_thr);
+    ARM_COMPUTE_ERROR_ON((lower_thr < 0) || (lower_thr >= upper_thr));
 
     _output = output;
 
diff --git a/tests/validation/Helpers.cpp b/tests/validation/Helpers.cpp
index 521cc57..e2415a2 100644
--- a/tests/validation/Helpers.cpp
+++ b/tests/validation/Helpers.cpp
@@ -141,7 +141,7 @@
 
     params.constant_border_value = int_dist(gen);
     params.upper_thresh          = threshold_dist(gen); // upper_threshold >= 1
-    threshold_dist               = std::uniform_int_distribution<uint8_t>(0, params.upper_thresh);
+    threshold_dist               = std::uniform_int_distribution<uint8_t>(1, params.upper_thresh - 1);
     params.lower_thresh          = threshold_dist(gen);
 
     return params;
diff --git a/tests/validation/reference/CannyEdgeDetector.cpp b/tests/validation/reference/CannyEdgeDetector.cpp
index 45b244f..6fe4544 100644
--- a/tests/validation/reference/CannyEdgeDetector.cpp
+++ b/tests/validation/reference/CannyEdgeDetector.cpp
@@ -49,38 +49,57 @@
 const auto MARK_MAYBE = 127u;
 const auto MARK_EDGE  = 255u;
 
-template <typename U, typename T, typename F>
-void trace_edge(SimpleTensor<T> &dst, SimpleTensor<U> &grad_mag, const ValidRegion &valid_region, std::vector<bool> &visited, uint32_t upper_thresh, const F &pixel_at_offset)
+template <typename T>
+void trace_edge(SimpleTensor<T> &dst)
 {
+    std::stack<Coordinates> pixels_stack;
     for(auto i = 0; i < dst.num_elements(); ++i)
     {
-        Coordinates coord;
-        if(visited[i] || dst[i] != MARK_MAYBE || !is_in_valid_region(valid_region, coord = index2coord(dst.shape(), i)))
+        if(dst[i] == MARK_EDGE)
         {
-            continue; // Skip visited or confirmed ZERO/EDGE pixels
+            pixels_stack.push(index2coord(dst.shape(), i));
         }
-        visited[i] = true; // Mark as visited
+    }
 
-        // Check if connected to a strong edge pixel
-        std::array<U, 8> neighbours =
+    while(!pixels_stack.empty())
+    {
+        const Coordinates pixel_coord = pixels_stack.top();
+        pixels_stack.pop();
+
+        std::array<Coordinates, 8> neighbours =
         {
             {
-                pixel_at_offset(grad_mag, coord, -1, 0),
-                pixel_at_offset(grad_mag, coord, 1, 0),
-                pixel_at_offset(grad_mag, coord, -1, -1),
-                pixel_at_offset(grad_mag, coord, +1, +1),
-                pixel_at_offset(grad_mag, coord, 0, -1),
-                pixel_at_offset(grad_mag, coord, 0, +1),
-                pixel_at_offset(grad_mag, coord, +1, -1),
-                pixel_at_offset(grad_mag, coord, -1, +1)
+                Coordinates(pixel_coord.x() - 1, pixel_coord.y() + 0),
+                Coordinates(pixel_coord.x() + 1, pixel_coord.y() + 0),
+                Coordinates(pixel_coord.x() - 1, pixel_coord.y() - 1),
+                Coordinates(pixel_coord.x() + 1, pixel_coord.y() + 1),
+                Coordinates(pixel_coord.x() + 0, pixel_coord.y() - 1),
+                Coordinates(pixel_coord.x() + 0, pixel_coord.y() + 1),
+                Coordinates(pixel_coord.x() + 1, pixel_coord.y() - 1),
+                Coordinates(pixel_coord.x() - 1, pixel_coord.y() + 1)
             }
         };
 
-        const auto is_edge_connected = std::any_of(neighbours.begin(), neighbours.end(), [&](const U & pixel)
+        // Mark MAYBE neighbours as edges since they are next to an EDGE
+        std::for_each(neighbours.begin(), neighbours.end(), [&](Coordinates & coord)
         {
-            return pixel >= upper_thresh;
+            const size_t pixel_index = coord2index(dst.shape(), coord);
+            const T      pixel       = dst[pixel_index];
+            if(pixel == MARK_MAYBE)
+            {
+                dst[pixel_index] = MARK_EDGE;
+                pixels_stack.push(coord);
+            }
         });
-        dst[i] = is_edge_connected ? MARK_EDGE : MARK_ZERO;
+    }
+
+    // Mark all remaining MAYBE pixels as ZERO (not edges)
+    for(auto i = 0; i < dst.num_elements(); ++i)
+    {
+        if(dst[i] == MARK_MAYBE)
+        {
+            dst[i] = MARK_ZERO;
+        }
     }
 }
 
@@ -202,8 +221,7 @@
     }
 
     // Final edge tracing
-    std::vector<bool> visited(dst.num_elements(), false);
-    trace_edge<unsigned_U>(dst, grad_mag, valid_region, visited, upper_thresh, pixel_at_offset);
+    trace_edge<T>(dst);
     return dst;
 }
 } // namespace