File: | ccv_tld.c |
Warning: | line 959, column 44 Division by zero |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | #include "ccv.h" | |||
2 | #include "ccv_internal.h" | |||
3 | #include "3rdparty/sfmt/SFMT.h" | |||
4 | #include "3rdparty/dsfmt/dSFMT.h" | |||
5 | ||||
6 | const ccv_tld_param_t ccv_tld_default_params = { | |||
7 | .win_size = { | |||
8 | 15, | |||
9 | 15, | |||
10 | }, | |||
11 | .level = 5, | |||
12 | .min_forward_backward_error = 100, | |||
13 | .min_eigen = 0.025, | |||
14 | .min_win = 20, | |||
15 | .interval = 3, | |||
16 | .shift = 0.1, | |||
17 | .top_n = 100, | |||
18 | .rotation = 0, | |||
19 | .include_overlap = 0.7, | |||
20 | .exclude_overlap = 0.2, | |||
21 | .structs = 40, | |||
22 | .features = 18, | |||
23 | .validate_set = 0.5, | |||
24 | .nnc_same = 0.95, | |||
25 | .nnc_thres = 0.65, | |||
26 | .nnc_verify = 0.7, | |||
27 | .nnc_beyond = 0.8, | |||
28 | .nnc_collect = 0.5, | |||
29 | .bad_patches = 100, | |||
30 | .new_deform = 20, | |||
31 | .track_deform = 10, | |||
32 | .new_deform_angle = 20, | |||
33 | .track_deform_angle = 10, | |||
34 | .new_deform_scale = 0.02, | |||
35 | .track_deform_scale = 0.02, | |||
36 | .new_deform_shift = 0.02, | |||
37 | .track_deform_shift = 0.02, | |||
38 | }; | |||
39 | ||||
40 | #define TLD_GRID_SPARSITY(10) (10) | |||
41 | #define TLD_PATCH_SIZE(10) (10) | |||
42 | ||||
43 | static CCV_IMPLEMENT_MEDIAN(_ccv_tld_median, float)float _ccv_tld_median(float* buf, int low, int high) { float w ; int middle, ll, hh; int median = (low + high) / 2; for (;;) { if (high <= low) return buf[median]; if (high == low + 1 ) { if (buf[low] > buf[high]) ((w) = (buf[low]), (buf[low] ) = (buf[high]), (buf[high]) = (w)); return buf[median]; } middle = (low + high) / 2; if (buf[middle] > buf[high]) ((w) = ( buf[middle]), (buf[middle]) = (buf[high]), (buf[high]) = (w)) ; if (buf[low] > buf[high]) ((w) = (buf[low]), (buf[low]) = (buf[high]), (buf[high]) = (w)); if (buf[middle] > buf[low ]) ((w) = (buf[middle]), (buf[middle]) = (buf[low]), (buf[low ]) = (w)); ((w) = (buf[middle]), (buf[middle]) = (buf[low + 1 ]), (buf[low + 1]) = (w)); ll = low + 1; hh = high; for (;;) { do ll++; while (buf[low] > buf[ll]); do hh--; while (buf[ hh] > buf[low]); if (hh < ll) break; ((w) = (buf[ll]), ( buf[ll]) = (buf[hh]), (buf[hh]) = (w)); } ((w) = (buf[low]), ( buf[low]) = (buf[hh]), (buf[hh]) = (w)); if (hh <= median) low = ll; else if (hh >= median) high = hh - 1; } } | |||
44 | ||||
45 | static float _ccv_tld_norm_cross_correlate(ccv_dense_matrix_t* r0, ccv_dense_matrix_t* r1) | |||
46 | { | |||
47 | assert(CCV_GET_CHANNEL(r0->type) == CCV_C1 && CCV_GET_DATA_TYPE(r0->type) == CCV_8U)((void) sizeof ((((r0->type) & 0xFFF) == CCV_C1 && ((r0->type) & 0xFF000) == CCV_8U) ? 1 : 0), __extension__ ({ if (((r0->type) & 0xFFF) == CCV_C1 && ((r0 ->type) & 0xFF000) == CCV_8U) ; else __assert_fail ("CCV_GET_CHANNEL(r0->type) == CCV_C1 && CCV_GET_DATA_TYPE(r0->type) == CCV_8U" , "ccv_tld.c", 47, __extension__ __PRETTY_FUNCTION__); })); | |||
48 | assert(CCV_GET_CHANNEL(r1->type) == CCV_C1 && CCV_GET_DATA_TYPE(r1->type) == CCV_8U)((void) sizeof ((((r1->type) & 0xFFF) == CCV_C1 && ((r1->type) & 0xFF000) == CCV_8U) ? 1 : 0), __extension__ ({ if (((r1->type) & 0xFFF) == CCV_C1 && ((r1 ->type) & 0xFF000) == CCV_8U) ; else __assert_fail ("CCV_GET_CHANNEL(r1->type) == CCV_C1 && CCV_GET_DATA_TYPE(r1->type) == CCV_8U" , "ccv_tld.c", 48, __extension__ __PRETTY_FUNCTION__); })); | |||
49 | assert(r0->rows == r1->rows && r0->cols == r1->cols)((void) sizeof ((r0->rows == r1->rows && r0-> cols == r1->cols) ? 1 : 0), __extension__ ({ if (r0->rows == r1->rows && r0->cols == r1->cols) ; else __assert_fail ("r0->rows == r1->rows && r0->cols == r1->cols" , "ccv_tld.c", 49, __extension__ __PRETTY_FUNCTION__); })); | |||
50 | int x, y; | |||
51 | int sum0 = 0, sum1 = 0; | |||
52 | unsigned char* r0_ptr = r0->data.u8; | |||
53 | unsigned char* r1_ptr = r1->data.u8; | |||
54 | for (y = 0; y < r0->rows; y++) | |||
55 | { | |||
56 | for (x = 0; x < r0->cols; x++) | |||
57 | { | |||
58 | sum0 += r0_ptr[x]; | |||
59 | sum1 += r1_ptr[x]; | |||
60 | } | |||
61 | r0_ptr += r0->step; | |||
62 | r1_ptr += r1->step; | |||
63 | } | |||
64 | r0_ptr = r0->data.u8; | |||
65 | r1_ptr = r1->data.u8; | |||
66 | float mr0 = (float)sum0 / (r0->rows * r0->cols); | |||
67 | float mr1 = (float)sum1 / (r1->rows * r1->cols); | |||
68 | float r0r1 = 0, r0r0 = 0, r1r1 = 0; | |||
69 | for (y = 0; y < r0->rows; y++) | |||
70 | { | |||
71 | for (x = 0; x < r0->cols; x++) | |||
72 | { | |||
73 | float r0f = r0_ptr[x] - mr0; | |||
74 | float r1f = r1_ptr[x] - mr1; | |||
75 | r0r1 += r0f * r1f; | |||
76 | r0r0 += r0f * r0f; | |||
77 | r1r1 += r1f * r1f; | |||
78 | } | |||
79 | r0_ptr += r0->step; | |||
80 | r1_ptr += r1->step; | |||
81 | } | |||
82 | if (r0r0 * r1r1 < 1e-6) | |||
83 | return 0; | |||
84 | return r0r1 / sqrtf(r0r0 * r1r1); | |||
85 | } | |||
86 | ||||
87 | static ccv_rect_t _ccv_tld_short_term_track(ccv_dense_matrix_t* a, ccv_dense_matrix_t* b, ccv_rect_t box, ccv_tld_param_t params) | |||
88 | { | |||
89 | ccv_rect_t newbox = ccv_rect(0, 0, 0, 0); | |||
90 | ccv_array_t* point_a = ccv_array_new(sizeof(ccv_decimal_point_t), (TLD_GRID_SPARSITY(10) - 1) * (TLD_GRID_SPARSITY(10) - 1), 0); | |||
91 | float gapx = (float)box.width / TLD_GRID_SPARSITY(10); | |||
92 | float gapy = (float)box.height / TLD_GRID_SPARSITY(10); | |||
93 | float x, y; | |||
94 | for (x = gapx * 0.5; x < box.width; x += gapx) | |||
95 | for (y = gapy * 0.5; y < box.height; y += gapy) | |||
96 | { | |||
97 | ccv_decimal_point_t point = ccv_decimal_point(box.x + x, box.y + y); | |||
98 | ccv_array_push(point_a, &point); | |||
99 | } | |||
100 | if (point_a->rnum <= 0) | |||
101 | { | |||
102 | ccv_array_free(point_a); | |||
103 | return newbox; | |||
104 | } | |||
105 | ccv_array_t* point_b = 0; | |||
106 | ccv_optical_flow_lucas_kanade(a, b, point_a, &point_b, params.win_size, params.level, params.min_eigen); | |||
107 | if (point_b->rnum <= 0) | |||
108 | { | |||
109 | ccv_array_free(point_b); | |||
110 | ccv_array_free(point_a); | |||
111 | return newbox; | |||
112 | } | |||
113 | ccv_array_t* point_c = 0; | |||
114 | ccv_optical_flow_lucas_kanade(b, a, point_b, &point_c, params.win_size, params.level, params.min_eigen); | |||
115 | // compute forward-backward error | |||
116 | ccv_dense_matrix_t* r0 = (ccv_dense_matrix_t*)alloca(ccv_compute_dense_matrix_size(TLD_PATCH_SIZE, TLD_PATCH_SIZE, CCV_8U | CCV_C1))__builtin_alloca ((((sizeof(ccv_dense_matrix_t) + 63) & - 64) + ((((10)) * _ccv_get_data_type_size[((CCV_8U | CCV_C1) & 0xFF000) >> 12] * ((CCV_8U | CCV_C1) & 0xFFF) + 3) & -4) * ((10)))); | |||
117 | ccv_dense_matrix_t* r1 = (ccv_dense_matrix_t*)alloca(ccv_compute_dense_matrix_size(TLD_PATCH_SIZE, TLD_PATCH_SIZE, CCV_8U | CCV_C1))__builtin_alloca ((((sizeof(ccv_dense_matrix_t) + 63) & - 64) + ((((10)) * _ccv_get_data_type_size[((CCV_8U | CCV_C1) & 0xFF000) >> 12] * ((CCV_8U | CCV_C1) & 0xFFF) + 3) & -4) * ((10)))); | |||
118 | r0 = ccv_dense_matrix_new(TLD_PATCH_SIZE(10), TLD_PATCH_SIZE(10), CCV_8U | CCV_C1, r0, 0); | |||
119 | r1 = ccv_dense_matrix_new(TLD_PATCH_SIZE(10), TLD_PATCH_SIZE(10), CCV_8U | CCV_C1, r1, 0); | |||
120 | int i, j, k, size; | |||
121 | int* wrt = (int*)alloca(sizeof(int) * point_a->rnum)__builtin_alloca (sizeof(int) * point_a->rnum); | |||
122 | { // will reclaim the stack | |||
123 | float* fberr = (float*)alloca(sizeof(float) * point_a->rnum)__builtin_alloca (sizeof(float) * point_a->rnum); | |||
124 | float* sim = (float*)alloca(sizeof(float) * point_a->rnum)__builtin_alloca (sizeof(float) * point_a->rnum); | |||
125 | for (i = 0, k = 0; i < point_a->rnum; i++) | |||
126 | { | |||
127 | ccv_decimal_point_t* p0 = (ccv_decimal_point_t*)ccv_array_get(point_a, i)((void*)(((char*)((point_a)->data)) + (size_t)(point_a)-> rsize * (size_t)(i))); | |||
128 | ccv_decimal_point_with_status_t* p1 = (ccv_decimal_point_with_status_t*)ccv_array_get(point_b, i)((void*)(((char*)((point_b)->data)) + (size_t)(point_b)-> rsize * (size_t)(i))); | |||
129 | ccv_decimal_point_with_status_t* p2 = (ccv_decimal_point_with_status_t*)ccv_array_get(point_c, i)((void*)(((char*)((point_c)->data)) + (size_t)(point_c)-> rsize * (size_t)(i))); | |||
130 | if (p1->status && p2->status && | |||
131 | p1->point.x >= 0 && p1->point.x < a->cols && p1->point.y >= 0 && p1->point.y < a->rows && | |||
132 | p2->point.x >= 0 && p2->point.x < a->cols && p2->point.y >= 0 && p2->point.y < a->rows) | |||
133 | { | |||
134 | fberr[k] = (p2->point.x - p0->x) * (p2->point.x - p0->x) + (p2->point.y - p0->y) * (p2->point.y - p0->y); | |||
135 | ccv_decimal_slice(a, &r0, 0, p0->y - (TLD_PATCH_SIZE(10) - 1) * 0.5, p0->x - (TLD_PATCH_SIZE(10) - 1) * 0.5, TLD_PATCH_SIZE(10), TLD_PATCH_SIZE(10)); | |||
136 | ccv_decimal_slice(b, &r1, 0, p1->point.y - (TLD_PATCH_SIZE(10) - 1) * 0.5, p1->point.x - (TLD_PATCH_SIZE(10) - 1) * 0.5, TLD_PATCH_SIZE(10), TLD_PATCH_SIZE(10)); | |||
137 | sim[k] = _ccv_tld_norm_cross_correlate(r0, r1); | |||
138 | wrt[k] = i; | |||
139 | ++k; | |||
140 | } | |||
141 | } | |||
142 | ccv_array_free(point_c); | |||
143 | if (k == 0) | |||
144 | { | |||
145 | // early termination because we don't have qualified tracking points | |||
146 | ccv_array_free(point_b); | |||
147 | ccv_array_free(point_a); | |||
148 | return newbox; | |||
149 | } | |||
150 | size = k; | |||
151 | float simmd = _ccv_tld_median(sim, 0, size - 1); | |||
152 | for (i = 0, k = 0; i < size; i++) | |||
153 | if (sim[i] > simmd) | |||
154 | { | |||
155 | fberr[k] = fberr[i]; | |||
156 | wrt[k] = wrt[i]; | |||
157 | ++k; | |||
158 | } | |||
159 | size = k; | |||
160 | float fberrmd = _ccv_tld_median(fberr, 0, size - 1); | |||
161 | if (fberrmd >= params.min_forward_backward_error) | |||
162 | { | |||
163 | // early termination because we don't have qualified tracking points | |||
164 | ccv_array_free(point_b); | |||
165 | ccv_array_free(point_a); | |||
166 | return newbox; | |||
167 | } | |||
168 | size = k; | |||
169 | for (i = 0, k = 0; i < size; i++) | |||
170 | if (fberr[i] <= fberrmd) | |||
171 | wrt[k++] = wrt[i]; | |||
172 | size = k; | |||
173 | if (k == 0) | |||
174 | { | |||
175 | // early termination because we don't have qualified tracking points | |||
176 | ccv_array_free(point_b); | |||
177 | ccv_array_free(point_a); | |||
178 | return newbox; | |||
179 | } | |||
180 | } // reclaim stack | |||
181 | float dx, dy; | |||
182 | { // will reclaim the stack | |||
183 | float* offx = (float*)alloca(sizeof(float) * size)__builtin_alloca (sizeof(float) * size); | |||
184 | float* offy = (float*)alloca(sizeof(float) * size)__builtin_alloca (sizeof(float) * size); | |||
185 | for (i = 0; i < size; i++) | |||
186 | { | |||
187 | ccv_decimal_point_t* p0 = (ccv_decimal_point_t*)ccv_array_get(point_a, wrt[i])((void*)(((char*)((point_a)->data)) + (size_t)(point_a)-> rsize * (size_t)(wrt[i]))); | |||
188 | ccv_decimal_point_t* p1 = (ccv_decimal_point_t*)ccv_array_get(point_b, wrt[i])((void*)(((char*)((point_b)->data)) + (size_t)(point_b)-> rsize * (size_t)(wrt[i]))); | |||
189 | offx[i] = p1->x - p0->x; | |||
190 | offy[i] = p1->y - p0->y; | |||
191 | } | |||
192 | dx = _ccv_tld_median(offx, 0, size - 1); | |||
193 | dy = _ccv_tld_median(offy, 0, size - 1); | |||
194 | } // reclaim stack | |||
195 | if (size > 1) | |||
196 | { | |||
197 | float* s = (float*)alloca(sizeof(float) * size * (size - 1) / 2)__builtin_alloca (sizeof(float) * size * (size - 1) / 2); | |||
198 | k = 0; | |||
199 | for (i = 0; i < size - 1; i++) | |||
200 | { | |||
201 | ccv_decimal_point_t* p0i = (ccv_decimal_point_t*)ccv_array_get(point_a, wrt[i])((void*)(((char*)((point_a)->data)) + (size_t)(point_a)-> rsize * (size_t)(wrt[i]))); | |||
202 | ccv_decimal_point_t* p1i = (ccv_decimal_point_t*)ccv_array_get(point_b, wrt[i])((void*)(((char*)((point_b)->data)) + (size_t)(point_b)-> rsize * (size_t)(wrt[i]))); | |||
203 | for (j = i + 1; j < size; j++) | |||
204 | { | |||
205 | ccv_decimal_point_t* p0j = (ccv_decimal_point_t*)ccv_array_get(point_a, wrt[j])((void*)(((char*)((point_a)->data)) + (size_t)(point_a)-> rsize * (size_t)(wrt[j]))); | |||
206 | ccv_decimal_point_t* p1j = (ccv_decimal_point_t*)ccv_array_get(point_b, wrt[j])((void*)(((char*)((point_b)->data)) + (size_t)(point_b)-> rsize * (size_t)(wrt[j]))); | |||
207 | s[k] = sqrtf(((p1i->x - p1j->x) * (p1i->x - p1j->x) + (p1i->y - p1j->y) * (p1i->y - p1j->y)) / | |||
208 | ((p0i->x - p0j->x) * (p0i->x - p0j->x) + (p0i->y - p0j->y) * (p0i->y - p0j->y))); | |||
209 | ++k; | |||
210 | } | |||
211 | } | |||
212 | assert(size * (size - 1) / 2 == k)((void) sizeof ((size * (size - 1) / 2 == k) ? 1 : 0), __extension__ ({ if (size * (size - 1) / 2 == k) ; else __assert_fail ("size * (size - 1) / 2 == k" , "ccv_tld.c", 212, __extension__ __PRETTY_FUNCTION__); })); | |||
213 | float ds = _ccv_tld_median(s, 0, size * (size - 1) / 2 - 1); | |||
214 | newbox.x = (int)(box.x + dx - box.width * (ds - 1.0) * 0.5 + 0.5); | |||
215 | newbox.y = (int)(box.y + dy - box.height * (ds - 1.0) * 0.5 + 0.5); | |||
216 | newbox.width = (int)(box.width * ds + 0.5); | |||
217 | newbox.height = (int)(box.height * ds + 0.5); | |||
218 | } else { | |||
219 | newbox.width = box.width; | |||
220 | newbox.height = box.height; | |||
221 | newbox.x = (int)(box.x + dx + 0.5); | |||
222 | newbox.y = (int)(box.y + dy + 0.5); | |||
223 | } | |||
224 | ccv_array_free(point_b); | |||
225 | ccv_array_free(point_a); | |||
226 | return newbox; | |||
227 | } | |||
228 | ||||
229 | static inline float _ccv_tld_rect_intersect(const ccv_rect_t r1, const ccv_rect_t r2) | |||
230 | { | |||
231 | int intersect = ccv_max(0, ccv_min(r1.x + r1.width, r2.x + r2.width) - ccv_max(r1.x, r2.x))({ typeof (0) _a = (0); typeof (({ typeof (r1.x + r1.width) _a = (r1.x + r1.width); typeof (r2.x + r2.width) _b = (r2.x + r2 .width); (_a < _b) ? _a : _b; }) - ({ typeof (r1.x) _a = ( r1.x); typeof (r2.x) _b = (r2.x); (_a > _b) ? _a : _b; })) _b = (({ typeof (r1.x + r1.width) _a = (r1.x + r1.width); typeof (r2.x + r2.width) _b = (r2.x + r2.width); (_a < _b) ? _a : _b; }) - ({ typeof (r1.x) _a = (r1.x); typeof (r2.x) _b = (r2 .x); (_a > _b) ? _a : _b; })); (_a > _b) ? _a : _b; }) * ccv_max(0, ccv_min(r1.y + r1.height, r2.y + r2.height) - ccv_max(r1.y, r2.y))({ typeof (0) _a = (0); typeof (({ typeof (r1.y + r1.height) _a = (r1.y + r1.height); typeof (r2.y + r2.height) _b = (r2.y + r2.height); (_a < _b) ? _a : _b; }) - ({ typeof (r1.y) _a = (r1.y); typeof (r2.y) _b = (r2.y); (_a > _b) ? _a : _b; })) _b = (({ typeof (r1.y + r1.height) _a = (r1.y + r1.height ); typeof (r2.y + r2.height) _b = (r2.y + r2.height); (_a < _b) ? _a : _b; }) - ({ typeof (r1.y) _a = (r1.y); typeof (r2 .y) _b = (r2.y); (_a > _b) ? _a : _b; })); (_a > _b) ? _a : _b; }); | |||
232 | return (float)intersect / (r1.width * r1.height + r2.width * r2.height - intersect); | |||
233 | } | |||
234 | ||||
235 | #define for_each_size(new_width, new_height, box_width, box_height, interval, image_width, image_height){ double scale235 = pow(2.0, 1.0 / (interval + 1.0)); int scale_upto235 = (int)(log((double)({ typeof ((double)image_width / box_width ) _a = ((double)image_width / box_width); typeof ((double)image_height / box_height) _b = ((double)image_height / box_height); (_a < _b) ? _a : _b; })) / log(scale235)); int s235; double ss235 = 1.0; for (s235 = 0; s235 < scale_upto235; s235++) { int new_width = (int)(box_width * ss235 + 0.5); int new_height = (int)(box_height * ss235 + 0.5); ss235 *= scale235; if (new_width > image_width || new_height > image_height) break; \ | |||
236 | { \ | |||
237 | double INTERNAL_CATCH_UNIQUE_NAME(scale)scale237 = pow(2.0, 1.0 / (interval + 1.0)); \ | |||
238 | int INTERNAL_CATCH_UNIQUE_NAME(scale_upto)scale_upto238 = (int)(log((double)ccv_min((double)image_width / box_width, (double)image_height / box_height)({ typeof ((double)image_width / box_width) _a = ((double)image_width / box_width); typeof ((double)image_height / box_height) _b = ((double)image_height / box_height); (_a < _b) ? _a : _b; })) / log(INTERNAL_CATCH_UNIQUE_NAME(scale)scale238)); \ | |||
239 | int INTERNAL_CATCH_UNIQUE_NAME(s)s239; \ | |||
240 | double INTERNAL_CATCH_UNIQUE_NAME(ss)ss240 = 1.0; \ | |||
241 | for (INTERNAL_CATCH_UNIQUE_NAME(s)s241 = 0; INTERNAL_CATCH_UNIQUE_NAME(s)s241 < INTERNAL_CATCH_UNIQUE_NAME(scale_upto)scale_upto241; INTERNAL_CATCH_UNIQUE_NAME(s)s241++) \ | |||
242 | { \ | |||
243 | int new_width = (int)(box_width * INTERNAL_CATCH_UNIQUE_NAME(ss)ss243 + 0.5); \ | |||
244 | int new_height = (int)(box_height * INTERNAL_CATCH_UNIQUE_NAME(ss)ss244 + 0.5); \ | |||
245 | INTERNAL_CATCH_UNIQUE_NAME(ss)ss245 *= INTERNAL_CATCH_UNIQUE_NAME(scale)scale245; \ | |||
246 | if (new_width > image_width || new_height > image_height) \ | |||
247 | break; | |||
248 | #define end_for_each_size} } } } | |||
249 | ||||
250 | #define for_each_box(new_comp, box_width, box_height, interval, shift, image_width, image_height){ { double scale250 = pow(2.0, 1.0 / (interval + 1.0)); int scale_upto250 = (int)(log((double)({ typeof ((double)image_width / box_width ) _a = ((double)image_width / box_width); typeof ((double)image_height / box_height) _b = ((double)image_height / box_height); (_a < _b) ? _a : _b; })) / log(scale250)); int s250; double ss250 = 1.0; for (s250 = 0; s250 < scale_upto250; s250++) { int width250 = (int)(box_width * ss250 + 0.5); int height250 = (int)(box_height * ss250 + 0.5); ss250 *= scale250; if (width250 > image_width || height250 > image_height) break; float x250, y250; int min_side250 = ({ typeof (width250) _a = (width250); typeof ( height250) _b = (height250); (_a < _b) ? _a : _b; }); int piy250 = -1; for (y250 = 0; y250 < image_height - height250 - 0.5 ; y250 += shift * min_side250) { int iy250 = (int)(y250 + 0.5 ); if (iy250 == piy250) continue; piy250 = iy250; int pix250 = -1; for (x250 = 0; x250 < image_width - width250 - 0.5; x250 += shift * min_side250) { int ix250 = (int)(x250 + 0.5); if ( ix250 == pix250) continue; pix250 = ix250; ccv_comp_t new_comp ; new_comp.rect = ccv_rect(ix250, iy250, width250, height250) ; new_comp.classification.id = s250; \ | |||
251 | { \ | |||
252 | for_each_size(INTERNAL_CATCH_UNIQUE_NAME(width), INTERNAL_CATCH_UNIQUE_NAME(height), box_width, box_height, interval, image_width, image_height){ double scale252 = pow(2.0, 1.0 / (interval + 1.0)); int scale_upto252 = (int)(log((double)({ typeof ((double)image_width / box_width ) _a = ((double)image_width / box_width); typeof ((double)image_height / box_height) _b = ((double)image_height / box_height); (_a < _b) ? _a : _b; })) / log(scale252)); int s252; double ss252 = 1.0; for (s252 = 0; s252 < scale_upto252; s252++) { int width252 = (int)(box_width * ss252 + 0.5); int height252 = (int)(box_height * ss252 + 0.5); ss252 *= scale252; if (width252 > image_width || height252 > image_height) break; \ | |||
253 | float INTERNAL_CATCH_UNIQUE_NAME(x)x253, INTERNAL_CATCH_UNIQUE_NAME(y)y253; \ | |||
254 | int INTERNAL_CATCH_UNIQUE_NAME(min_side)min_side254 = ccv_min(INTERNAL_CATCH_UNIQUE_NAME(width), INTERNAL_CATCH_UNIQUE_NAME(height))({ typeof (width254) _a = (width254); typeof (height254) _b = (height254); (_a < _b) ? _a : _b; }); \ | |||
255 | int INTERNAL_CATCH_UNIQUE_NAME(piy)piy255 = -1; \ | |||
256 | for (INTERNAL_CATCH_UNIQUE_NAME(y)y256 = 0; \ | |||
257 | INTERNAL_CATCH_UNIQUE_NAME(y)y257 < image_height - INTERNAL_CATCH_UNIQUE_NAME(height)height257 - 0.5; \ | |||
258 | INTERNAL_CATCH_UNIQUE_NAME(y)y258 += shift * INTERNAL_CATCH_UNIQUE_NAME(min_side)min_side258) /* min_side is exposed by for_each_size, and because the ubiquity of this macro, its name gets leaked */ \ | |||
259 | { \ | |||
260 | int INTERNAL_CATCH_UNIQUE_NAME(iy)iy260 = (int)(INTERNAL_CATCH_UNIQUE_NAME(y)y260 + 0.5); \ | |||
261 | if (INTERNAL_CATCH_UNIQUE_NAME(iy)iy261 == INTERNAL_CATCH_UNIQUE_NAME(piy)piy261) \ | |||
262 | continue; \ | |||
263 | INTERNAL_CATCH_UNIQUE_NAME(piy)piy263 = INTERNAL_CATCH_UNIQUE_NAME(iy)iy263; \ | |||
264 | int INTERNAL_CATCH_UNIQUE_NAME(pix)pix264 = -1; \ | |||
265 | for (INTERNAL_CATCH_UNIQUE_NAME(x)x265 = 0; \ | |||
266 | INTERNAL_CATCH_UNIQUE_NAME(x)x266 < image_width - INTERNAL_CATCH_UNIQUE_NAME(width)width266 - 0.5; \ | |||
267 | INTERNAL_CATCH_UNIQUE_NAME(x)x267 += shift * INTERNAL_CATCH_UNIQUE_NAME(min_side)min_side267) \ | |||
268 | { \ | |||
269 | int INTERNAL_CATCH_UNIQUE_NAME(ix)ix269 = (int)(INTERNAL_CATCH_UNIQUE_NAME(x)x269 + 0.5); \ | |||
270 | if (INTERNAL_CATCH_UNIQUE_NAME(ix)ix270 == INTERNAL_CATCH_UNIQUE_NAME(pix)pix270) \ | |||
271 | continue; \ | |||
272 | INTERNAL_CATCH_UNIQUE_NAME(pix)pix272 = INTERNAL_CATCH_UNIQUE_NAME(ix)ix272; \ | |||
273 | ccv_comp_t new_comp; \ | |||
274 | new_comp.rect = ccv_rect(INTERNAL_CATCH_UNIQUE_NAME(ix)ix274, INTERNAL_CATCH_UNIQUE_NAME(iy)iy274, INTERNAL_CATCH_UNIQUE_NAME(width)width274, INTERNAL_CATCH_UNIQUE_NAME(height)height274); \ | |||
275 | new_comp.classification.id = INTERNAL_CATCH_UNIQUE_NAME(s)s275; | |||
276 | #define end_for_each_box} } } } } } } end_for_each_size} } } | |||
277 | ||||
278 | static void _ccv_tld_box_percolate_down(ccv_array_t* good, int i) | |||
279 | { | |||
280 | for (;;) | |||
281 | { | |||
282 | int left = 2 * (i + 1) - 1; | |||
283 | int right = 2 * (i + 1); | |||
284 | int smallest = i; | |||
285 | ccv_comp_t* smallest_comp = (ccv_comp_t*)ccv_array_get(good, smallest)((void*)(((char*)((good)->data)) + (size_t)(good)->rsize * (size_t)(smallest))); | |||
286 | if (left < good->rnum) | |||
287 | { | |||
288 | ccv_comp_t* left_comp = (ccv_comp_t*)ccv_array_get(good, left)((void*)(((char*)((good)->data)) + (size_t)(good)->rsize * (size_t)(left))); | |||
289 | if (left_comp->classification.confidence < smallest_comp->classification.confidence) | |||
290 | smallest = left; | |||
291 | } | |||
292 | if (right < good->rnum) | |||
293 | { | |||
294 | ccv_comp_t* right_comp = (ccv_comp_t*)ccv_array_get(good, right)((void*)(((char*)((good)->data)) + (size_t)(good)->rsize * (size_t)(right))); | |||
295 | if (right_comp->classification.confidence < smallest_comp->classification.confidence) | |||
296 | smallest = right; | |||
297 | } | |||
298 | if (smallest == i) | |||
299 | break; | |||
300 | ccv_comp_t c = *(ccv_comp_t*)ccv_array_get(good, smallest)((void*)(((char*)((good)->data)) + (size_t)(good)->rsize * (size_t)(smallest))); | |||
301 | *(ccv_comp_t*)ccv_array_get(good, smallest)((void*)(((char*)((good)->data)) + (size_t)(good)->rsize * (size_t)(smallest))) = *(ccv_comp_t*)ccv_array_get(good, i)((void*)(((char*)((good)->data)) + (size_t)(good)->rsize * (size_t)(i))); | |||
302 | *(ccv_comp_t*)ccv_array_get(good, i)((void*)(((char*)((good)->data)) + (size_t)(good)->rsize * (size_t)(i))) = c; | |||
303 | i = smallest; | |||
304 | } | |||
305 | } | |||
306 | ||||
307 | static void _ccv_tld_box_percolate_up(ccv_array_t* good, int smallest) | |||
308 | { | |||
309 | for (;;) | |||
310 | { | |||
311 | int one = smallest; | |||
312 | int parent = (smallest + 1) / 2 - 1; | |||
313 | if (parent < 0) | |||
314 | break; | |||
315 | ccv_comp_t* parent_comp = (ccv_comp_t*)ccv_array_get(good, parent)((void*)(((char*)((good)->data)) + (size_t)(good)->rsize * (size_t)(parent))); | |||
316 | ccv_comp_t* smallest_comp = (ccv_comp_t*)ccv_array_get(good, smallest)((void*)(((char*)((good)->data)) + (size_t)(good)->rsize * (size_t)(smallest))); | |||
317 | if (smallest_comp->classification.confidence < parent_comp->classification.confidence) | |||
318 | { | |||
319 | smallest = parent; | |||
320 | smallest_comp = parent_comp; | |||
321 | } | |||
322 | // if current one is no smaller than the parent one, stop | |||
323 | if (smallest == one) | |||
324 | break; | |||
325 | ccv_comp_t c = *(ccv_comp_t*)ccv_array_get(good, smallest)((void*)(((char*)((good)->data)) + (size_t)(good)->rsize * (size_t)(smallest))); | |||
326 | *(ccv_comp_t*)ccv_array_get(good, smallest)((void*)(((char*)((good)->data)) + (size_t)(good)->rsize * (size_t)(smallest))) = *(ccv_comp_t*)ccv_array_get(good, one)((void*)(((char*)((good)->data)) + (size_t)(good)->rsize * (size_t)(one))); | |||
327 | *(ccv_comp_t*)ccv_array_get(good, one)((void*)(((char*)((good)->data)) + (size_t)(good)->rsize * (size_t)(one))) = c; | |||
328 | int other = 2 * (parent + 1) - !(one & 1); | |||
329 | if (other < good->rnum) | |||
330 | { | |||
331 | ccv_comp_t* other_comp = (ccv_comp_t*)ccv_array_get(good, other)((void*)(((char*)((good)->data)) + (size_t)(good)->rsize * (size_t)(other))); | |||
332 | // if current one is no smaller than the other one, stop, and this requires a percolating down | |||
333 | if (other_comp->classification.confidence < smallest_comp->classification.confidence) | |||
334 | break; | |||
335 | } | |||
336 | } | |||
337 | // have to percolating down to avoid it is bigger than the other side of the sub-tree | |||
338 | _ccv_tld_box_percolate_down(good, smallest); | |||
339 | } | |||
340 | ||||
341 | static ccv_comp_t _ccv_tld_generate_box_for(ccv_size_t image_size, ccv_size_t input_size, ccv_rect_t box, int gcap, ccv_array_t** good, ccv_array_t** bad, ccv_tld_param_t params) | |||
342 | { | |||
343 | assert(gcap > 0)((void) sizeof ((gcap > 0) ? 1 : 0), __extension__ ({ if ( gcap > 0) ; else __assert_fail ("gcap > 0", "ccv_tld.c" , 343, __extension__ __PRETTY_FUNCTION__); })); | |||
344 | ccv_array_t* agood = *good = ccv_array_new(sizeof(ccv_comp_t), gcap, 0); | |||
345 | ccv_array_t* abad = *bad = ccv_array_new(sizeof(ccv_comp_t), 64, 0); | |||
346 | double max_overlap = -DBL_MAX1.7976931348623157e+308; | |||
347 | ccv_comp_t best_box = { | |||
348 | .classification = { | |||
349 | .id = 0, | |||
350 | }, | |||
351 | .rect = ccv_rect(0, 0, 0, 0), | |||
352 | }; | |||
353 | int i = 0; | |||
354 | for_each_box(comp, input_size.width, input_size.height, params.interval, params.shift, image_size.width, image_size.height){ { double scale354 = pow(2.0, 1.0 / (params.interval + 1.0)) ; int scale_upto354 = (int)(log((double)({ typeof ((double)image_size .width / input_size.width) _a = ((double)image_size.width / input_size .width); typeof ((double)image_size.height / input_size.height ) _b = ((double)image_size.height / input_size.height); (_a < _b) ? _a : _b; })) / log(scale354)); int s354; double ss354 = 1.0; for (s354 = 0; s354 < scale_upto354; s354++) { int width354 = (int)(input_size.width * ss354 + 0.5); int height354 = (int )(input_size.height * ss354 + 0.5); ss354 *= scale354; if (width354 > image_size.width || height354 > image_size.height) break ; float x354, y354; int min_side354 = ({ typeof (width354) _a = (width354); typeof (height354) _b = (height354); (_a < _b ) ? _a : _b; }); int piy354 = -1; for (y354 = 0; y354 < image_size .height - height354 - 0.5; y354 += params.shift * min_side354 ) { int iy354 = (int)(y354 + 0.5); if (iy354 == piy354) continue ; piy354 = iy354; int pix354 = -1; for (x354 = 0; x354 < image_size .width - width354 - 0.5; x354 += params.shift * min_side354) { int ix354 = (int)(x354 + 0.5); if (ix354 == pix354) continue ; pix354 = ix354; ccv_comp_t comp; comp.rect = ccv_rect(ix354 , iy354, width354, height354); comp.classification.id = s354; | |||
355 | double overlap = _ccv_tld_rect_intersect(comp.rect, box); | |||
356 | comp.neighbors = i++; | |||
357 | comp.classification.confidence = overlap; | |||
358 | if (overlap > params.include_overlap) | |||
359 | { | |||
360 | if (overlap > max_overlap) | |||
361 | { | |||
362 | max_overlap = overlap; | |||
363 | best_box = comp; | |||
364 | } | |||
365 | if (agood->rnum < gcap) | |||
366 | { | |||
367 | ccv_array_push(agood, &comp); | |||
368 | _ccv_tld_box_percolate_up(agood, agood->rnum - 1); | |||
369 | } else { | |||
370 | ccv_comp_t* p = (ccv_comp_t*)ccv_array_get(agood, 0)((void*)(((char*)((agood)->data)) + (size_t)(agood)->rsize * (size_t)(0))); | |||
371 | if (overlap > p->classification.confidence) | |||
372 | { | |||
373 | *(ccv_comp_t*)ccv_array_get(agood, 0)((void*)(((char*)((agood)->data)) + (size_t)(agood)->rsize * (size_t)(0))) = comp; | |||
374 | _ccv_tld_box_percolate_down(agood, 0); | |||
375 | } | |||
376 | } | |||
377 | } else if (overlap < params.exclude_overlap) | |||
378 | ccv_array_push(abad, &comp); | |||
379 | end_for_each_box} } } } }; | |||
380 | best_box.neighbors = i; | |||
381 | return best_box; | |||
382 | } | |||
383 | ||||
384 | static void _ccv_tld_ferns_feature_for(ccv_ferns_t* ferns, ccv_dense_matrix_t* a, ccv_comp_t box, uint32_t* fern, dsfmt_t* dsfmt, float deform_angle, float deform_scale, float deform_shift) | |||
385 | { | |||
386 | assert(box.rect.x >= 0 && box.rect.x < a->cols)((void) sizeof ((box.rect.x >= 0 && box.rect.x < a->cols) ? 1 : 0), __extension__ ({ if (box.rect.x >= 0 && box.rect.x < a->cols) ; else __assert_fail ( "box.rect.x >= 0 && box.rect.x < a->cols", "ccv_tld.c" , 386, __extension__ __PRETTY_FUNCTION__); })); | |||
387 | assert(box.rect.y >= 0 && box.rect.y < a->rows)((void) sizeof ((box.rect.y >= 0 && box.rect.y < a->rows) ? 1 : 0), __extension__ ({ if (box.rect.y >= 0 && box.rect.y < a->rows) ; else __assert_fail ( "box.rect.y >= 0 && box.rect.y < a->rows", "ccv_tld.c" , 387, __extension__ __PRETTY_FUNCTION__); })); | |||
388 | assert(box.rect.x + box.rect.width <= a->cols)((void) sizeof ((box.rect.x + box.rect.width <= a->cols ) ? 1 : 0), __extension__ ({ if (box.rect.x + box.rect.width <= a->cols) ; else __assert_fail ("box.rect.x + box.rect.width <= a->cols" , "ccv_tld.c", 388, __extension__ __PRETTY_FUNCTION__); })); | |||
389 | assert(box.rect.y + box.rect.height <= a->rows)((void) sizeof ((box.rect.y + box.rect.height <= a->rows ) ? 1 : 0), __extension__ ({ if (box.rect.y + box.rect.height <= a->rows) ; else __assert_fail ("box.rect.y + box.rect.height <= a->rows" , "ccv_tld.c", 389, __extension__ __PRETTY_FUNCTION__); })); | |||
390 | if (!dsfmt) | |||
391 | { | |||
392 | ccv_dense_matrix_t roi = ccv_dense_matrix(box.rect.height, box.rect.width, CCV_GET_DATA_TYPE(a->type)((a->type) & 0xFF000) | CCV_GET_CHANNEL(a->type)((a->type) & 0xFFF), ccv_get_dense_matrix_cell(a, box.rect.y, box.rect.x, 0)((((a)->type) & CCV_32S) ? (void*)((a)->data.i32 + ( (box.rect.y) * (a)->cols + (box.rect.x)) * (((a)->type) & 0xFFF) + (0)) : ((((a)->type) & CCV_32F) ? (void *)((a)->data.f32+ ((box.rect.y) * (a)->cols + (box.rect .x)) * (((a)->type) & 0xFFF) + (0)) : ((((a)->type) & CCV_64S) ? (void*)((a)->data.i64+ ((box.rect.y) * ( a)->cols + (box.rect.x)) * (((a)->type) & 0xFFF) + ( 0)) : ((((a)->type) & CCV_64F) ? (void*)((a)->data. f64 + ((box.rect.y) * (a)->cols + (box.rect.x)) * (((a)-> type) & 0xFFF) + (0)) : (void*)((a)->data.u8 + (box.rect .y) * (a)->step + (box.rect.x) * (((a)->type) & 0xFFF ) + (0)))))), 0); | |||
393 | roi.step = a->step; | |||
394 | ccv_ferns_feature(ferns, &roi, box.classification.id, fern); | |||
395 | } else { | |||
396 | float rotate_x = (deform_angle * 2 * dsfmt_genrand_close_open(dsfmt) - deform_angle) * CCV_PI(3.141592653589793) / 180; | |||
397 | float rotate_y = (deform_angle * 2 * dsfmt_genrand_close_open(dsfmt) - deform_angle) * CCV_PI(3.141592653589793) / 180; | |||
398 | float rotate_z = (deform_angle * 2 * dsfmt_genrand_close_open(dsfmt) - deform_angle) * CCV_PI(3.141592653589793) / 180; | |||
399 | float scale = 1 + deform_scale - deform_scale * 2 * dsfmt_genrand_close_open(dsfmt); | |||
400 | float m00 = cosf(rotate_z) * scale; | |||
401 | float m01 = cosf(rotate_y) * sinf(rotate_z) * scale; | |||
402 | float m02 = (deform_shift * 2 * dsfmt_genrand_close_open(dsfmt) - deform_shift) * box.rect.width; | |||
403 | float m10 = (sinf(rotate_y) * cosf(rotate_z) - cosf(rotate_x) * sinf(rotate_z)) * scale; | |||
404 | float m11 = (sinf(rotate_y) * sinf(rotate_z) + cosf(rotate_x) * cosf(rotate_z)) * scale; | |||
405 | float m12 = (deform_shift * dsfmt_genrand_close_open(dsfmt) - deform_shift) * box.rect.height; | |||
406 | float m20 = (sinf(rotate_y) * cosf(rotate_z) + sinf(rotate_x) * sinf(rotate_z)) * scale; | |||
407 | float m21 = (sinf(rotate_y) * sinf(rotate_z) - sinf(rotate_x) * cosf(rotate_z)) * scale; | |||
408 | float m22 = cosf(rotate_x) * cosf(rotate_y); | |||
409 | ccv_decimal_point_t p00 = ccv_perspective_transform_apply(ccv_decimal_point(0, 0), ccv_size(box.rect.width, box.rect.height), m00, m01, m02, m10, m11, m12, m20, m21, m22); | |||
410 | ccv_decimal_point_t p01 = ccv_perspective_transform_apply(ccv_decimal_point(box.rect.width, 0), ccv_size(box.rect.width, box.rect.height), m00, m01, m02, m10, m11, m12, m20, m21, m22); | |||
411 | ccv_decimal_point_t p10 = ccv_perspective_transform_apply(ccv_decimal_point(0, box.rect.height), ccv_size(box.rect.width, box.rect.height), m00, m01, m02, m10, m11, m12, m20, m21, m22); | |||
412 | ccv_decimal_point_t p11 = ccv_perspective_transform_apply(ccv_decimal_point(box.rect.width, box.rect.height), ccv_size(box.rect.width, box.rect.height), m00, m01, m02, m10, m11, m12, m20, m21, m22); | |||
413 | int padding_top = (int)(ccv_max(0, -ccv_min(p00.y, p01.y))({ typeof (0) _a = (0); typeof (-({ typeof (p00.y) _a = (p00. y); typeof (p01.y) _b = (p01.y); (_a < _b) ? _a : _b; })) _b = (-({ typeof (p00.y) _a = (p00.y); typeof (p01.y) _b = (p01 .y); (_a < _b) ? _a : _b; })); (_a > _b) ? _a : _b; }) + 0.5) + 5; | |||
414 | padding_top = box.rect.y - ccv_max(box.rect.y - padding_top, 0)({ typeof (box.rect.y - padding_top) _a = (box.rect.y - padding_top ); typeof (0) _b = (0); (_a > _b) ? _a : _b; }); | |||
415 | int padding_right = (int)(ccv_max(0, ccv_max(p01.x, p11.x) - box.rect.width)({ typeof (0) _a = (0); typeof (({ typeof (p01.x) _a = (p01.x ); typeof (p11.x) _b = (p11.x); (_a > _b) ? _a : _b; }) - box .rect.width) _b = (({ typeof (p01.x) _a = (p01.x); typeof (p11 .x) _b = (p11.x); (_a > _b) ? _a : _b; }) - box.rect.width ); (_a > _b) ? _a : _b; }) + 0.5) + 5; | |||
416 | padding_right = ccv_min(box.rect.x + box.rect.width + padding_right, a->cols)({ typeof (box.rect.x + box.rect.width + padding_right) _a = ( box.rect.x + box.rect.width + padding_right); typeof (a->cols ) _b = (a->cols); (_a < _b) ? _a : _b; }) - (box.rect.x + box.rect.width); | |||
417 | int padding_bottom = (int)(ccv_max(0, ccv_max(p10.y, p11.y) - box.rect.height)({ typeof (0) _a = (0); typeof (({ typeof (p10.y) _a = (p10.y ); typeof (p11.y) _b = (p11.y); (_a > _b) ? _a : _b; }) - box .rect.height) _b = (({ typeof (p10.y) _a = (p10.y); typeof (p11 .y) _b = (p11.y); (_a > _b) ? _a : _b; }) - box.rect.height ); (_a > _b) ? _a : _b; }) + 0.5) + 5; | |||
418 | padding_bottom = ccv_min(box.rect.y + box.rect.height + padding_bottom, a->rows)({ typeof (box.rect.y + box.rect.height + padding_bottom) _a = (box.rect.y + box.rect.height + padding_bottom); typeof (a-> rows) _b = (a->rows); (_a < _b) ? _a : _b; }) - (box.rect.y + box.rect.height); | |||
419 | int padding_left = (int)(ccv_max(0, -ccv_min(p00.x, p10.x))({ typeof (0) _a = (0); typeof (-({ typeof (p00.x) _a = (p00. x); typeof (p10.x) _b = (p10.x); (_a < _b) ? _a : _b; })) _b = (-({ typeof (p00.x) _a = (p00.x); typeof (p10.x) _b = (p10 .x); (_a < _b) ? _a : _b; })); (_a > _b) ? _a : _b; }) + 0.5) + 5; | |||
420 | padding_left = box.rect.x - ccv_max(box.rect.x - padding_left, 0)({ typeof (box.rect.x - padding_left) _a = (box.rect.x - padding_left ); typeof (0) _b = (0); (_a > _b) ? _a : _b; }); | |||
421 | ccv_rect_t hull = ccv_rect(box.rect.x - padding_left, box.rect.y - padding_top, | |||
422 | box.rect.width + padding_left + padding_right, | |||
423 | box.rect.height + padding_top + padding_bottom); | |||
424 | assert(hull.x >= 0 && hull.x < a->cols)((void) sizeof ((hull.x >= 0 && hull.x < a-> cols) ? 1 : 0), __extension__ ({ if (hull.x >= 0 && hull.x < a->cols) ; else __assert_fail ("hull.x >= 0 && hull.x < a->cols" , "ccv_tld.c", 424, __extension__ __PRETTY_FUNCTION__); })); | |||
425 | assert(hull.y >= 0 && hull.y < a->rows)((void) sizeof ((hull.y >= 0 && hull.y < a-> rows) ? 1 : 0), __extension__ ({ if (hull.y >= 0 && hull.y < a->rows) ; else __assert_fail ("hull.y >= 0 && hull.y < a->rows" , "ccv_tld.c", 425, __extension__ __PRETTY_FUNCTION__); })); | |||
426 | assert(hull.x + hull.width <= a->cols)((void) sizeof ((hull.x + hull.width <= a->cols) ? 1 : 0 ), __extension__ ({ if (hull.x + hull.width <= a->cols) ; else __assert_fail ("hull.x + hull.width <= a->cols" , "ccv_tld.c", 426, __extension__ __PRETTY_FUNCTION__); })); | |||
427 | assert(hull.y + hull.height <= a->rows)((void) sizeof ((hull.y + hull.height <= a->rows) ? 1 : 0), __extension__ ({ if (hull.y + hull.height <= a->rows ) ; else __assert_fail ("hull.y + hull.height <= a->rows" , "ccv_tld.c", 427, __extension__ __PRETTY_FUNCTION__); })); | |||
428 | ccv_dense_matrix_t roi = ccv_dense_matrix(hull.height, hull.width, CCV_GET_DATA_TYPE(a->type)((a->type) & 0xFF000) | CCV_GET_CHANNEL(a->type)((a->type) & 0xFFF), ccv_get_dense_matrix_cell(a, hull.y, hull.x, 0)((((a)->type) & CCV_32S) ? (void*)((a)->data.i32 + ( (hull.y) * (a)->cols + (hull.x)) * (((a)->type) & 0xFFF ) + (0)) : ((((a)->type) & CCV_32F) ? (void*)((a)-> data.f32+ ((hull.y) * (a)->cols + (hull.x)) * (((a)->type ) & 0xFFF) + (0)) : ((((a)->type) & CCV_64S) ? (void *)((a)->data.i64+ ((hull.y) * (a)->cols + (hull.x)) * ( ((a)->type) & 0xFFF) + (0)) : ((((a)->type) & CCV_64F ) ? (void*)((a)->data.f64 + ((hull.y) * (a)->cols + (hull .x)) * (((a)->type) & 0xFFF) + (0)) : (void*)((a)-> data.u8 + (hull.y) * (a)->step + (hull.x) * (((a)->type ) & 0xFFF) + (0)))))), 0); | |||
429 | roi.step = a->step; | |||
430 | ccv_dense_matrix_t* b = 0; | |||
431 | ccv_perspective_transform(&roi, &b, 0, m00, m01, m02, m10, m11, m12, m20, m21, m22); | |||
432 | roi = ccv_dense_matrix(box.rect.height, box.rect.width, CCV_GET_DATA_TYPE(b->type)((b->type) & 0xFF000) | CCV_GET_CHANNEL(b->type)((b->type) & 0xFFF), ccv_get_dense_matrix_cell(b, padding_top, padding_left, 0)((((b)->type) & CCV_32S) ? (void*)((b)->data.i32 + ( (padding_top) * (b)->cols + (padding_left)) * (((b)->type ) & 0xFFF) + (0)) : ((((b)->type) & CCV_32F) ? (void *)((b)->data.f32+ ((padding_top) * (b)->cols + (padding_left )) * (((b)->type) & 0xFFF) + (0)) : ((((b)->type) & CCV_64S) ? (void*)((b)->data.i64+ ((padding_top) * (b)-> cols + (padding_left)) * (((b)->type) & 0xFFF) + (0)) : ((((b)->type) & CCV_64F) ? (void*)((b)->data.f64 + ((padding_top) * (b)->cols + (padding_left)) * (((b)-> type) & 0xFFF) + (0)) : (void*)((b)->data.u8 + (padding_top ) * (b)->step + (padding_left) * (((b)->type) & 0xFFF ) + (0)))))), 0); | |||
433 | roi.step = b->step; | |||
434 | ccv_ferns_feature(ferns, &roi, box.classification.id, fern); | |||
435 | ccv_matrix_free(b); | |||
436 | } | |||
437 | } | |||
438 | ||||
439 | static void _ccv_tld_fetch_patch(ccv_tld_t* tld, ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type, ccv_rect_t box) | |||
440 | { | |||
441 | if (box.width == tld->patch.width && box.height == tld->patch.height) | |||
442 | ccv_slice(a, (ccv_matrix_t**)b, type, box.y, box.x, box.height, box.width); | |||
443 | else { | |||
444 | assert((box.width >= tld->patch.width && box.height >= tld->patch.height) ||((void) sizeof (((box.width >= tld->patch.width && box.height >= tld->patch.height) || (box.width <= tld ->patch.width && box.height <= tld->patch.height )) ? 1 : 0), __extension__ ({ if ((box.width >= tld->patch .width && box.height >= tld->patch.height) || ( box.width <= tld->patch.width && box.height <= tld->patch.height)) ; else __assert_fail ("(box.width >= tld->patch.width && box.height >= tld->patch.height) || (box.width <= tld->patch.width && box.height <= tld->patch.height)" , "ccv_tld.c", 445, __extension__ __PRETTY_FUNCTION__); })) | |||
445 | (box.width <= tld->patch.width && box.height <= tld->patch.height))((void) sizeof (((box.width >= tld->patch.width && box.height >= tld->patch.height) || (box.width <= tld ->patch.width && box.height <= tld->patch.height )) ? 1 : 0), __extension__ ({ if ((box.width >= tld->patch .width && box.height >= tld->patch.height) || ( box.width <= tld->patch.width && box.height <= tld->patch.height)) ; else __assert_fail ("(box.width >= tld->patch.width && box.height >= tld->patch.height) || (box.width <= tld->patch.width && box.height <= tld->patch.height)" , "ccv_tld.c", 445, __extension__ __PRETTY_FUNCTION__); })); | |||
446 | ccv_dense_matrix_t* c = 0; | |||
447 | ccv_slice(a, (ccv_matrix_t**)&c, type, box.y, box.x, box.height, box.width); | |||
448 | ccv_resample(c, b, type, tld->patch.height, tld->patch.width, CCV_INTER_AREA | CCV_INTER_CUBIC); | |||
449 | ccv_matrix_free(c); | |||
450 | } | |||
451 | } | |||
452 | ||||
453 | static double _ccv_tld_box_variance(ccv_dense_matrix_t* sat, ccv_dense_matrix_t* sqsat, ccv_rect_t box) | |||
454 | { | |||
455 | assert(CCV_GET_DATA_TYPE(sat->type) == CCV_32S)((void) sizeof ((((sat->type) & 0xFF000) == CCV_32S) ? 1 : 0), __extension__ ({ if (((sat->type) & 0xFF000) == CCV_32S) ; else __assert_fail ("CCV_GET_DATA_TYPE(sat->type) == CCV_32S" , "ccv_tld.c", 455, __extension__ __PRETTY_FUNCTION__); })); | |||
456 | assert(CCV_GET_DATA_TYPE(sqsat->type) == CCV_64S)((void) sizeof ((((sqsat->type) & 0xFF000) == CCV_64S) ? 1 : 0), __extension__ ({ if (((sqsat->type) & 0xFF000 ) == CCV_64S) ; else __assert_fail ("CCV_GET_DATA_TYPE(sqsat->type) == CCV_64S" , "ccv_tld.c", 456, __extension__ __PRETTY_FUNCTION__); })); | |||
457 | int tls = (box.x > 0 && box.y > 0) ? sat->data.i32[box.x - 1 + (box.y - 1) * sat->cols] : 0; | |||
458 | int trs = (box.y > 0) ? sat->data.i32[box.x + box.width - 1 + (box.y - 1) * sat->cols] : 0; | |||
459 | int bls = (box.x > 0) ? sat->data.i32[box.x - 1 + (box.y + box.height - 1) * sat->cols] : 0; | |||
460 | int brs = sat->data.i32[box.x + box.width - 1 + (box.y + box.height - 1) * sat->cols]; | |||
461 | double mean = (double)(brs - trs - bls + tls) / (box.width * box.height); | |||
462 | int64_t tlsq = (box.x > 0 && box.y > 0) ? sqsat->data.i64[box.x - 1 + (box.y - 1) * sqsat->cols] : 0; | |||
463 | int64_t trsq = (box.y > 0) ? sqsat->data.i64[box.x + box.width - 1 + (box.y - 1) * sqsat->cols] : 0; | |||
464 | int64_t blsq = (box.x > 0) ? sqsat->data.i64[box.x - 1 + (box.y + box.height - 1) * sqsat->cols] : 0; | |||
465 | int64_t brsq = sqsat->data.i64[box.x + box.width - 1 + (box.y + box.height - 1) * sqsat->cols]; | |||
466 | double variance = (double)(brsq - trsq - blsq + tlsq) / (box.width * box.height); | |||
467 | variance = variance - mean * mean; | |||
468 | assert(variance >= 0)((void) sizeof ((variance >= 0) ? 1 : 0), __extension__ ({ if (variance >= 0) ; else __assert_fail ("variance >= 0" , "ccv_tld.c", 468, __extension__ __PRETTY_FUNCTION__); })); | |||
469 | return variance; | |||
470 | } | |||
471 | ||||
472 | static float _ccv_tld_sv_classify(ccv_tld_t* tld, ccv_dense_matrix_t* a, int pnum, int nnum, int* anyp, int* anyn) | |||
473 | { | |||
474 | assert(a->rows == tld->patch.height && a->cols == tld->patch.width)((void) sizeof ((a->rows == tld->patch.height && a->cols == tld->patch.width) ? 1 : 0), __extension__ ( { if (a->rows == tld->patch.height && a->cols == tld->patch.width) ; else __assert_fail ("a->rows == tld->patch.height && a->cols == tld->patch.width" , "ccv_tld.c", 474, __extension__ __PRETTY_FUNCTION__); })); | |||
475 | int i; | |||
476 | pnum = (pnum <= 0) ? tld->sv[1]->rnum : ccv_min(pnum, tld->sv[1]->rnum)({ typeof (pnum) _a = (pnum); typeof (tld->sv[1]->rnum) _b = (tld->sv[1]->rnum); (_a < _b) ? _a : _b; }); | |||
477 | if (pnum == 0) | |||
478 | return 0; | |||
479 | nnum = (nnum <= 0) ? tld->sv[0]->rnum : ccv_min(nnum, tld->sv[0]->rnum)({ typeof (nnum) _a = (nnum); typeof (tld->sv[0]->rnum) _b = (tld->sv[0]->rnum); (_a < _b) ? _a : _b; }); | |||
480 | if (nnum == 0) | |||
481 | return 1; | |||
482 | float maxp = -1; | |||
483 | for (i = 0; i < pnum; i++) | |||
484 | { | |||
485 | ccv_dense_matrix_t* b = *(ccv_dense_matrix_t**)ccv_array_get(tld->sv[1], i)((void*)(((char*)((tld->sv[1])->data)) + (size_t)(tld-> sv[1])->rsize * (size_t)(i))); | |||
486 | float nnc = _ccv_tld_norm_cross_correlate(a, b); | |||
487 | if (nnc > maxp) | |||
488 | maxp = nnc; | |||
489 | } | |||
490 | maxp = (maxp + 1) * 0.5; // make it in 0~1 range | |||
491 | if (anyp) | |||
492 | *anyp = (maxp > tld->params.nnc_same); | |||
493 | float maxn = -1; | |||
494 | for (i = 0; i < nnum; i++) | |||
495 | { | |||
496 | ccv_dense_matrix_t* b = *(ccv_dense_matrix_t**)ccv_array_get(tld->sv[0], i)((void*)(((char*)((tld->sv[0])->data)) + (size_t)(tld-> sv[0])->rsize * (size_t)(i))); | |||
497 | float nnc = _ccv_tld_norm_cross_correlate(a, b); | |||
498 | if (nnc > maxn) | |||
499 | maxn = nnc; | |||
500 | } | |||
501 | maxn = (maxn + 1) * 0.5; // make it in 0~1 range | |||
502 | if (anyn) | |||
503 | *anyn = (maxn > tld->params.nnc_same); | |||
504 | return (1 - maxn) / (2 - maxn - maxp); | |||
505 | } | |||
506 | ||||
507 | // return 0 means that we will retain the given example (thus, you don't want to free it) | |||
508 | static int _ccv_tld_sv_correct(ccv_tld_t* tld, ccv_dense_matrix_t* a, int y) | |||
509 | { | |||
510 | int anyp, anyn; | |||
511 | if (y == 1 && tld->sv[1]->rnum == 0) | |||
512 | { | |||
513 | ccv_array_push(tld->sv[1], &a); | |||
514 | return 0; | |||
515 | } | |||
516 | float conf = _ccv_tld_sv_classify(tld, a, 0, 0, &anyp, &anyn); | |||
517 | if (y == 1 && conf < tld->params.nnc_thres) | |||
518 | { | |||
519 | ccv_array_push(tld->sv[1], &a); | |||
520 | return 0; | |||
521 | } else if (y == 0 && conf > tld->params.nnc_collect) { | |||
522 | ccv_array_push(tld->sv[0], &a); | |||
523 | return 0; | |||
524 | } | |||
525 | return -1; | |||
526 | } | |||
527 | ||||
528 | static void _ccv_tld_check_params(ccv_tld_param_t params) | |||
529 | { | |||
530 | assert(params.top_n > 0)((void) sizeof ((params.top_n > 0) ? 1 : 0), __extension__ ({ if (params.top_n > 0) ; else __assert_fail ("params.top_n > 0" , "ccv_tld.c", 530, __extension__ __PRETTY_FUNCTION__); })); | |||
531 | assert(params.structs > 0)((void) sizeof ((params.structs > 0) ? 1 : 0), __extension__ ({ if (params.structs > 0) ; else __assert_fail ("params.structs > 0" , "ccv_tld.c", 531, __extension__ __PRETTY_FUNCTION__); })); | |||
532 | assert(params.features > 0 && params.features <= 32)((void) sizeof ((params.features > 0 && params.features <= 32) ? 1 : 0), __extension__ ({ if (params.features > 0 && params.features <= 32) ; else __assert_fail ( "params.features > 0 && params.features <= 32", "ccv_tld.c", 532, __extension__ __PRETTY_FUNCTION__); })); | |||
533 | assert(params.win_size.width > 0 && params.win_size.height > 0)((void) sizeof ((params.win_size.width > 0 && params .win_size.height > 0) ? 1 : 0), __extension__ ({ if (params .win_size.width > 0 && params.win_size.height > 0) ; else __assert_fail ("params.win_size.width > 0 && params.win_size.height > 0" , "ccv_tld.c", 533, __extension__ __PRETTY_FUNCTION__); })); | |||
534 | assert((params.win_size.width & 1) == 1 && (params.win_size.height & 1) == 1)((void) sizeof (((params.win_size.width & 1) == 1 && (params.win_size.height & 1) == 1) ? 1 : 0), __extension__ ({ if ((params.win_size.width & 1) == 1 && (params .win_size.height & 1) == 1) ; else __assert_fail ("(params.win_size.width & 1) == 1 && (params.win_size.height & 1) == 1" , "ccv_tld.c", 534, __extension__ __PRETTY_FUNCTION__); })); | |||
535 | assert(params.level >= 0)((void) sizeof ((params.level >= 0) ? 1 : 0), __extension__ ({ if (params.level >= 0) ; else __assert_fail ("params.level >= 0" , "ccv_tld.c", 535, __extension__ __PRETTY_FUNCTION__); })); | |||
536 | assert(params.min_eigen > 0)((void) sizeof ((params.min_eigen > 0) ? 1 : 0), __extension__ ({ if (params.min_eigen > 0) ; else __assert_fail ("params.min_eigen > 0" , "ccv_tld.c", 536, __extension__ __PRETTY_FUNCTION__); })); | |||
537 | assert(params.min_forward_backward_error > 0)((void) sizeof ((params.min_forward_backward_error > 0) ? 1 : 0), __extension__ ({ if (params.min_forward_backward_error > 0) ; else __assert_fail ("params.min_forward_backward_error > 0" , "ccv_tld.c", 537, __extension__ __PRETTY_FUNCTION__); })); | |||
538 | assert(params.bad_patches > 0)((void) sizeof ((params.bad_patches > 0) ? 1 : 0), __extension__ ({ if (params.bad_patches > 0) ; else __assert_fail ("params.bad_patches > 0" , "ccv_tld.c", 538, __extension__ __PRETTY_FUNCTION__); })); | |||
539 | assert(params.interval >= 0)((void) sizeof ((params.interval >= 0) ? 1 : 0), __extension__ ({ if (params.interval >= 0) ; else __assert_fail ("params.interval >= 0" , "ccv_tld.c", 539, __extension__ __PRETTY_FUNCTION__); })); | |||
540 | assert(params.shift > 0 && params.shift < 1)((void) sizeof ((params.shift > 0 && params.shift < 1) ? 1 : 0), __extension__ ({ if (params.shift > 0 && params.shift < 1) ; else __assert_fail ("params.shift > 0 && params.shift < 1" , "ccv_tld.c", 540, __extension__ __PRETTY_FUNCTION__); })); | |||
541 | assert(params.validate_set > 0 && params.validate_set < 1)((void) sizeof ((params.validate_set > 0 && params .validate_set < 1) ? 1 : 0), __extension__ ({ if (params.validate_set > 0 && params.validate_set < 1) ; else __assert_fail ("params.validate_set > 0 && params.validate_set < 1" , "ccv_tld.c", 541, __extension__ __PRETTY_FUNCTION__); })); | |||
542 | assert(params.nnc_same > 0.5 && params.nnc_same < 1)((void) sizeof ((params.nnc_same > 0.5 && params.nnc_same < 1) ? 1 : 0), __extension__ ({ if (params.nnc_same > 0.5 && params.nnc_same < 1) ; else __assert_fail ("params.nnc_same > 0.5 && params.nnc_same < 1" , "ccv_tld.c", 542, __extension__ __PRETTY_FUNCTION__); })); | |||
543 | assert(params.nnc_thres > 0.5 && params.nnc_thres < 1)((void) sizeof ((params.nnc_thres > 0.5 && params. nnc_thres < 1) ? 1 : 0), __extension__ ({ if (params.nnc_thres > 0.5 && params.nnc_thres < 1) ; else __assert_fail ("params.nnc_thres > 0.5 && params.nnc_thres < 1" , "ccv_tld.c", 543, __extension__ __PRETTY_FUNCTION__); })); | |||
544 | assert(params.nnc_verify > 0.5 && params.nnc_verify < 1)((void) sizeof ((params.nnc_verify > 0.5 && params .nnc_verify < 1) ? 1 : 0), __extension__ ({ if (params.nnc_verify > 0.5 && params.nnc_verify < 1) ; else __assert_fail ("params.nnc_verify > 0.5 && params.nnc_verify < 1" , "ccv_tld.c", 544, __extension__ __PRETTY_FUNCTION__); })); | |||
545 | assert(params.nnc_beyond > 0.5 && params.nnc_beyond < 1)((void) sizeof ((params.nnc_beyond > 0.5 && params .nnc_beyond < 1) ? 1 : 0), __extension__ ({ if (params.nnc_beyond > 0.5 && params.nnc_beyond < 1) ; else __assert_fail ("params.nnc_beyond > 0.5 && params.nnc_beyond < 1" , "ccv_tld.c", 545, __extension__ __PRETTY_FUNCTION__); })); | |||
546 | assert(params.nnc_collect >= 0.5 && params.nnc_collect < 1)((void) sizeof ((params.nnc_collect >= 0.5 && params .nnc_collect < 1) ? 1 : 0), __extension__ ({ if (params.nnc_collect >= 0.5 && params.nnc_collect < 1) ; else __assert_fail ("params.nnc_collect >= 0.5 && params.nnc_collect < 1" , "ccv_tld.c", 546, __extension__ __PRETTY_FUNCTION__); })); | |||
547 | assert(params.new_deform > 0)((void) sizeof ((params.new_deform > 0) ? 1 : 0), __extension__ ({ if (params.new_deform > 0) ; else __assert_fail ("params.new_deform > 0" , "ccv_tld.c", 547, __extension__ __PRETTY_FUNCTION__); })); | |||
548 | assert(params.track_deform > 0)((void) sizeof ((params.track_deform > 0) ? 1 : 0), __extension__ ({ if (params.track_deform > 0) ; else __assert_fail ("params.track_deform > 0" , "ccv_tld.c", 548, __extension__ __PRETTY_FUNCTION__); })); | |||
549 | assert(params.new_deform_angle > 0)((void) sizeof ((params.new_deform_angle > 0) ? 1 : 0), __extension__ ({ if (params.new_deform_angle > 0) ; else __assert_fail ( "params.new_deform_angle > 0", "ccv_tld.c", 549, __extension__ __PRETTY_FUNCTION__); })); | |||
550 | assert(params.track_deform_angle > 0)((void) sizeof ((params.track_deform_angle > 0) ? 1 : 0), __extension__ ({ if (params.track_deform_angle > 0) ; else __assert_fail ("params.track_deform_angle > 0", "ccv_tld.c", 550, __extension__ __PRETTY_FUNCTION__); })); | |||
551 | assert(params.new_deform_scale > 0)((void) sizeof ((params.new_deform_scale > 0) ? 1 : 0), __extension__ ({ if (params.new_deform_scale > 0) ; else __assert_fail ( "params.new_deform_scale > 0", "ccv_tld.c", 551, __extension__ __PRETTY_FUNCTION__); })); | |||
552 | assert(params.track_deform_scale > 0)((void) sizeof ((params.track_deform_scale > 0) ? 1 : 0), __extension__ ({ if (params.track_deform_scale > 0) ; else __assert_fail ("params.track_deform_scale > 0", "ccv_tld.c", 552, __extension__ __PRETTY_FUNCTION__); })); | |||
553 | assert(params.new_deform_shift > 0)((void) sizeof ((params.new_deform_shift > 0) ? 1 : 0), __extension__ ({ if (params.new_deform_shift > 0) ; else __assert_fail ( "params.new_deform_shift > 0", "ccv_tld.c", 553, __extension__ __PRETTY_FUNCTION__); })); | |||
554 | assert(params.track_deform_shift > 0)((void) sizeof ((params.track_deform_shift > 0) ? 1 : 0), __extension__ ({ if (params.track_deform_shift > 0) ; else __assert_fail ("params.track_deform_shift > 0", "ccv_tld.c", 554, __extension__ __PRETTY_FUNCTION__); })); | |||
555 | assert(params.rotation >= 0)((void) sizeof ((params.rotation >= 0) ? 1 : 0), __extension__ ({ if (params.rotation >= 0) ; else __assert_fail ("params.rotation >= 0" , "ccv_tld.c", 555, __extension__ __PRETTY_FUNCTION__); })); | |||
556 | } | |||
557 | ||||
558 | static float _ccv_tld_ferns_compute_threshold(ccv_ferns_t* ferns, float ferns_thres, ccv_dense_matrix_t* ga, ccv_dense_matrix_t* sat, ccv_dense_matrix_t* sqsat, double var_thres, ccv_array_t* bad, int starter) | |||
559 | { | |||
560 | int i; | |||
561 | uint32_t* fern = (uint32_t*)alloca(sizeof(uint32_t) * ferns->structs)__builtin_alloca (sizeof(uint32_t) * ferns->structs); | |||
562 | for (i = starter; i < bad->rnum; i++) | |||
563 | { | |||
564 | ccv_comp_t* box = (ccv_comp_t*)ccv_array_get(bad, i)((void*)(((char*)((bad)->data)) + (size_t)(bad)->rsize * (size_t)(i))); | |||
565 | if (_ccv_tld_box_variance(sat, sqsat, box->rect) > var_thres) | |||
566 | { | |||
567 | _ccv_tld_ferns_feature_for(ferns, ga, *box, fern, 0, 0, 0, 0); | |||
568 | float c = ccv_ferns_predict(ferns, fern); | |||
569 | if (c > ferns_thres) | |||
570 | ferns_thres = c; | |||
571 | } | |||
572 | } | |||
573 | return ferns_thres; | |||
574 | } | |||
575 | ||||
576 | static float _ccv_tld_nnc_compute_threshold(ccv_tld_t* tld, float nnc_thres, ccv_dense_matrix_t* ga, ccv_dense_matrix_t* sat, ccv_dense_matrix_t* sqsat, double var_thres, ccv_array_t* bad, int starter) | |||
577 | { | |||
578 | int i; | |||
579 | dsfmt_t* dsfmt = (dsfmt_t*)tld->dsfmt; | |||
580 | for (i = starter; i < bad->rnum; i++) | |||
581 | { | |||
582 | ccv_comp_t* box = (ccv_comp_t*)ccv_array_get(bad, i)((void*)(((char*)((bad)->data)) + (size_t)(bad)->rsize * (size_t)(i))); | |||
583 | if (_ccv_tld_box_variance(sat, sqsat, box->rect) > var_thres) | |||
584 | { | |||
585 | if (dsfmt_genrand_close_open(dsfmt) <= 0.1) // only pick 1 / 10 sample for this | |||
586 | { | |||
587 | ccv_dense_matrix_t* b = 0; | |||
588 | _ccv_tld_fetch_patch(tld, ga, &b, 0, box->rect); | |||
589 | float c = _ccv_tld_sv_classify(tld, b, 0, 0, 0, 0); | |||
590 | ccv_matrix_free(b); | |||
591 | if (c > nnc_thres) | |||
592 | nnc_thres = c; | |||
593 | } | |||
594 | } | |||
595 | } | |||
596 | return nnc_thres; | |||
597 | } | |||
598 | ||||
599 | ccv_tld_t* ccv_tld_new(ccv_dense_matrix_t* a, ccv_rect_t box, ccv_tld_param_t params) | |||
600 | { | |||
601 | _ccv_tld_check_params(params); | |||
602 | ccv_size_t patch = ccv_size((int)(sqrtf(params.min_win * params.min_win * (float)box.width / box.height) + 0.5), | |||
603 | (int)(sqrtf(params.min_win * params.min_win * (float)box.height / box.width) + 0.5)); | |||
604 | ccv_array_t* good = 0; | |||
605 | ccv_array_t* bad = 0; | |||
606 | ccv_comp_t best_box = _ccv_tld_generate_box_for(ccv_size(a->cols, a->rows), patch, box, 20, &good, &bad, params); | |||
607 | ccv_tld_t* tld = (ccv_tld_t*)ccmallocmalloc(sizeof(ccv_tld_t) + sizeof(uint32_t) * (params.structs * best_box.neighbors - 1)); | |||
608 | tld->patch = patch; | |||
609 | tld->params = params; | |||
610 | tld->nnc_verify_thres = params.nnc_verify; | |||
611 | tld->frame_signature = a->sig; | |||
612 | tld->sfmt = ccmallocmalloc(sizeof(sfmt_t)); | |||
613 | tld->dsfmt = ccmallocmalloc(sizeof(dsfmt_t)); | |||
614 | tld->box.rect = box; | |||
615 | { | |||
616 | double scale = pow(2.0, 1.0 / (params.interval + 1.0)); | |||
617 | int scale_upto = (int)(log((double)ccv_min((double)a->cols / patch.width, (double)a->rows / patch.height)({ typeof ((double)a->cols / patch.width) _a = ((double)a-> cols / patch.width); typeof ((double)a->rows / patch.height ) _b = ((double)a->rows / patch.height); (_a < _b) ? _a : _b; })) / log(scale)); | |||
618 | ccv_size_t* scales = (ccv_size_t*)alloca(sizeof(ccv_size_t) * scale_upto)__builtin_alloca (sizeof(ccv_size_t) * scale_upto); | |||
619 | int is = 0; | |||
620 | for_each_size(width, height, patch.width, patch.height, params.interval, a->cols, a->rows){ double scale620 = pow(2.0, 1.0 / (params.interval + 1.0)); int scale_upto620 = (int)(log((double)({ typeof ((double)a->cols / patch.width) _a = ((double)a->cols / patch.width); typeof ((double)a->rows / patch.height) _b = ((double)a->rows / patch.height); (_a < _b) ? _a : _b; })) / log(scale620) ); int s620; double ss620 = 1.0; for (s620 = 0; s620 < scale_upto620 ; s620++) { int width = (int)(patch.width * ss620 + 0.5); int height = (int)(patch.height * ss620 + 0.5); ss620 *= scale620 ; if (width > a->cols || height > a->rows) break; | |||
621 | scales[is] = ccv_size(width, height); | |||
622 | ++is; | |||
623 | end_for_each_size} }; | |||
624 | tld->ferns = ccv_ferns_new(params.structs, params.features, is, scales); | |||
625 | } | |||
626 | tld->sv[0] = ccv_array_new(sizeof(ccv_dense_matrix_t*), 64, 0); | |||
627 | tld->sv[1] = ccv_array_new(sizeof(ccv_dense_matrix_t*), 64, 0); | |||
628 | sfmt_t* sfmt = (sfmt_t*)tld->sfmt; | |||
629 | sfmt_init_gen_rand(sfmt, (uint32_t)(uintptr_t)a); | |||
630 | sfmt_genrand_shuffle(sfmt, ccv_array_get(bad, 0)((void*)(((char*)((bad)->data)) + (size_t)(bad)->rsize * (size_t)(0))), bad->rnum, bad->rsize); | |||
631 | int badex = (bad->rnum + 1) / 2; | |||
632 | int i, j, k = good->rnum; | |||
633 | // inflate good so that it can be used many times for the deformation | |||
634 | for (i = 0; i < params.new_deform; i++) | |||
635 | for (j = 0; j < k; j++) | |||
636 | { | |||
637 | // needs to get it out first, otherwise the pointer may be invalid | |||
638 | // soon (when we realloc the array in push). | |||
639 | ccv_comp_t box = *(ccv_comp_t*)ccv_array_get(good, j)((void*)(((char*)((good)->data)) + (size_t)(good)->rsize * (size_t)(j))); | |||
640 | ccv_array_push(good, &box); | |||
641 | } | |||
642 | int* idx = (int*)ccmallocmalloc(sizeof(int) * (badex + good->rnum)); | |||
643 | for (i = 0; i < badex + good->rnum; i++) | |||
644 | idx[i] = i; | |||
645 | sfmt_genrand_shuffle(sfmt, idx, badex + good->rnum, sizeof(int)); | |||
646 | // train the fern classifier | |||
647 | ccv_dense_matrix_t* ga = 0; | |||
648 | ccv_blur(a, &ga, 0, 1.5); | |||
649 | ccv_dense_matrix_t* b = 0; | |||
650 | _ccv_tld_fetch_patch(tld, ga, &b, 0, best_box.rect); | |||
651 | tld->var_thres = ccv_variance(b) * 0.5; | |||
652 | ccv_array_push(tld->sv[1], &b); | |||
653 | ccv_dense_matrix_t* sat = 0; | |||
654 | ccv_sat(a, &sat, 0, CCV_NO_PADDING); | |||
655 | ccv_dense_matrix_t* sq = 0; | |||
656 | ccv_multiply(a, a, (ccv_matrix_t**)&sq, 0); | |||
657 | ccv_dense_matrix_t* sqsat = 0; | |||
658 | ccv_sat(sq, &sqsat, 0, CCV_NO_PADDING); | |||
659 | ccv_matrix_free(sq); | |||
660 | dsfmt_t* dsfmt = (dsfmt_t*)tld->dsfmt; | |||
661 | dsfmt_init_gen_rand(dsfmt, (uint32_t)(uintptr_t)tld); | |||
662 | { // save stack fr alloca | |||
663 | uint32_t* fern = (uint32_t*)alloca(sizeof(uint32_t) * tld->ferns->structs)__builtin_alloca (sizeof(uint32_t) * tld->ferns->structs ); | |||
664 | for (i = 0; i < 2; i++) // run twice to take into account when warm up, we missed a few examples | |||
665 | { | |||
666 | for (j = 0; j < badex + good->rnum; j++) | |||
667 | { | |||
668 | k = idx[j]; | |||
669 | if (k < badex) | |||
670 | { | |||
671 | ccv_comp_t* box = (ccv_comp_t*)ccv_array_get(bad, k)((void*)(((char*)((bad)->data)) + (size_t)(bad)->rsize * (size_t)(k))); | |||
672 | assert(box->neighbors >= 0 && box->neighbors < best_box.neighbors)((void) sizeof ((box->neighbors >= 0 && box-> neighbors < best_box.neighbors) ? 1 : 0), __extension__ ({ if (box->neighbors >= 0 && box->neighbors < best_box.neighbors) ; else __assert_fail ("box->neighbors >= 0 && box->neighbors < best_box.neighbors" , "ccv_tld.c", 672, __extension__ __PRETTY_FUNCTION__); })); | |||
673 | if (_ccv_tld_box_variance(sat, sqsat, box->rect) > tld->var_thres * 0.5) | |||
674 | { | |||
675 | _ccv_tld_ferns_feature_for(tld->ferns, ga, *box, fern, 0, 0, 0, 0); | |||
676 | // fix the thresholding for negative | |||
677 | if (ccv_ferns_predict(tld->ferns, fern) >= tld->ferns->threshold) | |||
678 | ccv_ferns_correct(tld->ferns, fern, 0, 2); | |||
679 | } | |||
680 | } else { | |||
681 | ccv_comp_t* box = (ccv_comp_t*)ccv_array_get(good, k - badex)((void*)(((char*)((good)->data)) + (size_t)(good)->rsize * (size_t)(k - badex))); | |||
682 | _ccv_tld_ferns_feature_for(tld->ferns, ga, *box, fern, dsfmt, params.new_deform_angle, params.new_deform_scale, params.new_deform_shift); | |||
683 | // fix the thresholding for positive | |||
684 | if (ccv_ferns_predict(tld->ferns, fern) <= tld->ferns->threshold) | |||
685 | ccv_ferns_correct(tld->ferns, fern, 1, 2); | |||
686 | } | |||
687 | } | |||
688 | } | |||
689 | } // reclaim stack | |||
690 | tld->ferns_thres = _ccv_tld_ferns_compute_threshold(tld->ferns, tld->ferns->threshold, ga, sat, sqsat, tld->var_thres * 0.5, bad, badex); | |||
691 | ccv_array_free(good); | |||
692 | ccfreefree(idx); | |||
693 | // train the nearest-neighbor classifier | |||
694 | for (i = 0, k = 0; i < bad->rnum && k < params.bad_patches; i++) | |||
695 | { | |||
696 | ccv_comp_t* box = (ccv_comp_t*)ccv_array_get(bad, i)((void*)(((char*)((bad)->data)) + (size_t)(bad)->rsize * (size_t)(i))); | |||
697 | if (_ccv_tld_box_variance(sat, sqsat, box->rect) > tld->var_thres * 0.5) | |||
698 | { | |||
699 | ccv_dense_matrix_t* b = 0; | |||
700 | _ccv_tld_fetch_patch(tld, ga, &b, 0, box->rect); | |||
701 | if (_ccv_tld_sv_correct(tld, b, 0) != 0) | |||
702 | ccv_matrix_free(b); | |||
703 | ++k; | |||
704 | } | |||
705 | } | |||
706 | tld->nnc_thres = _ccv_tld_nnc_compute_threshold(tld, tld->params.nnc_thres, ga, sat, sqsat, tld->var_thres * 0.5, bad, badex); | |||
707 | tld->nnc_thres = ccv_min(tld->nnc_thres, params.nnc_beyond)({ typeof (tld->nnc_thres) _a = (tld->nnc_thres); typeof (params.nnc_beyond) _b = (params.nnc_beyond); (_a < _b) ? _a : _b; }); | |||
708 | ccv_matrix_free(sqsat); | |||
709 | ccv_matrix_free(sat); | |||
710 | ccv_matrix_free(ga); | |||
711 | ccv_array_free(bad); | |||
712 | // init tld params | |||
713 | tld->found = 1; // assume last time has found (we just started) | |||
714 | tld->verified = 1; // assume last frame is verified tracking | |||
715 | // top is ccv_tld_feature_t, and its continuous memory region for a feature | |||
716 | tld->top = ccv_array_new(sizeof(ccv_comp_t), params.top_n, 0); | |||
717 | tld->top->rnum = 0; | |||
718 | tld->count = 0; | |||
719 | return tld; | |||
720 | } | |||
721 | ||||
722 | static int _ccv_tld_quick_learn(ccv_tld_t* tld, ccv_dense_matrix_t* ga, ccv_dense_matrix_t* sat, ccv_dense_matrix_t* sqsat, ccv_comp_t dd) | |||
723 | { | |||
724 | ccv_dense_matrix_t* b = 0; | |||
725 | float scale = sqrtf((float)(dd.rect.width * dd.rect.height) / (tld->patch.width * tld->patch.height)); | |||
726 | // regularize the rect to conform patch's aspect ratio | |||
727 | dd.rect = ccv_rect((int)(dd.rect.x + (dd.rect.width - tld->patch.width * scale) + 0.5), | |||
728 | (int)(dd.rect.y + (dd.rect.height - tld->patch.height * scale) + 0.5), | |||
729 | (int)(tld->patch.width * scale + 0.5), | |||
730 | (int)(tld->patch.height * scale + 0.5)); | |||
731 | _ccv_tld_fetch_patch(tld, ga, &b, 0, dd.rect); | |||
732 | double variance = ccv_variance(b); | |||
733 | int anyp, anyn; | |||
734 | float c = _ccv_tld_sv_classify(tld, b, 0, 0, &anyp, &anyn); | |||
735 | ccv_matrix_free(b); | |||
736 | if (c > tld->params.nnc_collect && !anyn && variance > tld->var_thres) | |||
737 | { | |||
738 | ccv_array_t* good = 0; | |||
739 | ccv_array_t* bad = 0; | |||
740 | ccv_comp_t best_box = _ccv_tld_generate_box_for(ccv_size(ga->cols, ga->rows), tld->patch, dd.rect, 10, &good, &bad, tld->params); | |||
741 | int i, j, k = good->rnum; | |||
742 | // inflate good boxes to take into account deformations | |||
743 | for (i = 0; i < tld->params.track_deform; i++) | |||
744 | for (j = 0; j < k; j++) | |||
745 | { | |||
746 | // needs to get it out first, otherwise the pointer may be invalid | |||
747 | // soon (when we realloc the array in push). | |||
748 | ccv_comp_t box = *(ccv_comp_t*)ccv_array_get(good, j)((void*)(((char*)((good)->data)) + (size_t)(good)->rsize * (size_t)(j))); | |||
749 | ccv_array_push(good, &box); | |||
750 | } | |||
751 | sfmt_t* sfmt = (sfmt_t*)tld->sfmt; | |||
752 | sfmt_genrand_shuffle(sfmt, ccv_array_get(bad, 0)((void*)(((char*)((bad)->data)) + (size_t)(bad)->rsize * (size_t)(0))), bad->rnum, bad->rsize); | |||
753 | int badex = (bad->rnum * 4 + 3) / 6; // only use 2 / 3 bad example for quick learn | |||
754 | int* idx = (int*)ccmallocmalloc(sizeof(int) * (badex + good->rnum)); | |||
755 | for (i = 0; i < badex + good->rnum; i++) | |||
756 | idx[i] = i; | |||
757 | sfmt_genrand_shuffle(sfmt, idx, badex + good->rnum, sizeof(int)); | |||
758 | dsfmt_t* dsfmt = (dsfmt_t*)tld->dsfmt; | |||
759 | uint32_t* fern = (uint32_t*)ccmallocmalloc(sizeof(uint32_t) * tld->ferns->structs * (badex + 1)); | |||
760 | int r0 = tld->count % (tld->params.rotation + 1), r1 = tld->params.rotation + 1; | |||
761 | // train the fern classifier | |||
762 | for (i = 0; i < 2; i++) // run it twice to take into account the cases we missed when warm up | |||
763 | { | |||
764 | uint32_t* pfern = fern + tld->ferns->structs; | |||
765 | for (j = 0; j < badex + good->rnum; j++) | |||
766 | { | |||
767 | k = idx[j]; | |||
768 | if (k < badex) | |||
769 | { | |||
770 | ccv_comp_t *box = (ccv_comp_t*)ccv_array_get(bad, k)((void*)(((char*)((bad)->data)) + (size_t)(bad)->rsize * (size_t)(k))); | |||
771 | if (i == 0) | |||
772 | { | |||
773 | assert(box->neighbors >= 0 && box->neighbors < best_box.neighbors)((void) sizeof ((box->neighbors >= 0 && box-> neighbors < best_box.neighbors) ? 1 : 0), __extension__ ({ if (box->neighbors >= 0 && box->neighbors < best_box.neighbors) ; else __assert_fail ("box->neighbors >= 0 && box->neighbors < best_box.neighbors" , "ccv_tld.c", 773, __extension__ __PRETTY_FUNCTION__); })); | |||
774 | if (box->neighbors % r1 == r0 && | |||
775 | _ccv_tld_box_variance(sat, sqsat, box->rect) > tld->var_thres) | |||
776 | { | |||
777 | // put them in order for faster access the next round | |||
778 | memcpy(pfern, tld->fern_buffer + box->neighbors * tld->ferns->structs, sizeof(uint32_t) * tld->ferns->structs); | |||
779 | // fix the thresholding for negative | |||
780 | if (ccv_ferns_predict(tld->ferns, pfern) >= tld->ferns->threshold) | |||
781 | ccv_ferns_correct(tld->ferns, pfern, 0, 2); // just feel like to use 2 | |||
782 | pfern += tld->ferns->structs; | |||
783 | } else | |||
784 | box->neighbors = -1; | |||
785 | } else { | |||
786 | if (box->neighbors < 0) | |||
787 | continue; | |||
788 | if (ccv_ferns_predict(tld->ferns, pfern) >= tld->ferns->threshold) | |||
789 | ccv_ferns_correct(tld->ferns, pfern, 0, 2); // just feel like to use 2 | |||
790 | pfern += tld->ferns->structs; | |||
791 | } | |||
792 | } else { | |||
793 | ccv_comp_t *box = (ccv_comp_t*)ccv_array_get(good, k - badex)((void*)(((char*)((good)->data)) + (size_t)(good)->rsize * (size_t)(k - badex))); | |||
794 | _ccv_tld_ferns_feature_for(tld->ferns, ga, *box, fern, dsfmt, tld->params.track_deform_angle, tld->params.track_deform_scale, tld->params.track_deform_shift); | |||
795 | // fix the thresholding for positive | |||
796 | if (ccv_ferns_predict(tld->ferns, fern) <= tld->ferns_thres) | |||
797 | ccv_ferns_correct(tld->ferns, fern, 1, 1); | |||
798 | } | |||
799 | } | |||
800 | } | |||
801 | ccfreefree(fern); | |||
802 | ccv_array_free(bad); | |||
803 | ccv_array_free(good); | |||
804 | ccfreefree(idx); | |||
805 | // train the nearest-neighbor classifier | |||
806 | ccv_dense_matrix_t* b = 0; | |||
807 | _ccv_tld_fetch_patch(tld, ga, &b, 0, best_box.rect); | |||
808 | if (_ccv_tld_sv_correct(tld, b, 1) != 0) | |||
809 | ccv_matrix_free(b); | |||
810 | for (i = 0; i < tld->top->rnum; i++) | |||
811 | { | |||
812 | ccv_comp_t* box = (ccv_comp_t*)ccv_array_get(tld->top, i)((void*)(((char*)((tld->top)->data)) + (size_t)(tld-> top)->rsize * (size_t)(i))); | |||
813 | if (_ccv_tld_rect_intersect(box->rect, best_box.rect) < tld->params.exclude_overlap) | |||
814 | { | |||
815 | ccv_dense_matrix_t* b = 0; | |||
816 | _ccv_tld_fetch_patch(tld, ga, &b, 0, box->rect); | |||
817 | if (_ccv_tld_sv_correct(tld, b, 0) != 0) | |||
818 | ccv_matrix_free(b); | |||
819 | } | |||
820 | } | |||
821 | // shuffle them | |||
822 | sfmt_genrand_shuffle(sfmt, ccv_array_get(tld->sv[0], 0)((void*)(((char*)((tld->sv[0])->data)) + (size_t)(tld-> sv[0])->rsize * (size_t)(0))), tld->sv[0]->rnum, sizeof(ccv_dense_matrix_t*)); | |||
823 | sfmt_genrand_shuffle(sfmt, ccv_array_get(tld->sv[1], 0)((void*)(((char*)((tld->sv[1])->data)) + (size_t)(tld-> sv[1])->rsize * (size_t)(0))), tld->sv[1]->rnum, sizeof(ccv_dense_matrix_t*)); | |||
824 | return 0; | |||
825 | } | |||
826 | return -1; | |||
827 | } | |||
828 | ||||
829 | static ccv_array_t* _ccv_tld_long_term_detect(ccv_tld_t* tld, ccv_dense_matrix_t* ga, ccv_dense_matrix_t* sat, ccv_dense_matrix_t* sqsat, ccv_tld_info_t* info) | |||
830 | { | |||
831 | int i = 0, r0 = tld->count % (tld->params.rotation + 1), r1 = tld->params.rotation + 1; | |||
832 | tld->top->rnum = 0; | |||
833 | uint32_t* fern = tld->fern_buffer; | |||
834 | for_each_box(box, tld->patch.width, tld->patch.height, tld->params.interval, tld->params.shift, ga->cols, ga->rows){ { double scale834 = pow(2.0, 1.0 / (tld->params.interval + 1.0)); int scale_upto834 = (int)(log((double)({ typeof ((double )ga->cols / tld->patch.width) _a = ((double)ga->cols / tld->patch.width); typeof ((double)ga->rows / tld-> patch.height) _b = ((double)ga->rows / tld->patch.height ); (_a < _b) ? _a : _b; })) / log(scale834)); int s834; double ss834 = 1.0; for (s834 = 0; s834 < scale_upto834; s834++) { int width834 = (int)(tld->patch.width * ss834 + 0.5); int height834 = (int)(tld->patch.height * ss834 + 0.5); ss834 *= scale834; if (width834 > ga->cols || height834 > ga->rows) break; float x834, y834; int min_side834 = ({ typeof (width834) _a = (width834); typeof (height834) _b = (height834 ); (_a < _b) ? _a : _b; }); int piy834 = -1; for (y834 = 0 ; y834 < ga->rows - height834 - 0.5; y834 += tld->params .shift * min_side834) { int iy834 = (int)(y834 + 0.5); if (iy834 == piy834) continue; piy834 = iy834; int pix834 = -1; for (x834 = 0; x834 < ga->cols - width834 - 0.5; x834 += tld-> params.shift * min_side834) { int ix834 = (int)(x834 + 0.5); if (ix834 == pix834) continue; pix834 = ix834; ccv_comp_t box; box .rect = ccv_rect(ix834, iy834, width834, height834); box.classification .id = s834; | |||
835 | if (i % r1 == r0 && | |||
836 | _ccv_tld_box_variance(sat, sqsat, box.rect) > tld->var_thres) | |||
837 | { | |||
838 | _ccv_tld_ferns_feature_for(tld->ferns, ga, box, fern, 0, 0, 0, 0); | |||
839 | box.classification.confidence = ccv_ferns_predict(tld->ferns, fern); | |||
840 | if (box.classification.confidence > tld->ferns_thres) | |||
841 | { | |||
842 | if (tld->top->rnum < tld->params.top_n) | |||
843 | { | |||
844 | ccv_array_push(tld->top, &box); | |||
845 | _ccv_tld_box_percolate_up(tld->top, tld->top->rnum - 1); | |||
846 | } else { | |||
847 | ccv_comp_t* top_box = (ccv_comp_t*)ccv_array_get(tld->top, 0)((void*)(((char*)((tld->top)->data)) + (size_t)(tld-> top)->rsize * (size_t)(0))); | |||
848 | if (top_box->classification.confidence < box.classification.confidence) | |||
849 | { | |||
850 | *(ccv_comp_t*)ccv_array_get(tld->top, 0)((void*)(((char*)((tld->top)->data)) + (size_t)(tld-> top)->rsize * (size_t)(0))) = box; | |||
851 | _ccv_tld_box_percolate_down(tld->top, 0); | |||
852 | } | |||
853 | } | |||
854 | } | |||
855 | } | |||
856 | fern += tld->ferns->structs; | |||
857 | ++i; | |||
858 | end_for_each_box} } } } }; | |||
859 | ccv_array_t* seq = ccv_array_new(sizeof(ccv_comp_t), tld->top->rnum, 0); | |||
860 | for (i = 0; i < tld->top->rnum; i++) | |||
861 | { | |||
862 | ccv_comp_t* box = (ccv_comp_t*)ccv_array_get(tld->top, i)((void*)(((char*)((tld->top)->data)) + (size_t)(tld-> top)->rsize * (size_t)(i))); | |||
863 | int anyp = 0, anyn = 0; | |||
864 | ccv_dense_matrix_t* b = 0; | |||
865 | _ccv_tld_fetch_patch(tld, ga, &b, 0, box->rect); | |||
866 | float c = _ccv_tld_sv_classify(tld, b, 0, 0, &anyp, &anyn); | |||
867 | if (c > tld->nnc_thres) | |||
868 | { | |||
869 | // save only the conservative confidence (50% samples) | |||
870 | box->classification.confidence = _ccv_tld_sv_classify(tld, b, ccv_max((int)(tld->sv[1]->rnum * tld->params.validate_set + 0.5), 1)({ typeof ((int)(tld->sv[1]->rnum * tld->params.validate_set + 0.5)) _a = ((int)(tld->sv[1]->rnum * tld->params. validate_set + 0.5)); typeof (1) _b = (1); (_a > _b) ? _a : _b; }), 0, &anyp, &anyn); | |||
871 | ccv_array_push(seq, box); | |||
872 | } | |||
873 | ccv_matrix_free(b); | |||
874 | } | |||
875 | return seq; | |||
876 | } | |||
877 | ||||
878 | static int _ccv_is_equal(const void* _r1, const void* _r2, void* data) | |||
879 | { | |||
880 | const ccv_comp_t* r1 = (const ccv_comp_t*)_r1; | |||
881 | const ccv_comp_t* r2 = (const ccv_comp_t*)_r2; | |||
882 | return _ccv_tld_rect_intersect(r1->rect, r2->rect) > 0.5; | |||
883 | } | |||
884 | ||||
885 | // since there is no refcount syntax for ccv yet, we won't implicitly retain any matrix in ccv_tld_t | |||
886 | // instead, you should pass the previous frame and the current frame into the track function | |||
887 | ccv_comp_t ccv_tld_track_object(ccv_tld_t* tld, ccv_dense_matrix_t* a, ccv_dense_matrix_t* b, ccv_tld_info_t* info) | |||
888 | { | |||
889 | ccv_comp_t result; | |||
890 | int tracked = 0; | |||
891 | int verified = 0; | |||
892 | assert(tld->frame_signature == a->sig)((void) sizeof ((tld->frame_signature == a->sig) ? 1 : 0 ), __extension__ ({ if (tld->frame_signature == a->sig) ; else __assert_fail ("tld->frame_signature == a->sig" , "ccv_tld.c", 892, __extension__ __PRETTY_FUNCTION__); })); | |||
| ||||
893 | ccv_dense_matrix_t* gb = 0; | |||
894 | ccv_blur(b, &gb, 0, 1.5); | |||
895 | if (info) | |||
896 | info->perform_track = tld->found; | |||
897 | if (tld->found) | |||
898 | { | |||
899 | result.rect = _ccv_tld_short_term_track(a, b, tld->box.rect, tld->params); | |||
900 | if (!ccv_rect_is_zero(result.rect)) | |||
901 | { | |||
902 | float scale = sqrtf((float)(result.rect.width * result.rect.height) / (tld->patch.width * tld->patch.height)); | |||
903 | // regularize the rect to conform patch's aspect ratio | |||
904 | result.rect = ccv_rect((int)(result.rect.x + (result.rect.width - tld->patch.width * scale) + 0.5), | |||
905 | (int)(result.rect.y + (result.rect.height - tld->patch.height * scale) + 0.5), | |||
906 | (int)(tld->patch.width * scale + 0.5), | |||
907 | (int)(tld->patch.height * scale + 0.5)); | |||
908 | tracked = 1; | |||
909 | verified = tld->verified; // inherit it is verified from last frame | |||
910 | int anyp = 0, anyn = 0; | |||
911 | ccv_dense_matrix_t* c = 0; | |||
912 | _ccv_tld_fetch_patch(tld, gb, &c, 0, result.rect); | |||
913 | result.classification.confidence = _ccv_tld_sv_classify(tld, c, 0, 0, &anyp, &anyn); | |||
914 | ccv_matrix_free(c); | |||
915 | if (result.classification.confidence > tld->nnc_verify_thres) | |||
916 | verified = 1; | |||
917 | } | |||
918 | } | |||
919 | if (info
| |||
920 | info->track_success = tracked; | |||
921 | ccv_dense_matrix_t* sat = 0; | |||
922 | ccv_sat(b, &sat, 0, CCV_NO_PADDING); | |||
923 | ccv_dense_matrix_t* sq = 0; | |||
924 | ccv_multiply(b, b, (ccv_matrix_t**)&sq, 0); | |||
925 | ccv_dense_matrix_t* sqsat = 0; | |||
926 | ccv_sat(sq, &sqsat, 0, CCV_NO_PADDING); | |||
927 | ccv_matrix_free(sq); | |||
928 | ccv_array_t* dd = _ccv_tld_long_term_detect(tld, gb, sat, sqsat, info); | |||
929 | if (info
| |||
930 | { | |||
931 | info->ferns_detects = tld->top->rnum; | |||
932 | info->nnc_detects = dd->rnum; | |||
933 | } | |||
934 | int i; | |||
935 | // cluster detected result | |||
936 | if (dd->rnum > 1) | |||
937 | { | |||
938 | ccv_array_t* idx_dd = 0; | |||
939 | // group retrieved rectangles in order to filter out noise | |||
940 | int ncomp = ccv_array_group(dd, &idx_dd, _ccv_is_equal, 0); | |||
941 | ccv_comp_t* comps = (ccv_comp_t*)ccmallocmalloc(ncomp * sizeof(ccv_comp_t)); | |||
942 | memset(comps, 0, ncomp * sizeof(ccv_comp_t)); | |||
943 | for (i = 0; i < dd->rnum; i++) | |||
944 | { | |||
945 | ccv_comp_t r1 = *(ccv_comp_t*)ccv_array_get(dd, i)((void*)(((char*)((dd)->data)) + (size_t)(dd)->rsize * ( size_t)(i))); | |||
946 | int idx = *(int*)ccv_array_get(idx_dd, i)((void*)(((char*)((idx_dd)->data)) + (size_t)(idx_dd)-> rsize * (size_t)(i))); | |||
947 | ++comps[idx].neighbors; | |||
948 | comps[idx].rect.x += r1.rect.x; | |||
949 | comps[idx].rect.y += r1.rect.y; | |||
950 | comps[idx].rect.width += r1.rect.width; | |||
951 | comps[idx].rect.height += r1.rect.height; | |||
952 | comps[idx].classification.confidence += r1.classification.confidence; | |||
953 | } | |||
954 | ccv_array_clear(dd); | |||
955 | for(i = 0; i < ncomp; i++) | |||
956 | { | |||
957 | int n = comps[i].neighbors; | |||
958 | ccv_comp_t comp; | |||
959 | comp.rect.x = (comps[i].rect.x * 2 + n) / (2 * n); | |||
| ||||
960 | comp.rect.y = (comps[i].rect.y * 2 + n) / (2 * n); | |||
961 | comp.rect.width = (comps[i].rect.width * 2 + n) / (2 * n); | |||
962 | comp.rect.height = (comps[i].rect.height * 2 + n) / (2 * n); | |||
963 | comp.neighbors = comps[i].neighbors; | |||
964 | comp.classification.confidence = comps[i].classification.confidence / n; | |||
965 | ccv_array_push(dd, &comp); | |||
966 | } | |||
967 | ccv_array_free(idx_dd); | |||
968 | ccfreefree(comps); | |||
969 | } | |||
970 | if (info) | |||
971 | { | |||
972 | info->clustered_detects = dd->rnum; | |||
973 | info->confident_matches = info->close_matches = 0; | |||
974 | } | |||
975 | if (tracked) | |||
976 | { | |||
977 | if (dd->rnum > 0) | |||
978 | { | |||
979 | ccv_comp_t* ddcomp = 0; | |||
980 | int confident_matches = 0; | |||
981 | for (i = 0; i < dd->rnum; i++) | |||
982 | { | |||
983 | ccv_comp_t* comp = (ccv_comp_t*)ccv_array_get(dd, i)((void*)(((char*)((dd)->data)) + (size_t)(dd)->rsize * ( size_t)(i))); | |||
984 | if (_ccv_tld_rect_intersect(result.rect, comp->rect) < 0.5 && comp->classification.confidence > result.classification.confidence) | |||
985 | { | |||
986 | ++confident_matches; | |||
987 | ddcomp = comp; | |||
988 | } | |||
989 | } | |||
990 | if (info) | |||
991 | info->confident_matches = confident_matches; | |||
992 | if (confident_matches == 1) | |||
993 | { | |||
994 | // only one match, reinitialize tracking | |||
995 | result = *ddcomp; | |||
996 | // but the result is not a valid tracking | |||
997 | verified = 0; | |||
998 | } else { | |||
999 | // too much confident matches, we will focus on close matches instead | |||
1000 | int close_matches = 0; | |||
1001 | ccv_rect_t ddc = ccv_rect(0, 0, 0, 0); | |||
1002 | for (i = 0; i < dd->rnum; i++) | |||
1003 | { | |||
1004 | ccv_comp_t* comp = (ccv_comp_t*)ccv_array_get(dd, i)((void*)(((char*)((dd)->data)) + (size_t)(dd)->rsize * ( size_t)(i))); | |||
1005 | if (_ccv_tld_rect_intersect(result.rect, comp->rect) > 0.7) | |||
1006 | { | |||
1007 | ddc.y += comp->rect.y; | |||
1008 | ddc.x += comp->rect.x; | |||
1009 | ddc.height += comp->rect.height; | |||
1010 | ddc.width += comp->rect.width; | |||
1011 | ++close_matches; | |||
1012 | } | |||
1013 | } | |||
1014 | if (info) | |||
1015 | info->close_matches = close_matches; | |||
1016 | if (close_matches > 0) | |||
1017 | { | |||
1018 | // reweight the tracking result | |||
1019 | result.rect.x = (20 * result.rect.x + ddc.x * 2 + close_matches + 10) / (20 + 2 * close_matches); | |||
1020 | result.rect.y = (20 * result.rect.y + ddc.y * 2 + close_matches + 10) / (20 + 2 * close_matches); | |||
1021 | result.rect.width = (20 * result.rect.width + ddc.width * 2 + close_matches + 10) / (20 + 2 * close_matches); | |||
1022 | result.rect.height = (20 * result.rect.height + ddc.height * 2 + close_matches + 10) / (20 + 2 * close_matches); | |||
1023 | } | |||
1024 | } | |||
1025 | } | |||
1026 | } else if (dd->rnum == 1) { | |||
1027 | // only reinitialize tracker when detection result is exactly one | |||
1028 | result = *(ccv_comp_t*)ccv_array_get(dd, 0)((void*)(((char*)((dd)->data)) + (size_t)(dd)->rsize * ( size_t)(0))); | |||
1029 | tld->found = 1; | |||
1030 | } else { | |||
1031 | // failed to found anything | |||
1032 | tld->found = 0; | |||
1033 | } | |||
1034 | ccv_array_free(dd); | |||
1035 | if (info) | |||
1036 | info->perform_learn = verified; | |||
1037 | if (verified) | |||
1038 | verified = (_ccv_tld_quick_learn(tld, gb, sat, sqsat, result) == 0); | |||
1039 | ccv_matrix_free(sqsat); | |||
1040 | ccv_matrix_free(sat); | |||
1041 | ccv_matrix_free(gb); | |||
1042 | tld->verified = verified; | |||
1043 | tld->box = result; | |||
1044 | tld->frame_signature = b->sig; | |||
1045 | ++tld->count; | |||
1046 | return result; | |||
1047 | } | |||
1048 | ||||
1049 | void ccv_tld_free(ccv_tld_t* tld) | |||
1050 | { | |||
1051 | int i; | |||
1052 | ccfreefree(tld->dsfmt); | |||
1053 | ccfreefree(tld->sfmt); | |||
1054 | for (i = 0; i < tld->sv[0]->rnum; i++) | |||
1055 | ccv_matrix_free(*(ccv_dense_matrix_t**)ccv_array_get(tld->sv[0], i)((void*)(((char*)((tld->sv[0])->data)) + (size_t)(tld-> sv[0])->rsize * (size_t)(i)))); | |||
1056 | ccv_array_free(tld->sv[0]); | |||
1057 | for (i = 0; i < tld->sv[1]->rnum; i++) | |||
1058 | ccv_matrix_free(*(ccv_dense_matrix_t**)ccv_array_get(tld->sv[1], i)((void*)(((char*)((tld->sv[1])->data)) + (size_t)(tld-> sv[1])->rsize * (size_t)(i)))); | |||
1059 | ccv_array_free(tld->sv[1]); | |||
1060 | ccv_array_free(tld->top); | |||
1061 | ccv_ferns_free(tld->ferns); | |||
1062 | ccfreefree(tld); | |||
1063 | } |