/home/liu/actions-runner/_work/ccv/ccv/lib/ccv_classic.c
Line | Count | Source |
1 | | #include "ccv.h" |
2 | | #include "ccv_internal.h" |
3 | | |
4 | | void ccv_hog(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int b_type, int sbin, int size) |
5 | 0 | { |
6 | 0 | assert(a->rows >= size && a->cols >= size && (4 + sbin * 3) <= CCV_MAX_CHANNEL); |
7 | 0 | int rows = a->rows / size; |
8 | 0 | int cols = a->cols / size; |
9 | 0 | b_type = (CCV_GET_DATA_TYPE(b_type) == CCV_64F) ? CCV_64F | (4 + sbin * 3) : CCV_32F | (4 + sbin * 3); |
10 | 0 | ccv_declare_derived_signature(sig, a->sig != 0, ccv_sign_with_format(64, "ccv_hog(%d,%d)", sbin, size), a->sig, CCV_EOF_SIGN); |
11 | 0 | ccv_dense_matrix_t* db = *b = ccv_dense_matrix_renew(*b, rows, cols, CCV_64F | CCV_32F | (4 + sbin * 3), b_type, sig); |
12 | 0 | ccv_object_return_if_cached(, db); |
13 | 0 | ccv_dense_matrix_t* ag = 0; |
14 | 0 | ccv_dense_matrix_t* mg = 0; |
15 | 0 | ccv_gradient(a, &ag, 0, &mg, 0, 1, 1); |
16 | 0 | float* agp = ag->data.f32; |
17 | 0 | float* mgp = mg->data.f32; |
18 | 0 | int i, j, k, ch = CCV_GET_CHANNEL(a->type); |
19 | 0 | ccv_dense_matrix_t* cn = ccv_dense_matrix_new(rows, cols, CCV_GET_DATA_TYPE(db->type) | (sbin * 2), 0, 0); |
20 | 0 | ccv_dense_matrix_t* ca = ccv_dense_matrix_new(rows, cols, CCV_GET_DATA_TYPE(db->type) | CCV_C1, 0, 0); |
21 | 0 | ccv_zero(cn); |
22 | | // normalize sbin direction-sensitive and sbin * 2 insensitive over 4 normalization factor |
23 | | // accumulating them over sbin * 2 + sbin + 4 channels |
24 | | // TNA - truncation - normalization - accumulation |
25 | 0 | #define TNA(_for_type, idx, a, b, c, d) \ |
26 | 0 | { \ |
27 | 0 | _for_type norm = 1.0 / sqrt(cap[a] + cap[b] + cap[c] + cap[d] + 1e-4); \ |
28 | 0 | for (k = 0; k < sbin * 2; k++) \ |
29 | 0 | { \ |
30 | 0 | _for_type v = 0.5 * ccv_min(cnp[k] * norm, 0.2); \ |
31 | 0 | dbp[4 + sbin + k] += v; \ |
32 | 0 | dbp[idx] += v; \ |
33 | 0 | } \ |
34 | 0 | dbp[idx] *= 0.2357; \ |
35 | 0 | for (k = 0; k < sbin; k++) \ |
36 | 0 | { \ |
37 | 0 | _for_type v = 0.5 * ccv_min((cnp[k] + cnp[k + sbin]) * norm, 0.2); \ |
38 | 0 | dbp[4 + k] += v; \ |
39 | 0 | } \ |
40 | 0 | } |
41 | 0 | #define for_block(_, _for_type) \ |
42 | 0 | _for_type* cnp = (_for_type*)ccv_get_dense_matrix_cell(cn, 0, 0, 0); \ |
43 | 0 | for (i = 0; i < rows * size; i++) \ |
44 | 0 | { \ |
45 | 0 | for (j = 0; j < cols * size; j++) \ |
46 | 0 | { \ |
47 | 0 | _for_type agv = agp[j * ch]; \ |
48 | 0 | _for_type mgv = mgp[j * ch]; \ |
49 | 0 | for (k = 1; k < ch; k++) \ |
50 | 0 | if (mgp[j * ch + k] > mgv) \ |
51 | 0 | { \ |
52 | 0 | mgv = mgp[j * ch + k]; \ |
53 | 0 | agv = agp[j * ch + k]; \ |
54 | 0 | } \ |
55 | 0 | _for_type agr0 = (ccv_clamp(agv, 0, 359.99) / 360.0) * (sbin * 2); \ |
56 | 0 | int ag0 = (int)agr0; \ |
57 | 0 | int ag1 = (ag0 + 1 < sbin * 2) ? ag0 + 1 : 0; \ |
58 | 0 | agr0 = agr0 - ag0; \ |
59 | 0 | _for_type agr1 = 1.0 - agr0; \ |
60 | 0 | mgv = mgv / 255.0; \ |
61 | 0 | _for_type yp = ((_for_type)i + 0.5) / (_for_type)size - 0.5; \ |
62 | 0 | _for_type xp = ((_for_type)j + 0.5) / (_for_type)size - 0.5; \ |
63 | 0 | int iyp = (int)floor(yp); \ |
64 | 0 | assert(iyp < rows); \ |
65 | 0 | int ixp = (int)floor(xp); \ |
66 | 0 | assert(ixp < cols); \ |
67 | 0 | _for_type vy0 = yp - iyp; \ |
68 | 0 | _for_type vx0 = xp - ixp; \ |
69 | 0 | _for_type vy1 = 1.0 - vy0; \ |
70 | 0 | _for_type vx1 = 1.0 - vx0; \ |
71 | 0 | if (ixp >= 0 && iyp >= 0) \ |
72 | 0 | { \ |
73 | 0 | cnp[iyp * cn->cols * sbin * 2 + ixp * sbin * 2 + ag0] += agr1 * vx1 * vy1 * mgv; \ |
74 | 0 | cnp[iyp * cn->cols * sbin * 2 + ixp * sbin * 2 + ag1] += agr0 * vx1 * vy1 * mgv; \ |
75 | 0 | } \ |
76 | 0 | if (ixp + 1 < cn->cols && iyp >= 0) \ |
77 | 0 | { \ |
78 | 0 | cnp[iyp * cn->cols * sbin * 2 + (ixp + 1) * sbin * 2 + ag0] += agr1 * vx0 * vy1 * mgv; \ |
79 | 0 | cnp[iyp * cn->cols * sbin * 2 + (ixp + 1) * sbin * 2 + ag1] += agr0 * vx0 * vy1 * mgv; \ |
80 | 0 | } \ |
81 | 0 | if (ixp >= 0 && iyp + 1 < cn->rows) \ |
82 | 0 | { \ |
83 | 0 | cnp[(iyp + 1) * cn->cols * sbin * 2 + ixp * sbin * 2 + ag0] += agr1 * vx1 * vy0 * mgv; \ |
84 | 0 | cnp[(iyp + 1) * cn->cols * sbin * 2 + ixp * sbin * 2 + ag1] += agr0 * vx1 * vy0 * mgv; \ |
85 | 0 | } \ |
86 | 0 | if (ixp + 1 < cn->cols && iyp + 1 < cn->rows) \ |
87 | 0 | { \ |
88 | 0 | cnp[(iyp + 1) * cn->cols * sbin * 2 + (ixp + 1) * sbin * 2 + ag0] += agr1 * vx0 * vy0 * mgv; \ |
89 | 0 | cnp[(iyp + 1) * cn->cols * sbin * 2 + (ixp + 1) * sbin * 2 + ag1] += agr0 * vx0 * vy0 * mgv; \ |
90 | 0 | } \ |
91 | 0 | } \ |
92 | 0 | agp += a->cols * ch; \ |
93 | 0 | mgp += a->cols * ch; \ |
94 | 0 | } \ |
95 | 0 | ccv_matrix_free(ag); \ |
96 | 0 | ccv_matrix_free(mg); \ |
97 | 0 | cnp = (_for_type*)ccv_get_dense_matrix_cell(cn, 0, 0, 0); \ |
98 | 0 | _for_type* cap = (_for_type*)ccv_get_dense_matrix_cell(ca, 0, 0, 0); \ |
99 | 0 | for (i = 0; i < rows; i++) \ |
100 | 0 | { \ |
101 | 0 | for (j = 0; j < cols; j++) \ |
102 | 0 | { \ |
103 | 0 | *cap = 0; \ |
104 | 0 | for (k = 0; k < sbin; k++) \ |
105 | 0 | *cap += (cnp[k] + cnp[k + sbin]) * (cnp[k] + cnp[k + sbin]); \ |
106 | 0 | cnp += 2 * sbin; \ |
107 | 0 | cap++; \ |
108 | 0 | } \ |
109 | 0 | } \ |
110 | 0 | cnp = (_for_type*)ccv_get_dense_matrix_cell(cn, 0, 0, 0); \ |
111 | 0 | cap = (_for_type*)ccv_get_dense_matrix_cell(ca, 0, 0, 0); \ |
112 | 0 | ccv_zero(db); \ |
113 | 0 | _for_type* dbp = (_for_type*)ccv_get_dense_matrix_cell(db, 0, 0, 0); \ |
114 | 0 | TNA(_for_type, 0, 1, cols + 1, cols, 0); \ |
115 | 0 | TNA(_for_type, 1, 1, 1, 0, 0); \ |
116 | 0 | TNA(_for_type, 2, 0, cols, cols, 0); \ |
117 | 0 | TNA(_for_type, 3, 0, 0, 0, 0); \ |
118 | 0 | cnp += 2 * sbin; \ |
119 | 0 | dbp += 3 * sbin + 4; \ |
120 | 0 | cap++; \ |
121 | 0 | for (j = 1; j < cols - 1; j++) \ |
122 | 0 | { \ |
123 | 0 | TNA(_for_type, 0, 1, cols + 1, cols, 0); \ |
124 | 0 | TNA(_for_type, 1, 1, 1, 0, 0); \ |
125 | 0 | TNA(_for_type, 2, -1, cols - 1, cols, 0); \ |
126 | 0 | TNA(_for_type, 3, -1, -1, 0, 0); \ |
127 | 0 | cnp += 2 * sbin; \ |
128 | 0 | dbp += 3 * sbin + 4; \ |
129 | 0 | cap++; \ |
130 | 0 | } \ |
131 | 0 | TNA(_for_type, 0, 0, cols, cols, 0); \ |
132 | 0 | TNA(_for_type, 1, 0, 0, 0, 0); \ |
133 | 0 | TNA(_for_type, 2, -1, cols - 1, cols, 0); \ |
134 | 0 | TNA(_for_type, 3, -1, -1, 0, 0); \ |
135 | 0 | cnp += 2 * sbin; \ |
136 | 0 | dbp += 3 * sbin + 4; \ |
137 | 0 | cap++; \ |
138 | 0 | for (i = 1; i < rows - 1; i++) \ |
139 | 0 | { \ |
140 | 0 | TNA(_for_type, 0, 1, cols + 1, cols, 0); \ |
141 | 0 | TNA(_for_type, 1, 1, -cols + 1, -cols, 0); \ |
142 | 0 | TNA(_for_type, 2, 0, cols, cols, 0); \ |
143 | 0 | TNA(_for_type, 3, 0, -cols, -cols, 0); \ |
144 | 0 | cnp += 2 * sbin; \ |
145 | 0 | dbp += 3 * sbin + 4; \ |
146 | 0 | cap++; \ |
147 | 0 | for (j = 1; j < cols - 1; j++) \ |
148 | 0 | { \ |
149 | 0 | TNA(_for_type, 0, 1, cols + 1, cols, 0); \ |
150 | 0 | TNA(_for_type, 1, 1, -cols + 1, -cols, 0); \ |
151 | 0 | TNA(_for_type, 2, -1, cols - 1, cols, 0); \ |
152 | 0 | TNA(_for_type, 3, -1, -cols - 1, -cols, 0); \ |
153 | 0 | cnp += 2 * sbin; \ |
154 | 0 | dbp += 3 * sbin + 4; \ |
155 | 0 | cap++; \ |
156 | 0 | } \ |
157 | 0 | TNA(_for_type, 0, 0, cols, cols, 0); \ |
158 | 0 | TNA(_for_type, 1, 0, -cols, -cols, 0); \ |
159 | 0 | TNA(_for_type, 2, -1, cols - 1, cols, 0); \ |
160 | 0 | TNA(_for_type, 3, -1, -cols - 1, -cols, 0); \ |
161 | 0 | cnp += 2 * sbin; \ |
162 | 0 | dbp += 3 * sbin + 4; \ |
163 | 0 | cap++; \ |
164 | 0 | } \ |
165 | 0 | TNA(_for_type, 0, 1, 1, 0, 0); \ |
166 | 0 | TNA(_for_type, 1, 1, -cols + 1, -cols, 0); \ |
167 | 0 | TNA(_for_type, 2, 0, 0, 0, 0); \ |
168 | 0 | TNA(_for_type, 3, 0, -cols, -cols, 0); \ |
169 | 0 | cnp += 2 * sbin; \ |
170 | 0 | dbp += 3 * sbin + 4; \ |
171 | 0 | cap++; \ |
172 | 0 | for (j = 1; j < cols - 1; j++) \ |
173 | 0 | { \ |
174 | 0 | TNA(_for_type, 0, 1, 1, 0, 0); \ |
175 | 0 | TNA(_for_type, 1, 1, -cols + 1, -cols, 0); \ |
176 | 0 | TNA(_for_type, 2, -1, -1, 0, 0); \ |
177 | 0 | TNA(_for_type, 3, -1, -cols - 1, -cols, 0); \ |
178 | 0 | cnp += 2 * sbin; \ |
179 | 0 | dbp += 3 * sbin + 4; \ |
180 | 0 | cap++; \ |
181 | 0 | } \ |
182 | 0 | TNA(_for_type, 0, 0, 0, 0, 0); \ |
183 | 0 | TNA(_for_type, 1, 0, -cols, -cols, 0); \ |
184 | 0 | TNA(_for_type, 2, -1, -1, 0, 0); \ |
185 | 0 | TNA(_for_type, 3, -1, -cols - 1, -cols, 0); |
186 | 0 | ccv_matrix_typeof(db->type, for_block); |
187 | 0 | #undef for_block |
188 | 0 | #undef TNA |
189 | 0 | ccv_matrix_free(cn); |
190 | 0 | ccv_matrix_free(ca); |
191 | 0 | } |
192 | | |
193 | | /* it is a supposely cleaner and faster implementation than original OpenCV (ccv_canny_deprecated, |
194 | | * removed, since the newer implementation achieve bit accuracy with OpenCV's), after a lot |
195 | | * profiling, the current implementation still uses integer to speed up */ |
196 | | void ccv_canny(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type, int size, double low_thresh, double high_thresh) |
197 | 1 | { |
198 | 1 | assert(CCV_GET_CHANNEL(a->type) == CCV_C1); |
199 | 1 | ccv_declare_derived_signature(sig, a->sig != 0, ccv_sign_with_format(64, "ccv_canny(%d,%la,%la)", size, low_thresh, high_thresh), a->sig, CCV_EOF_SIGN); |
200 | 1 | type = (type == 0) ? CCV_8U | CCV_C1 : CCV_GET_DATA_TYPE0 (type) | CCV_C10 ; |
201 | 1 | ccv_dense_matrix_t* db = *b = ccv_dense_matrix_renew(*b, a->rows, a->cols, CCV_C1 | CCV_ALL_DATA_TYPE, type, sig); |
202 | 1 | ccv_object_return_if_cached(, db); |
203 | 1 | if ((a->type & CCV_8U) || (a->type & CCV_32S)0 ) |
204 | 1 | { |
205 | 1 | ccv_dense_matrix_t* dx = 0; |
206 | 1 | ccv_dense_matrix_t* dy = 0; |
207 | 1 | ccv_sobel(a, &dx, 0, size, 0); |
208 | 1 | ccv_sobel(a, &dy, 0, 0, size); |
209 | | /* special case, all integer */ |
210 | 1 | int low = (int)(low_thresh + 0.5); |
211 | 1 | int high = (int)(high_thresh + 0.5); |
212 | 1 | int* dxi = dx->data.i32; |
213 | 1 | int* dyi = dy->data.i32; |
214 | 1 | int i, j; |
215 | 1 | int* mbuf = (int*)alloca(3 * (a->cols + 2) * sizeof(int)); |
216 | 1 | memset(mbuf, 0, 3 * (a->cols + 2) * sizeof(int)); |
217 | 1 | int* rows[3]; |
218 | 1 | rows[0] = mbuf + 1; |
219 | 1 | rows[1] = mbuf + (a->cols + 2) + 1; |
220 | 1 | rows[2] = mbuf + 2 * (a->cols + 2) + 1; |
221 | 501 | for (j = 0; j < a->cols; j++500 ) |
222 | 500 | rows[1][j] = abs(dxi[j]) + abs(dyi[j]); |
223 | 1 | dxi += a->cols; |
224 | 1 | dyi += a->cols; |
225 | 1 | int* map = (int*)ccmalloc(sizeof(int) * (a->rows + 2) * (a->cols + 2)); |
226 | 1 | int map_cols = a->cols + 2; |
227 | 1 | memset(map, 0, sizeof(int) * map_cols); |
228 | 1 | int* map_ptr = map + map_cols + 1; |
229 | 1 | int** stack = (int**)ccmalloc(sizeof(int*) * a->rows * a->cols); |
230 | 1 | int** stack_top = stack; |
231 | 1 | int** stack_bottom = stack; |
232 | 501 | for (i = 1; i <= a->rows; i++500 ) |
233 | 500 | { |
234 | | /* the if clause should be unswitched automatically, no need to manually do so */ |
235 | 500 | if (i == a->rows) |
236 | 1 | memset(rows[2], 0, sizeof(int) * a->cols); |
237 | 499 | else |
238 | 249k | for (j = 0; 499 j < a->cols; j++249k ) |
239 | 249k | rows[2][j] = abs(dxi[j]) + abs(dyi[j]); |
240 | 500 | int* _dx = dxi - a->cols; |
241 | 500 | int* _dy = dyi - a->cols; |
242 | 500 | map_ptr[-1] = 0; |
243 | 500 | int suppress = 0; |
244 | 250k | for (j = 0; j < a->cols; j++250k ) |
245 | 250k | { |
246 | 250k | int f = rows[1][j]; |
247 | 250k | if (f > low) |
248 | 6.72k | { |
249 | 6.72k | int x = abs(_dx[j]); |
250 | 6.72k | int y = abs(_dy[j]); |
251 | 6.72k | int s = _dx[j] ^ _dy[j]; |
252 | | /* x * tan(22.5) */ |
253 | 6.72k | int tg22x = x * (int)(0.4142135623730950488016887242097 * (1 << 15) + 0.5); |
254 | | /* x * tan(67.5) == 2 * x + x * tan(22.5) */ |
255 | 6.72k | int tg67x = tg22x + ((x + x) << 15); |
256 | 6.72k | y <<= 15; |
257 | | /* it is a little different from the Canny original paper because we adopted the coordinate system of |
258 | | * top-left corner as origin. Thus, the derivative of y convolved with matrix: |
259 | | * |-1 -2 -1| |
260 | | * | 0 0 0| |
261 | | * | 1 2 1| |
262 | | * actually is the reverse of real y. Thus, the computed angle will be mirrored around x-axis. |
263 | | * In this case, when angle is -45 (135), we compare with north-east and south-west, and for 45, |
264 | | * we compare with north-west and south-east (in traditional coordinate system sense, the same if we |
265 | | * adopt top-left corner as origin for "north", "south", "east", "west" accordingly) */ |
266 | 6.72k | #define high_block \ |
267 | 6.72k | { \ |
268 | 1.14k | if (f > high && !suppress && map_ptr[j - map_cols] != 2663 ) \ |
269 | 1.14k | { \ |
270 | 463 | map_ptr[j] = 2; \ |
271 | 463 | suppress = 1; \ |
272 | 463 | *(stack_top++) = map_ptr + j; \ |
273 | 682 | } else { \ |
274 | 682 | map_ptr[j] = 1; \ |
275 | 682 | } \ |
276 | 1.14k | continue; \ |
277 | 1.14k | } |
278 | | /* sometimes, we end up with same f in integer domain, for that case, we will take the first occurrence |
279 | | * suppressing the second with flag */ |
280 | 6.72k | if (y < tg22x) |
281 | 1.39k | { |
282 | 1.39k | if (f > rows[1][j - 1] && f >= rows[1][j + 1]813 ) |
283 | 1.00k | high_block388 ; |
284 | 5.32k | } else if (y > tg67x) { |
285 | 1.34k | if (f > rows[0][j] && f >= rows[2][j]786 ) |
286 | 987 | high_block357 ; |
287 | 3.98k | } else { |
288 | 3.98k | s = s < 0 ? -12.45k : 11.52k ; |
289 | 3.98k | if (f > rows[0][j - s] && f > rows[2][j + s]2.19k ) |
290 | 3.58k | high_block400 ; |
291 | 3.58k | } |
292 | 6.72k | #undef high_block |
293 | 6.72k | } |
294 | 248k | map_ptr[j] = 0; |
295 | 248k | suppress = 0; |
296 | 248k | } |
297 | 500 | map_ptr[a->cols] = 0; |
298 | 500 | map_ptr += map_cols; |
299 | 500 | dxi += a->cols; |
300 | 500 | dyi += a->cols; |
301 | 500 | int* row = rows[0]; |
302 | 500 | rows[0] = rows[1]; |
303 | 500 | rows[1] = rows[2]; |
304 | 500 | rows[2] = row; |
305 | 500 | } |
306 | 1 | memset(map_ptr - 1, 0, sizeof(int) * map_cols); |
307 | 1 | int dr[] = {-1, 1, -map_cols - 1, -map_cols, -map_cols + 1, map_cols - 1, map_cols, map_cols + 1}; |
308 | 1.14k | while (stack_top > stack_bottom) |
309 | 1.14k | { |
310 | 1.14k | map_ptr = *(--stack_top); |
311 | 10.3k | for (i = 0; i < 8; i++9.16k ) |
312 | 9.16k | if (map_ptr[dr[i]] == 1) |
313 | 682 | { |
314 | 682 | map_ptr[dr[i]] = 2; |
315 | 682 | *(stack_top++) = map_ptr + dr[i]; |
316 | 682 | } |
317 | 1.14k | } |
318 | 1 | map_ptr = map + map_cols + 1; |
319 | 1 | unsigned char* b_ptr = db->data.u8; |
320 | 1 | #define for_block(_, _for_set) \ |
321 | 501 | for (i = 0; 1 i < a->rows; i++500 ) \ |
322 | 500 | { \ |
323 | 250k | for (j = 0; j < a->cols; j++250k ) \ |
324 | 500 | _for_set(b_ptr, j, (map_ptr[j] == 2)); \ |
325 | 500 | map_ptr += map_cols; \ |
326 | 500 | b_ptr += db->step; \ |
327 | 500 | } |
328 | 1 | ccv_matrix_setter(db->type, for_block); |
329 | 1 | #undef for_block |
330 | 1 | ccfree(stack); |
331 | 1 | ccfree(map); |
332 | 1 | ccv_matrix_free(dx); |
333 | 1 | ccv_matrix_free(dy); |
334 | 1 | } else { |
335 | | /* general case, use all ccv facilities to deal with it */ |
336 | 0 | ccv_dense_matrix_t* mg = 0; |
337 | 0 | ccv_dense_matrix_t* ag = 0; |
338 | 0 | ccv_gradient(a, &ag, 0, &mg, 0, size, size); |
339 | 0 | ccv_matrix_free(ag); |
340 | 0 | ccv_matrix_free(mg); |
341 | | /* FIXME: Canny implementation for general case */ |
342 | 0 | } |
343 | 1 | } |
344 | | |
345 | | void ccv_close_outline(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type) |
346 | 0 | { |
347 | 0 | assert((CCV_GET_CHANNEL(a->type) == CCV_C1) && ((a->type & CCV_8U) || (a->type & CCV_32S) || (a->type & CCV_64S))); |
348 | 0 | ccv_declare_derived_signature(sig, a->sig != 0, ccv_sign_with_literal("ccv_close_outline"), a->sig, CCV_EOF_SIGN); |
349 | 0 | type = ((type == 0) || (type & CCV_32F) || (type & CCV_64F)) ? CCV_GET_DATA_TYPE(a->type) | CCV_C1 : CCV_GET_DATA_TYPE(type) | CCV_C1; |
350 | 0 | ccv_dense_matrix_t* db = *b = ccv_dense_matrix_renew(*b, a->rows, a->cols, CCV_C1 | CCV_ALL_DATA_TYPE, type, sig); |
351 | 0 | ccv_object_return_if_cached(, db); |
352 | 0 | int i, j; |
353 | 0 | unsigned char* a_ptr = a->data.u8; |
354 | 0 | unsigned char* b_ptr = db->data.u8; |
355 | 0 | ccv_zero(db); |
356 | 0 | #define for_block(_for_get, _for_set_b, _for_get_b) \ |
357 | 0 | for (i = 0; i < a->rows - 1; i++) \ |
358 | 0 | { \ |
359 | 0 | for (j = 0; j < a->cols - 1; j++) \ |
360 | 0 | { \ |
361 | 0 | if (_for_get_b(b_ptr, j) == 0) \ |
362 | 0 | _for_set_b(b_ptr, j, _for_get(a_ptr, j)); \ |
363 | 0 | if (_for_get(a_ptr, j) != 0 && _for_get(a_ptr + a->step, j + 1) != 0) \ |
364 | 0 | { \ |
365 | 0 | _for_set_b(b_ptr + a->step, j, 1); \ |
366 | 0 | _for_set_b(b_ptr, j + 1, 1); \ |
367 | 0 | } \ |
368 | 0 | if (_for_get(a_ptr + a->step, j) != 0 && _for_get(a_ptr, j + 1) != 0) \ |
369 | 0 | { \ |
370 | 0 | _for_set_b(b_ptr, j, 1); \ |
371 | 0 | _for_set_b(b_ptr + a->step, j + 1, 1); \ |
372 | 0 | } \ |
373 | 0 | } \ |
374 | 0 | if (_for_get_b(b_ptr, a->cols - 1) == 0) \ |
375 | 0 | _for_set_b(b_ptr, a->cols - 1, _for_get(a_ptr, a->cols - 1)); \ |
376 | 0 | a_ptr += a->step; \ |
377 | 0 | b_ptr += db->step; \ |
378 | 0 | } \ |
379 | 0 | for (j = 0; j < a->cols; j++) \ |
380 | 0 | { \ |
381 | 0 | if (_for_get_b(b_ptr, j) == 0) \ |
382 | 0 | _for_set_b(b_ptr, j, _for_get(a_ptr, j)); \ |
383 | 0 | } |
384 | 0 | ccv_matrix_getter_integer_only(a->type, ccv_matrix_setter_getter_integer_only, db->type, for_block); |
385 | 0 | #undef for_block |
386 | 0 | } |
387 | | |
388 | | int ccv_otsu(ccv_dense_matrix_t* a, double* outvar, int range) |
389 | 1 | { |
390 | 1 | assert((a->type & CCV_32S) || (a->type & CCV_8U)); |
391 | 1 | int* histogram = (int*)alloca(range * sizeof(int)); |
392 | 1 | memset(histogram, 0, sizeof(int) * range); |
393 | 1 | int i, j; |
394 | 1 | unsigned char* a_ptr = a->data.u8; |
395 | 1 | #define for_block(_, _for_get) \ |
396 | 7 | for (i = 0; 1 i < a->rows; i++6 ) \ |
397 | 6 | { \ |
398 | 42 | for (j = 0; j < a->cols; j++36 ) \ |
399 | 36 | histogram[ccv_clamp((int)_for_get(a_ptr, j), 0, range - 1)]++; \ |
400 | 6 | a_ptr += a->step; \ |
401 | 6 | } |
402 | 1 | ccv_matrix_getter(a->type, for_block); |
403 | 1 | #undef for_block |
404 | 1 | double sum = 0, sumB = 0; |
405 | 7 | for (i = 0; i < range; i++6 ) |
406 | 6 | sum += i * histogram[i]; |
407 | 1 | int wB = 0, wF = 0, total = a->rows * a->cols; |
408 | 1 | double maxVar = 0; |
409 | 1 | int threshold = 0; |
410 | 6 | for (i = 0; i < range; i++5 ) |
411 | 6 | { |
412 | 6 | wB += histogram[i]; |
413 | 6 | if (wB == 0) |
414 | 0 | continue; |
415 | 6 | wF = total - wB; |
416 | 6 | if (wF == 0) |
417 | 1 | break; |
418 | 5 | sumB += i * histogram[i]; |
419 | 5 | double mB = sumB / wB; |
420 | 5 | double mF = (sum - sumB) / wF; |
421 | 5 | double var = wB * wF * (mB - mF) * (mB - mF); |
422 | 5 | if (var > maxVar) |
423 | 3 | { |
424 | 3 | maxVar = var; |
425 | 3 | threshold = i; |
426 | 3 | } |
427 | 5 | } |
428 | 1 | if (outvar != 0) |
429 | 1 | *outvar = maxVar / total / total; |
430 | 1 | return threshold; |
431 | 1 | } |
432 | | |
433 | 0 | #define LK_MAX_ITER (30) |
434 | 0 | #define LK_EPSILON (0.01) |
435 | | |
436 | | /* this code is a rewrite from OpenCV's legendary Lucas-Kanade optical flow implementation */ |
437 | | void ccv_optical_flow_lucas_kanade(ccv_dense_matrix_t* a, ccv_dense_matrix_t* b, ccv_array_t* point_a, ccv_array_t** point_b, ccv_size_t win_size, int level, double min_eigen) |
438 | 0 | { |
439 | 0 | assert(a && b && a->rows == b->rows && a->cols == b->cols); |
440 | 0 | assert(CCV_GET_CHANNEL(a->type) == CCV_GET_CHANNEL(b->type) && CCV_GET_DATA_TYPE(a->type) == CCV_GET_DATA_TYPE(b->type)); |
441 | 0 | assert(CCV_GET_CHANNEL(a->type) == 1); |
442 | 0 | assert(CCV_GET_DATA_TYPE(a->type) == CCV_8U); |
443 | 0 | assert(point_a->rnum > 0); |
444 | 0 | level = ccv_clamp(level + 1, 1, (int)(log((double)ccv_min(a->rows, a->cols) / ccv_max(win_size.width * 2, win_size.height * 2)) / log(2.0) + 0.5)); |
445 | 0 | ccv_declare_derived_signature(sig, a->sig != 0 && b->sig != 0 && point_a->sig != 0, ccv_sign_with_format(128, "ccv_optical_flow_lucas_kanade(%d,%d,%d,%la)", win_size.width, win_size.height, level, min_eigen), a->sig, b->sig, point_a->sig, CCV_EOF_SIGN); |
446 | 0 | ccv_array_t* seq = *point_b = ccv_array_new(sizeof(ccv_decimal_point_with_status_t), point_a->rnum, sig); |
447 | 0 | ccv_object_return_if_cached(, seq); |
448 | 0 | seq->rnum = point_a->rnum; |
449 | 0 | ccv_dense_matrix_t** pyr_a = (ccv_dense_matrix_t**)alloca(sizeof(ccv_dense_matrix_t*) * level); |
450 | 0 | ccv_dense_matrix_t** pyr_a_dx = (ccv_dense_matrix_t**)alloca(sizeof(ccv_dense_matrix_t*) * level); |
451 | 0 | ccv_dense_matrix_t** pyr_a_dy = (ccv_dense_matrix_t**)alloca(sizeof(ccv_dense_matrix_t*) * level); |
452 | 0 | ccv_dense_matrix_t** pyr_b = (ccv_dense_matrix_t**)alloca(sizeof(ccv_dense_matrix_t*) * level); |
453 | 0 | int i, j, t, x, y; |
454 | | /* generating image pyramid */ |
455 | 0 | pyr_a[0] = a; |
456 | 0 | pyr_a_dx[0] = pyr_a_dy[0] = 0; |
457 | 0 | ccv_sobel(pyr_a[0], &pyr_a_dx[0], 0, 3, 0); |
458 | 0 | ccv_sobel(pyr_a[0], &pyr_a_dy[0], 0, 0, 3); |
459 | 0 | pyr_b[0] = b; |
460 | 0 | for (i = 1; i < level; i++) |
461 | 0 | { |
462 | 0 | pyr_a[i] = pyr_a_dx[i] = pyr_a_dy[i] = pyr_b[i] = 0; |
463 | 0 | ccv_sample_down(pyr_a[i - 1], &pyr_a[i], 0, 0, 0); |
464 | 0 | ccv_sobel(pyr_a[i], &pyr_a_dx[i], 0, 3, 0); |
465 | 0 | ccv_sobel(pyr_a[i], &pyr_a_dy[i], 0, 0, 3); |
466 | 0 | ccv_sample_down(pyr_b[i - 1], &pyr_b[i], 0, 0, 0); |
467 | 0 | } |
468 | 0 | int* wi = (int*)alloca(sizeof(int) * win_size.width * win_size.height); |
469 | 0 | int* widx = (int*)alloca(sizeof(int) * win_size.width * win_size.height); |
470 | 0 | int* widy = (int*)alloca(sizeof(int) * win_size.width * win_size.height); |
471 | 0 | ccv_decimal_point_t half_win = ccv_decimal_point((win_size.width - 1) * 0.5f, (win_size.height - 1) * 0.5f); |
472 | 0 | const int W_BITS14 = 14, W_BITS7 = 7, W_BITS9 = 9; |
473 | 0 | const float FLT_SCALE = 1.0f / (1 << 25); |
474 | | // clean up status to 1 |
475 | 0 | for (i = 0; i < point_a->rnum; i++) |
476 | 0 | { |
477 | 0 | ccv_decimal_point_with_status_t* point_with_status = (ccv_decimal_point_with_status_t*)ccv_array_get(seq, i); |
478 | 0 | point_with_status->status = 1; |
479 | 0 | } |
480 | 0 | int prev_rows, prev_cols; |
481 | 0 | for (t = level - 1; t >= 0; t--) |
482 | 0 | { |
483 | 0 | ccv_dense_matrix_t* a = pyr_a[t]; |
484 | 0 | ccv_dense_matrix_t* adx = pyr_a_dx[t]; |
485 | 0 | ccv_dense_matrix_t* ady = pyr_a_dy[t]; |
486 | 0 | assert(CCV_GET_DATA_TYPE(adx->type) == CCV_32S); |
487 | 0 | assert(CCV_GET_DATA_TYPE(ady->type) == CCV_32S); |
488 | 0 | ccv_dense_matrix_t* b = pyr_b[t]; |
489 | 0 | for (i = 0; i < point_a->rnum; i++) |
490 | 0 | { |
491 | 0 | ccv_decimal_point_t prev_point = *(ccv_decimal_point_t*)ccv_array_get(point_a, i); |
492 | 0 | ccv_decimal_point_with_status_t* point_with_status = (ccv_decimal_point_with_status_t*)ccv_array_get(seq, i); |
493 | 0 | prev_point.x = prev_point.x / (float)(1 << t); |
494 | 0 | prev_point.y = prev_point.y / (float)(1 << t); |
495 | 0 | ccv_decimal_point_t next_point; |
496 | 0 | if (t == level - 1) |
497 | 0 | next_point = prev_point; |
498 | 0 | else { |
499 | 0 | next_point.x = point_with_status->point.x * 2 + (a->cols - prev_cols * 2) * 0.5; |
500 | 0 | next_point.y = point_with_status->point.y * 2 + (a->rows - prev_rows * 2) * 0.5; |
501 | 0 | } |
502 | 0 | point_with_status->point = next_point; |
503 | 0 | prev_point.x -= half_win.x; |
504 | 0 | prev_point.y -= half_win.y; |
505 | 0 | ccv_point_t iprev_point = ccv_point((int)prev_point.x, (int)prev_point.y); |
506 | 0 | if (iprev_point.x < 0 || iprev_point.x >= a->cols - win_size.width - 1 || |
507 | 0 | iprev_point.y < 0 || iprev_point.y >= a->rows - win_size.height - 1) |
508 | 0 | { |
509 | 0 | if (t == 0) |
510 | 0 | point_with_status->status = 0; |
511 | 0 | continue; |
512 | 0 | } |
513 | 0 | float xd = prev_point.x - iprev_point.x; |
514 | 0 | float yd = prev_point.y - iprev_point.y; |
515 | 0 | int iw00 = (int)((1 - xd) * (1 - yd) * (1 << W_BITS14) + 0.5); |
516 | 0 | int iw01 = (int)(xd * (1 - yd) * (1 << W_BITS14) + 0.5); |
517 | 0 | int iw10 = (int)((1 - xd) * yd * (1 << W_BITS14) + 0.5); |
518 | 0 | int iw11 = (1 << W_BITS14) - iw00 - iw01 - iw10; |
519 | 0 | float a11 = 0, a12 = 0, a22 = 0; |
520 | 0 | unsigned char* a_ptr = (unsigned char*)ccv_get_dense_matrix_cell_by(CCV_C1 | CCV_8U, a, iprev_point.y, iprev_point.x, 0); |
521 | 0 | int* adx_ptr = (int*)ccv_get_dense_matrix_cell_by(CCV_C1 | CCV_32S, adx, iprev_point.y, iprev_point.x, 0); |
522 | 0 | int* ady_ptr = (int*)ccv_get_dense_matrix_cell_by(CCV_C1 | CCV_32S, ady, iprev_point.y, iprev_point.x, 0); |
523 | 0 | int* wi_ptr = wi; |
524 | 0 | int* widx_ptr = widx; |
525 | 0 | int* widy_ptr = widy; |
526 | 0 | for (y = 0; y < win_size.height; y++) |
527 | 0 | { |
528 | 0 | for (x = 0; x < win_size.width; x++) |
529 | 0 | { |
530 | 0 | wi_ptr[x] = ccv_descale(a_ptr[x] * iw00 + a_ptr[x + 1] * iw01 + a_ptr[x + a->step] * iw10 + a_ptr[x + a->step + 1] * iw11, W_BITS7); |
531 | | // because we use 3x3 sobel, which scaled derivative up by 4 |
532 | 0 | widx_ptr[x] = ccv_descale(adx_ptr[x] * iw00 + adx_ptr[x + 1] * iw01 + adx_ptr[x + adx->cols] * iw10 + adx_ptr[x + adx->cols + 1] * iw11, W_BITS9); |
533 | 0 | widy_ptr[x] = ccv_descale(ady_ptr[x] * iw00 + ady_ptr[x + 1] * iw01 + ady_ptr[x + ady->cols] + iw10 + ady_ptr[x + ady->cols + 1] * iw11, W_BITS9); |
534 | 0 | a11 += (float)(widx_ptr[x] * widx_ptr[x]); |
535 | 0 | a12 += (float)(widx_ptr[x] * widy_ptr[x]); |
536 | 0 | a22 += (float)(widy_ptr[x] * widy_ptr[x]); |
537 | 0 | } |
538 | 0 | a_ptr += a->step; |
539 | 0 | adx_ptr += adx->cols; |
540 | 0 | ady_ptr += ady->cols; |
541 | 0 | wi_ptr += win_size.width; |
542 | 0 | widx_ptr += win_size.width; |
543 | 0 | widy_ptr += win_size.width; |
544 | 0 | } |
545 | 0 | a11 *= FLT_SCALE; |
546 | 0 | a12 *= FLT_SCALE; |
547 | 0 | a22 *= FLT_SCALE; |
548 | 0 | float D = a11 * a22 - a12 * a12; |
549 | 0 | float eigen = (a22 + a11 - sqrtf((a11 - a22) * (a11 - a22) + 4.0f * a12 * a12)) / (2 * win_size.width * win_size.height); |
550 | 0 | if (eigen < min_eigen || D < FLT_EPSILON) |
551 | 0 | { |
552 | 0 | if (t == 0) |
553 | 0 | point_with_status->status = 0; |
554 | 0 | continue; |
555 | 0 | } |
556 | 0 | D = 1.0f / D; |
557 | 0 | next_point.x -= half_win.x; |
558 | 0 | next_point.y -= half_win.y; |
559 | 0 | ccv_decimal_point_t prev_delta; |
560 | 0 | for (j = 0; j < LK_MAX_ITER; j++) |
561 | 0 | { |
562 | 0 | ccv_point_t inext_point = ccv_point((int)next_point.x, (int)next_point.y); |
563 | 0 | if (inext_point.x < 0 || inext_point.x >= a->cols - win_size.width - 1 || |
564 | 0 | inext_point.y < 0 || inext_point.y >= a->rows - win_size.height - 1) |
565 | 0 | break; |
566 | 0 | float xd = next_point.x - inext_point.x; |
567 | 0 | float yd = next_point.y - inext_point.y; |
568 | 0 | int iw00 = (int)((1 - xd) * (1 - yd) * (1 << W_BITS14) + 0.5); |
569 | 0 | int iw01 = (int)(xd * (1 - yd) * (1 << W_BITS14) + 0.5); |
570 | 0 | int iw10 = (int)((1 - xd) * yd * (1 << W_BITS14) + 0.5); |
571 | 0 | int iw11 = (1 << W_BITS14) - iw00 - iw01 - iw10; |
572 | 0 | float b1 = 0, b2 = 0; |
573 | 0 | unsigned char* b_ptr = (unsigned char*)ccv_get_dense_matrix_cell_by(CCV_C1 | CCV_8U, b, inext_point.y, inext_point.x, 0); |
574 | 0 | int* wi_ptr = wi; |
575 | 0 | int* widx_ptr = widx; |
576 | 0 | int* widy_ptr = widy; |
577 | 0 | for (y = 0; y < win_size.height; y++) |
578 | 0 | { |
579 | 0 | for (x = 0; x < win_size.width; x++) |
580 | 0 | { |
581 | 0 | int diff = ccv_descale(b_ptr[x] * iw00 + b_ptr[x + 1] * iw01 + b_ptr[x + b->step] * iw10 + b_ptr[x + b->step + 1] * iw11, W_BITS7) - wi_ptr[x]; |
582 | 0 | b1 += (float)(diff * widx_ptr[x]); |
583 | 0 | b2 += (float)(diff * widy_ptr[x]); |
584 | 0 | } |
585 | 0 | b_ptr += b->step; |
586 | 0 | wi_ptr += win_size.width; |
587 | 0 | widx_ptr += win_size.width; |
588 | 0 | widy_ptr += win_size.width; |
589 | 0 | } |
590 | 0 | b1 *= FLT_SCALE; |
591 | 0 | b2 *= FLT_SCALE; |
592 | 0 | ccv_decimal_point_t delta = ccv_decimal_point((a12 * b2 - a22 * b1) * D, (a12 * b1 - a11 * b2) * D); |
593 | 0 | next_point.x += delta.x; |
594 | 0 | next_point.y += delta.y; |
595 | 0 | if (delta.x * delta.x + delta.y * delta.y < LK_EPSILON) |
596 | 0 | break; |
597 | 0 | if (j > 0 && fabs(prev_delta.x - delta.x) < 0.01 && fabs(prev_delta.y - delta.y) < 0.01) |
598 | 0 | { |
599 | 0 | next_point.x -= delta.x * 0.5; |
600 | 0 | next_point.y -= delta.y * 0.5; |
601 | 0 | break; |
602 | 0 | } |
603 | 0 | prev_delta = delta; |
604 | 0 | } |
605 | 0 | ccv_point_t inext_point = ccv_point((int)next_point.x, (int)next_point.y); |
606 | 0 | if (inext_point.x < 0 || inext_point.x >= a->cols - win_size.width - 1 || |
607 | 0 | inext_point.y < 0 || inext_point.y >= a->rows - win_size.height - 1) |
608 | 0 | point_with_status->status = 0; |
609 | 0 | else { |
610 | 0 | point_with_status->point.x = next_point.x + half_win.x; |
611 | 0 | point_with_status->point.y = next_point.y + half_win.y; |
612 | 0 | } |
613 | 0 | } |
614 | 0 | prev_rows = a->rows; |
615 | 0 | prev_cols = a->cols; |
616 | 0 | ccv_matrix_free(adx); |
617 | 0 | ccv_matrix_free(ady); |
618 | 0 | if (t > 0) |
619 | 0 | { |
620 | 0 | ccv_matrix_free(a); |
621 | 0 | ccv_matrix_free(b); |
622 | 0 | } |
623 | 0 | } |
624 | 0 | } |