| 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 | } |