arm_compute v18.02
[platform/upstream/armcl.git] / src / core / CL / cl_kernels / canny.cl
1 /*
2  * Copyright (c) 2017 ARM Limited.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 #include "helpers.h"
25
26 /** Calculate the magnitude and phase from horizontal and vertical result of sobel result.
27  *
28  * @note The calculation of gradient uses level 1 normalisation.
29  * @attention The input and output data types need to be passed at compile time using -DDATA_TYPE_IN and -DDATA_TYPE_OUT:
30  * e.g. -DDATA_TYPE_IN=uchar -DDATA_TYPE_OUT=short
31  *
32  * @param[in]  src1_ptr                            Pointer to the source image (Vertical result of Sobel). Supported data types: S16, S32
33  * @param[in]  src1_stride_x                       Stride of the source image in X dimension (in bytes)
34  * @param[in]  src1_step_x                         src1_stride_x * number of elements along X processed per workitem(in bytes)
35  * @param[in]  src1_stride_y                       Stride of the source image in Y dimension (in bytes)
36  * @param[in]  src1_step_y                         src1_stride_y * number of elements along Y processed per workitem(in bytes)
37  * @param[in]  src1_offset_first_element_in_bytes  The offset of the first element in the source image
38  * @param[in]  src2_ptr                            Pointer to the source image (Vertical result of Sobel). Supported data types: S16, S32
39  * @param[in]  src2_stride_x                       Stride of the source image in X dimension (in bytes)
40  * @param[in]  src2_step_x                         src2_stride_x * number of elements along X processed per workitem(in bytes)
41  * @param[in]  src2_stride_y                       Stride of the source image in Y dimension (in bytes)
42  * @param[in]  src2_step_y                         src2_stride_y * number of elements along Y processed per workitem(in bytes)
43  * @param[in]  src2_offset_first_element_in_bytes  The offset of the first element in the source image
44  * @param[out] grad_ptr                            Pointer to the gradient output. Supported data types: U16, U32
45  * @param[in]  grad_stride_x                       Stride of the source image in X dimension (in bytes)
46  * @param[in]  grad_step_x                         grad_stride_x * number of elements along X processed per workitem(in bytes)
47  * @param[in]  grad_stride_y                       Stride of the source image in Y dimension (in bytes)
48  * @param[in]  grad_step_y                         grad_stride_y * number of elements along Y processed per workitem(in bytes)
49  * @param[in]  grad_offset_first_element_in_bytes  The offset of the first element of the output
50  * @param[out] angle_ptr                           Pointer to the angle output. Supported data types: U8
51  * @param[in]  angle_stride_x                      Stride of the source image in X dimension (in bytes)
52  * @param[in]  angle_step_x                        angle_stride_x * number of elements along X processed per workitem(in bytes)
53  * @param[in]  angle_stride_y                      Stride of the source image in Y dimension (in bytes)
54  * @param[in]  angle_step_y                        angle_stride_y * number of elements along Y processed per workitem(in bytes)
55  * @param[in]  angle_offset_first_element_in_bytes The offset of the first element of the output
56  */
57 __kernel void combine_gradients_L1(
58     IMAGE_DECLARATION(src1),
59     IMAGE_DECLARATION(src2),
60     IMAGE_DECLARATION(grad),
61     IMAGE_DECLARATION(angle))
62 {
63     // Construct images
64     Image src1  = CONVERT_TO_IMAGE_STRUCT(src1);
65     Image src2  = CONVERT_TO_IMAGE_STRUCT(src2);
66     Image grad  = CONVERT_TO_IMAGE_STRUCT(grad);
67     Image angle = CONVERT_TO_IMAGE_STRUCT(angle);
68
69     // Load sobel horizontal and vertical values
70     VEC_DATA_TYPE(DATA_TYPE_IN, 4)
71     h = vload4(0, (__global DATA_TYPE_IN *)src1.ptr);
72     VEC_DATA_TYPE(DATA_TYPE_IN, 4)
73     v = vload4(0, (__global DATA_TYPE_IN *)src2.ptr);
74
75     /* Calculate the gradient, using level 1 normalisation method */
76     VEC_DATA_TYPE(DATA_TYPE_OUT, 4)
77     m = CONVERT_SAT((abs(h) + abs(v)), VEC_DATA_TYPE(DATA_TYPE_OUT, 4));
78
79     /* Calculate the angle */
80     float4 p = atan2pi(convert_float4(v), convert_float4(h));
81
82     /* Remap angle to range [0, 256) */
83     p = select(p, p + 2, p < 0.0f) * 128.0f;
84
85     /* Store results */
86     vstore4(m, 0, (__global DATA_TYPE_OUT *)grad.ptr);
87     vstore4(convert_uchar4_sat_rte(p), 0, angle.ptr);
88 }
89
90 /** Calculate the gradient and angle from horizontal and vertical result of sobel result.
91  *
92  * @note The calculation of gradient uses level 2 normalisation
93  * @attention The input and output data types need to be passed at compile time using -DDATA_TYPE_IN and -DDATA_TYPE_OUT:
94  * e.g. -DDATA_TYPE_IN=uchar -DDATA_TYPE_OUT=short
95  *
96  * @param[in]  src1_ptr                            Pointer to the source image (Vertical result of Sobel). Supported data types: S16, S32
97  * @param[in]  src1_stride_x                       Stride of the source image in X dimension (in bytes)
98  * @param[in]  src1_step_x                         src1_stride_x * number of elements along X processed per workitem(in bytes)
99  * @param[in]  src1_stride_y                       Stride of the source image in Y dimension (in bytes)
100  * @param[in]  src1_step_y                         src1_stride_y * number of elements along Y processed per workitem(in bytes)
101  * @param[in]  src1_offset_first_element_in_bytes  The offset of the first element in the source image
102  * @param[in]  src2_ptr                            Pointer to the source image (Vertical result of Sobel). Supported data types: S16, S32
103  * @param[in]  src2_stride_x                       Stride of the source image in X dimension (in bytes)
104  * @param[in]  src2_step_x                         src2_stride_x * number of elements along X processed per workitem(in bytes)
105  * @param[in]  src2_stride_y                       Stride of the source image in Y dimension (in bytes)
106  * @param[in]  src2_step_y                         src2_stride_y * number of elements along Y processed per workitem(in bytes)
107  * @param[in]  src2_offset_first_element_in_bytes  The offset of the first element in the source image
108  * @param[out] grad_ptr                            Pointer to the gradient output. Supported data types: U16, U32
109  * @param[in]  grad_stride_x                       Stride of the source image in X dimension (in bytes)
110  * @param[in]  grad_step_x                         grad_stride_x * number of elements along X processed per workitem(in bytes)
111  * @param[in]  grad_stride_y                       Stride of the source image in Y dimension (in bytes)
112  * @param[in]  grad_step_y                         grad_stride_y * number of elements along Y processed per workitem(in bytes)
113  * @param[in]  grad_offset_first_element_in_bytes  The offset of the first element of the output
114  * @param[out] angle_ptr                           Pointer to the angle output. Supported data types: U8
115  * @param[in]  angle_stride_x                      Stride of the source image in X dimension (in bytes)
116  * @param[in]  angle_step_x                        angle_stride_x * number of elements along X processed per workitem(in bytes)
117  * @param[in]  angle_stride_y                      Stride of the source image in Y dimension (in bytes)
118  * @param[in]  angle_step_y                        angle_stride_y * number of elements along Y processed per workitem(in bytes)
119  * @param[in]  angle_offset_first_element_in_bytes The offset of the first element of the output
120  */
121 __kernel void combine_gradients_L2(
122     IMAGE_DECLARATION(src1),
123     IMAGE_DECLARATION(src2),
124     IMAGE_DECLARATION(grad),
125     IMAGE_DECLARATION(angle))
126 {
127     // Construct images
128     Image src1  = CONVERT_TO_IMAGE_STRUCT(src1);
129     Image src2  = CONVERT_TO_IMAGE_STRUCT(src2);
130     Image grad  = CONVERT_TO_IMAGE_STRUCT(grad);
131     Image angle = CONVERT_TO_IMAGE_STRUCT(angle);
132
133     // Load sobel horizontal and vertical values
134     float4 h = convert_float4(vload4(0, (__global DATA_TYPE_IN *)src1.ptr));
135     float4 v = convert_float4(vload4(0, (__global DATA_TYPE_IN *)src2.ptr));
136
137     /* Calculate the gradient, using level 2 normalisation method */
138     float4 m = sqrt(h * h + v * v);
139
140     /* Calculate the angle */
141     float4 p = atan2pi(v, h);
142
143     /* Remap angle to range [0, 256) */
144     p = select(p, p + 2, p < 0.0f) * 128.0f;
145
146     /* Store results */
147     vstore4(CONVERT_SAT_ROUND(m, VEC_DATA_TYPE(DATA_TYPE_OUT, 4), rte), 0, (__global DATA_TYPE_OUT *)grad.ptr);
148     vstore4(convert_uchar4_sat_rte(p), 0, angle.ptr);
149 }
150
151 /** Array that holds the relative coordinates offset for the neighbouring pixels.
152  */
153 __constant short4 neighbours_coords[] =
154 {
155     { -1, 0, 1, 0 },  // 0
156     { -1, 1, 1, -1 }, // 45
157     { 0, 1, 0, -1 },  // 90
158     { 1, 1, -1, -1 }, // 135
159     { 1, 0, -1, 0 },  // 180
160     { 1, -1, -1, 1 }, // 225
161     { 0, 1, 0, -1 },  // 270
162     { -1, -1, 1, 1 }, // 315
163     { -1, 0, 1, 0 },  // 360
164 };
165
166 /** Perform non maximum suppression.
167  *
168  * @attention The input and output data types need to be passed at compile time using -DDATA_TYPE_IN and -DDATA_TYPE_OUT:
169  * e.g. -DDATA_TYPE_IN=uchar -DDATA_TYPE_OUT=short
170  *
171  * @param[in]  grad_ptr                              Pointer to the gradient output. Supported data types: S16, S32
172  * @param[in]  grad_stride_x                         Stride of the source image in X dimension (in bytes)
173  * @param[in]  grad_step_x                           grad_stride_x * number of elements along X processed per workitem(in bytes)
174  * @param[in]  grad_stride_y                         Stride of the source image in Y dimension (in bytes)
175  * @param[in]  grad_step_y                           grad_stride_y * number of elements along Y processed per workitem(in bytes)
176  * @param[in]  grad_offset_first_element_in_bytes    The offset of the first element of the output
177  * @param[in]  angle_ptr                             Pointer to the angle output. Supported data types: U8
178  * @param[in]  angle_stride_x                        Stride of the source image in X dimension (in bytes)
179  * @param[in]  angle_step_x                          angle_stride_x * number of elements along X processed per workitem(in bytes)
180  * @param[in]  angle_stride_y                        Stride of the source image in Y dimension (in bytes)
181  * @param[in]  angle_step_y                          angle_stride_y * number of elements along Y processed per workitem(in bytes)
182  * @param[in]  angle_offset_first_element_in_bytes   TThe offset of the first element of the output
183  * @param[out] non_max_ptr                           Pointer to the non maximum suppressed output. Supported data types: U16, U32
184  * @param[in]  non_max_stride_x                      Stride of the source image in X dimension (in bytes)
185  * @param[in]  non_max_step_x                        non_max_stride_x * number of elements along X processed per workitem(in bytes)
186  * @param[in]  non_max_stride_y                      Stride of the source image in Y dimension (in bytes)
187  * @param[in]  non_max_step_y                        non_max_stride_y * number of elements along Y processed per workitem(in bytes)
188  * @param[in]  non_max_offset_first_element_in_bytes The offset of the first element of the output
189  * @param[in]  lower_thr                             The low threshold
190  */
191 __kernel void suppress_non_maximum(
192     IMAGE_DECLARATION(grad),
193     IMAGE_DECLARATION(angle),
194     IMAGE_DECLARATION(non_max),
195     uint lower_thr)
196 {
197     // Construct images
198     Image grad    = CONVERT_TO_IMAGE_STRUCT(grad);
199     Image angle   = CONVERT_TO_IMAGE_STRUCT(angle);
200     Image non_max = CONVERT_TO_IMAGE_STRUCT(non_max);
201
202     // Get gradient and angle
203     DATA_TYPE_IN gradient = *((__global DATA_TYPE_IN *)grad.ptr);
204     uchar an              = convert_ushort(*angle.ptr);
205
206     if(gradient <= lower_thr)
207     {
208         return;
209     }
210
211     // Divide the whole round into 8 directions
212     uchar         ang  = 127 - an;
213     DATA_TYPE_OUT q_an = (ang + 16) >> 5;
214
215     // Find the two pixels in the perpendicular direction
216     short2       x_p = neighbours_coords[q_an].s02;
217     short2       y_p = neighbours_coords[q_an].s13;
218     DATA_TYPE_IN g1  = *((global DATA_TYPE_IN *)offset(&grad, x_p.x, y_p.x));
219     DATA_TYPE_IN g2  = *((global DATA_TYPE_IN *)offset(&grad, x_p.y, y_p.y));
220
221     if((gradient > g1) && (gradient > g2))
222     {
223         *((global DATA_TYPE_OUT *)non_max.ptr) = gradient;
224     }
225 }
226
227 #define EDGE 255
228 #define hysteresis_local_stack_L1 8  // The size of level 1 stack. This has to agree with the host side
229 #define hysteresis_local_stack_L2 16 // The size of level 2 stack, adjust this can impact the match rate with VX implementation
230
231 /** Check whether pixel is valid
232  *
233  * Skip the pixel if the early_test fails.
234  * Otherwise, it tries to add the pixel coordinate to the stack, and proceed to popping the stack instead if the stack is full
235  *
236  * @param[in] early_test Boolean condition based on the minv check and visited buffer check
237  * @param[in] x_pos      X-coordinate of pixel that is going to be recorded, has to be within the boundary
238  * @param[in] y_pos      Y-coordinate of pixel that is going to be recorded, has to be within the boundary
239  * @param[in] x_cur      X-coordinate of current central pixel
240  * @param[in] y_cur      Y-coordinate of current central pixel
241  */
242 #define check_pixel(early_test, x_pos, y_pos, x_cur, y_cur)                               \
243     {                                                                                     \
244         if(!early_test)                                                                   \
245         {                                                                                 \
246             /* Number of elements in the local stack 1, points to next available entry */ \
247             c = *((__global char *)offset(&l1_stack_counter, x_cur, y_cur));              \
248             \
249             if(c > (hysteresis_local_stack_L1 - 1)) /* Stack level 1 is full */           \
250                 goto pop_stack;                                                           \
251             \
252             /* The pixel that has already been recorded is ignored */                     \
253             if(!atomic_or((__global uint *)offset(&recorded, x_pos, y_pos), 1))           \
254             {                                                                             \
255                 l1_ptr[c] = (short2)(x_pos, y_pos);                                       \
256                 *((__global char *)offset(&l1_stack_counter, x_cur, y_cur)) += 1;         \
257             }                                                                             \
258         }                                                                                 \
259     }
260
261 /** Perform hysteresis.
262  *
263  * @attention The input data_type needs to be passed at compile time using -DDATA_TYPE_IN: e.g. -DDATA_TYPE_IN=short
264  *
265  * @param[in]  src_ptr                                        Pointer to the input image. Supported data types: U8
266  * @param[in]  src_stride_x                                   Stride of the source image in X dimension (in bytes)
267  * @param[in]  src_step_x                                     src_stride_x * number of elements along X processed per workitem(in bytes)
268  * @param[in]  src_stride_y                                   Stride of the source image in Y dimension (in bytes)
269  * @param[in]  src_step_y                                     src_stride_y * number of elements along Y processed per workitem(in bytes)
270  * @param[in]  src_offset_first_element_in_bytes              The offset of the first element of the output
271  * @param[out] out_ptr                                        Pointer to the output image. Supported data types: U8
272  * @param[in]  out_stride_x                                   Stride of the source image in X dimension (in bytes)
273  * @param[in]  out_step_x                                     out_stride_x * number of elements along X processed per workitem(in bytes)
274  * @param[in]  out_stride_y                                   Stride of the source image in Y dimension (in bytes)
275  * @param[in]  out_step_y                                     out_stride_y * number of elements along Y processed per workitem(in bytes)
276  * @param[in]  out_offset_first_element_in_bytes              The offset of the first element of the output
277  * @param[out] visited_ptr                                    Pointer to the visited buffer, where pixels are marked as visited. Supported data types: U32
278  * @param[in]  visited_stride_x                               Stride of the source image in X dimension (in bytes)
279  * @param[in]  visited_step_x                                 visited_stride_x * number of elements along X processed per workitem(in bytes)
280  * @param[in]  visited_stride_y                               Stride of the source image in Y dimension (in bytes)
281  * @param[in]  visited_step_y                                 visited_stride_y * number of elements along Y processed per workitem(in bytes)
282  * @param[in]  visited_offset_first_element_in_bytes          The offset of the first element of the output
283  * @param[out] recorded_ptr                                   Pointer to the recorded buffer, where pixels are marked as recorded. Supported data types: U32
284  * @param[in]  recorded_stride_x                              Stride of the source image in X dimension (in bytes)
285  * @param[in]  recorded_step_x                                recorded_stride_x * number of elements along X processed per workitem(in bytes)
286  * @param[in]  recorded_stride_y                              Stride of the source image in Y dimension (in bytes)
287  * @param[in]  recorded_step_y                                recorded_stride_y * number of elements along Y processed per workitem(in bytes)
288  * @param[in]  recorded_offset_first_element_in_bytes         The offset of the first element of the output
289  * @param[out] l1_stack_ptr                                   Pointer to the l1 stack of a pixel. Supported data types: S32
290  * @param[in]  l1_stack_stride_x                              Stride of the source image in X dimension (in bytes)
291  * @param[in]  l1_stack_step_x                                l1_stack_stride_x * number of elements along X processed per workitem(in bytes)
292  * @param[in]  l1_stack_stride_y                              Stride of the source image in Y dimension (in bytes)
293  * @param[in]  l1_stack_step_y                                l1_stack_stride_y * number of elements along Y processed per workitem(in bytes)
294  * @param[in]  l1_stack_offset_first_element_in_bytes         The offset of the first element of the output
295  * @param[out] l1_stack_counter_ptr                           Pointer to the l1 stack counters of an image. Supported data types: U8
296  * @param[in]  l1_stack_counter_stride_x                      Stride of the source image in X dimension (in bytes)
297  * @param[in]  l1_stack_counter_step_x                        l1_stack_counter_stride_x * number of elements along X processed per workitem(in bytes)
298  * @param[in]  l1_stack_counter_stride_y                      Stride of the source image in Y dimension (in bytes)
299  * @param[in]  l1_stack_counter_step_y                        l1_stack_counter_stride_y * number of elements along Y processed per workitem(in bytes)
300  * @param[in]  l1_stack_counter_offset_first_element_in_bytes The offset of the first element of the output
301  * @param[in]  low_thr                                        The lower threshold
302  * @param[in]  up_thr                                         The upper threshold
303  * @param[in]  width                                          The width of the image.
304  * @param[in]  height                                         The height of the image
305  */
306 kernel void hysteresis(
307     IMAGE_DECLARATION(src),
308     IMAGE_DECLARATION(out),
309     IMAGE_DECLARATION(visited),
310     IMAGE_DECLARATION(recorded),
311     IMAGE_DECLARATION(l1_stack),
312     IMAGE_DECLARATION(l1_stack_counter),
313     uint low_thr,
314     uint up_thr,
315     int  width,
316     int  height)
317 {
318     // Create images
319     Image src              = CONVERT_TO_IMAGE_STRUCT_NO_STEP(src);
320     Image out              = CONVERT_TO_IMAGE_STRUCT_NO_STEP(out);
321     Image visited          = CONVERT_TO_IMAGE_STRUCT_NO_STEP(visited);
322     Image recorded         = CONVERT_TO_IMAGE_STRUCT_NO_STEP(recorded);
323     Image l1_stack         = CONVERT_TO_IMAGE_STRUCT_NO_STEP(l1_stack);
324     Image l1_stack_counter = CONVERT_TO_IMAGE_STRUCT_NO_STEP(l1_stack_counter);
325
326     // Index
327     int x = get_global_id(0);
328     int y = get_global_id(1);
329
330     // Load value
331     DATA_TYPE_IN val = *((__global DATA_TYPE_IN *)offset(&src, x, y));
332
333     // If less than upper threshold set to NO_EDGE and return
334     if(val <= up_thr)
335     {
336         *offset(&out, x, y) = 0;
337         return;
338     }
339
340     // Init local stack 2
341     short2 stack_L2[hysteresis_local_stack_L2] = { 0 };
342     int    L2_counter                          = 0;
343
344     // Perform recursive hysteresis
345     while(true)
346     {
347         // Get L1 stack pointer
348         __global short2 *l1_ptr = (__global short2 *)(l1_stack.ptr + y * l1_stack.stride_y + x * hysteresis_local_stack_L1 * l1_stack.stride_x);
349
350         // If the pixel has already been visited, proceed with the items in the stack instead
351         if(atomic_or((__global uint *)offset(&visited, x, y), 1) != 0)
352         {
353             goto pop_stack;
354         }
355
356         // Set strong edge
357         *offset(&out, x, y) = EDGE;
358
359         // If it is the top of stack l2, we don't need check the surrounding pixels
360         if(L2_counter > (hysteresis_local_stack_L2 - 1))
361         {
362             goto pop_stack2;
363         }
364
365         // Points to the start of the local stack;
366         char c;
367
368         VEC_DATA_TYPE(DATA_TYPE_IN, 4)
369         x_tmp;
370         uint4 v_tmp;
371
372         // Get direction pixel indices
373         int N = max(y - 1, 0), S = min(y + 1, height - 2), W = max(x - 1, 0), E = min(x + 1, width - 2);
374
375         // Check 8 pixels around for week edges where low_thr < val <= up_thr
376         x_tmp = vload4(0, (__global DATA_TYPE_IN *)offset(&src, W, N));
377         v_tmp = vload4(0, (__global uint *)offset(&visited, W, N));
378         check_pixel(((x_tmp.s0 <= low_thr) || v_tmp.s0 || (x_tmp.s0 > up_thr)), W, N, x, y); // NW
379         check_pixel(((x_tmp.s1 <= low_thr) || v_tmp.s1 || (x_tmp.s1 > up_thr)), x, N, x, y); // N
380         check_pixel(((x_tmp.s2 <= low_thr) || v_tmp.s2 || (x_tmp.s2 > up_thr)), E, N, x, y); // NE
381
382         x_tmp = vload4(0, (__global DATA_TYPE_IN *)offset(&src, W, y));
383         v_tmp = vload4(0, (__global uint *)offset(&visited, W, y));
384         check_pixel(((x_tmp.s0 <= low_thr) || v_tmp.s0 || (x_tmp.s0 > up_thr)), W, y, x, y); // W
385         check_pixel(((x_tmp.s2 <= low_thr) || v_tmp.s2 || (x_tmp.s2 > up_thr)), E, y, x, y); // E
386
387         x_tmp = vload4(0, (__global DATA_TYPE_IN *)offset(&src, W, S));
388         v_tmp = vload4(0, (__global uint *)offset(&visited, W, S));
389         check_pixel(((x_tmp.s0 <= low_thr) || v_tmp.s0 || (x_tmp.s0 > up_thr)), W, S, x, y); // SW
390         check_pixel(((x_tmp.s1 <= low_thr) || v_tmp.s1 || (x_tmp.s1 > up_thr)), x, S, x, y); // S
391         check_pixel(((x_tmp.s2 <= low_thr) || v_tmp.s2 || (x_tmp.s2 > up_thr)), E, S, x, y); // SE
392
393 #undef check_pixel
394
395 pop_stack:
396         c = *((__global char *)offset(&l1_stack_counter, x, y));
397
398         if(c >= 1)
399         {
400             *((__global char *)offset(&l1_stack_counter, x, y)) -= 1;
401             int2 l_c = convert_int2(l1_ptr[c - 1]);
402
403             // Push the current position into level 2 stack
404             stack_L2[L2_counter].x = x;
405             stack_L2[L2_counter].y = y;
406
407             x = l_c.x;
408             y = l_c.y;
409
410             L2_counter++;
411
412             continue;
413         }
414
415         if(L2_counter > 0)
416         {
417             goto pop_stack2;
418         }
419         else
420         {
421             return;
422         }
423
424 pop_stack2:
425         L2_counter--;
426         x = stack_L2[L2_counter].x;
427         y = stack_L2[L2_counter].y;
428     };
429 }