blob: 76b35b931bb08b60fa3ef26c5a5c11896e47b44d [file] [log] [blame]
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001/*
Abe Mbise25a340f2017-12-19 13:00:58 +00002 * Copyright (c) 2016-2018 ARM Limited.
Anthony Barbier6ff3b192017-09-04 18:44:23 +01003 *
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#include "types.h"
26
27/* The map table to retrieve the 16 texels in the Bresenham circle of radius 3 with center in P.
28 *
29 * . . F 0 1 . . .
30 * . E . . . 2 . .
31 * D . . . . . 3 .
32 * C . . P . . 4 .
33 * B . . . . . 5 .
34 * . A . . . 6 . .
35 * . . 9 8 7 . . .
36 */
37constant int offsets_s[16][2] =
38{
39 { 0, -3 }, // 0
40 { 1, -3 }, // 1
41 { 2, -2 }, // 2
42 { 3, -1 }, // 3
43 { 3, 0 }, // 4
44 { 3, 1 }, // 5
45 { 2, 2 }, // 6
46 { 1, 3 }, // 7
47 { 0, 3 }, // 8
48 { -1, 3 }, // 9
49 { -2, 2 }, // A
50 { -3, 1 }, // B
51 { -3, 0 }, // C
52 { -3, -1 }, // D
53 { -2, -2 }, // E
54 { -1, -3 }, // F
55};
56
57/** Load a pixel and set the mask values.
58 *
59 * @param[in] ptr The pointer to the starting address of source image
60 * @param[in] a Index to indicate the position in the Bresenham circle
61 * @param[in] stride Stride of source image in x dimension
62 * @param[in] dark The left end of the threshold range
63 * @param[in] bright The right end of the threshold range
64 * @param[out] dark_mask The bit-set mask records dark pixels. Its bit is set as 1 if the corresponding pixel is dark
65 * @param[out] bright_mask The bit-set mask records bright pixels. Its bit is set as 1 if the corresponding pixel is bright
66 *
67 */
68#define LOAD_AND_SET_MASK(ptr, a, stride, dark, bright, dark_mask, bright_mask) \
69 { \
70 unsigned char pixel; \
71 pixel = *(ptr + (int)stride * offsets_s[a][1] + offsets_s[a][0]); \
72 dark_mask |= (pixel < dark) << a; \
73 bright_mask |= (pixel > bright) << a; \
74 }
75
76/** Checks if a pixel is a corner. Pixel is considerred as a corner if the 9 continuous pixels in the Bresenham circle are bright or dark.
77 *
78 * @param[in] bright_mask The mask recording postions of bright pixels
79 * @param[in] dark_mask The mask recording postions of dark pixels
80 * @param[out] isCorner Indicate whether candidate pixel is corner
81 */
82#define CHECK_CORNER(bright_mask, dark_mask, isCorner) \
83 { \
84 for(int i = 0; i < 16; i++) \
85 { \
86 isCorner |= ((bright_mask & 0x1FF) == 0x1FF); \
87 isCorner |= ((dark_mask & 0x1FF) == 0x1FF); \
88 if(isCorner) \
89 { \
90 break; \
91 } \
92 bright_mask >>= 1; \
93 dark_mask >>= 1; \
94 } \
95 }
96
97/* Calculate pixel's strength */
98uchar compute_strength(uchar candidate_pixel, __global unsigned char *ptr, unsigned int stride, unsigned char threshold)
99{
100 short a = threshold;
101 short b = 255;
102 while(b - a > 1)
103 {
104 uchar c = convert_uchar_sat((a + b) / 2);
105 unsigned int bright_mask = 0;
106 unsigned int dark_mask = 0;
107
108 unsigned char p_bright = add_sat(candidate_pixel, c);
109 unsigned char p_dark = sub_sat(candidate_pixel, c);
110
111 bool isCorner = 0;
112
113 for(uint i = 0; i < 16; i++)
114 {
115 LOAD_AND_SET_MASK(ptr, i, stride, p_dark, p_bright, dark_mask, bright_mask)
116 }
117
118 bright_mask |= (bright_mask << 16);
119 dark_mask |= (dark_mask << 16);
120 CHECK_CORNER(bright_mask, dark_mask, isCorner);
121
122 if(isCorner)
123 {
124 a = convert_short(c);
125 }
126 else
127 {
128 b = convert_short(c);
129 }
130 }
131 return a;
132}
133
134/** Fast corners implementation. Calculates and returns the strength of each pixel.
135 *
136 * The algorithm loops through the 16 pixels in the Bresenham circle and set low 16 bit of masks if corresponding pixel is bright
137 * or dark. It then copy the low 16 bit to the high 16 bit of the masks. Right shift the bit to check whether the 9 continuous bits
138 * from the LSB are set.
139 *
140 * @param[in] input_ptr Pointer to the first source image. Supported data types: U8
141 * @param[in] input_stride_x Stride of the first source image in X dimension (in bytes)
142 * @param[in] input_step_x input_stride_x * number of elements along X processed per workitem(in bytes)
143 * @param[in] input_stride_y Stride of the first source image in Y dimension (in bytes)
144 * @param[in] input_step_y input_stride_y * number of elements along Y processed per workitem(in bytes)
145 * @param[in] input_offset_first_element_in_bytes The offset of the first element in the first source image
146 * @param[out] output_ptr Pointer to the first source image. Supported data types: U8
147 * @param[in] output_stride_x Stride of the first source image in X dimension (in bytes)
148 * @param[in] output_step_x output_stride_x * number of elements along X processed per workitem(in bytes)
149 * @param[in] output_stride_y Stride of the first source image in Y dimension (in bytes)
150 * @param[in] output_step_y output_stride_y * number of elements along Y processed per workitem(in bytes)
151 * @param[in] output_offset_first_element_in_bytes The offset of the first element in the first source image
152 * @param[in] threshold_value Threshold value.
153 *
154 */
155__kernel void fast_corners(
156 IMAGE_DECLARATION(input),
157 IMAGE_DECLARATION(output),
158 float threshold_value)
159{
160 Image in = CONVERT_TO_IMAGE_STRUCT(input);
161 Image out = CONVERT_TO_IMAGE_STRUCT(output);
162
163 const unsigned char threshold = (uchar)threshold_value;
164
165 unsigned int bright_mask = 0;
166 unsigned int dark_mask = 0;
167
168 unsigned char isCorner = 0;
169
170 unsigned char p = *in.ptr;
171 unsigned char p_bright = add_sat(p, threshold);
172 unsigned char p_dark = sub_sat(p, threshold);
173
174 LOAD_AND_SET_MASK(in.ptr, 0, input_stride_y, p_dark, p_bright, dark_mask, bright_mask)
175 LOAD_AND_SET_MASK(in.ptr, 4, input_stride_y, p_dark, p_bright, dark_mask, bright_mask)
176 LOAD_AND_SET_MASK(in.ptr, 8, input_stride_y, p_dark, p_bright, dark_mask, bright_mask)
177 LOAD_AND_SET_MASK(in.ptr, 12, input_stride_y, p_dark, p_bright, dark_mask, bright_mask)
178
179 if(((bright_mask | dark_mask) & 0x1111) == 0)
180 {
181 *out.ptr = 0;
182 return;
183 }
184
185 LOAD_AND_SET_MASK(in.ptr, 1, input_stride_y, p_dark, p_bright, dark_mask, bright_mask)
186 LOAD_AND_SET_MASK(in.ptr, 2, input_stride_y, p_dark, p_bright, dark_mask, bright_mask)
187 LOAD_AND_SET_MASK(in.ptr, 3, input_stride_y, p_dark, p_bright, dark_mask, bright_mask)
188 LOAD_AND_SET_MASK(in.ptr, 5, input_stride_y, p_dark, p_bright, dark_mask, bright_mask)
189 LOAD_AND_SET_MASK(in.ptr, 6, input_stride_y, p_dark, p_bright, dark_mask, bright_mask)
190 LOAD_AND_SET_MASK(in.ptr, 7, input_stride_y, p_dark, p_bright, dark_mask, bright_mask)
191 LOAD_AND_SET_MASK(in.ptr, 9, input_stride_y, p_dark, p_bright, dark_mask, bright_mask)
192 LOAD_AND_SET_MASK(in.ptr, 10, input_stride_y, p_dark, p_bright, dark_mask, bright_mask)
193 LOAD_AND_SET_MASK(in.ptr, 11, input_stride_y, p_dark, p_bright, dark_mask, bright_mask)
194 LOAD_AND_SET_MASK(in.ptr, 13, input_stride_y, p_dark, p_bright, dark_mask, bright_mask)
195 LOAD_AND_SET_MASK(in.ptr, 14, input_stride_y, p_dark, p_bright, dark_mask, bright_mask)
196 LOAD_AND_SET_MASK(in.ptr, 15, input_stride_y, p_dark, p_bright, dark_mask, bright_mask)
197
198 bright_mask |= (bright_mask << 16);
199 dark_mask |= (dark_mask << 16);
200
201 CHECK_CORNER(bright_mask, dark_mask, isCorner)
202
203 if(!isCorner)
204 {
205 *out.ptr = 0;
206 return;
207 }
208
Anthony Barbierac69aa12017-07-03 17:39:37 +0100209#ifdef USE_MAXSUPPRESSION
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100210 *out.ptr = compute_strength(p, in.ptr, input_stride_y, threshold);
Anthony Barbierac69aa12017-07-03 17:39:37 +0100211#else /* USE_MAXSUPPRESSION */
212 *out.ptr = 1;
213#endif /* USE_MAXSUPPRESSION */
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100214}
215
216/** Copy result to Keypoint buffer and count number of corners
217 *
218 * @param[in] input_ptr Pointer to the image with calculated strenghs. Supported data types: U8
219 * @param[in] input_stride_x Stride of the first source image in X dimension (in bytes)
220 * @param[in] input_step_x input_stride_x * number of elements along X processed per workitem(in bytes)
221 * @param[in] input_stride_y Stride of the first source image in Y dimension (in bytes)
222 * @param[in] input_step_y input_stride_y * number of elements along Y processed per workitem(in bytes)
223 * @param[in] input_offset_first_element_in_bytes The offset of the first element in the first source image
224 * @param[in] max_num_points The maximum number of keypoints the array can hold
225 * @param[out] offset The number of skipped pixels in x dimension
226 * @param[out] num_of_points Number of points found
227 * @param[out] out The keypoints found
228 *
229 */
230__kernel void copy_to_keypoint(
231 IMAGE_DECLARATION(input),
232 uint max_num_points,
233 uint offset,
234 __global uint *num_of_points,
235 __global Keypoint *out)
236{
237#ifndef UPDATE_NUMBER
238 if(*num_of_points >= max_num_points)
239 {
240 return;
241 }
Anthony Barbierac69aa12017-07-03 17:39:37 +0100242#endif /* UPDATE_NUMBER */
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100243
244 Image in = CONVERT_TO_IMAGE_STRUCT(input);
245
246 uchar value = *in.ptr;
247
248 if(value > 0)
249 {
250 int id = atomic_inc(num_of_points);
251 if(id < max_num_points)
252 {
253 out[id].strength = value;
254 out[id].x = get_global_id(0) + offset;
255 out[id].y = get_global_id(1) + offset;
256 out[id].tracking_status = 1;
Abe Mbise25a340f2017-12-19 13:00:58 +0000257 out[id].scale = 0.f;
258 out[id].orientation = 0.f;
259 out[id].error = 0.f;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100260 }
261 }
262}