static int _ccv_read_bbf_stage_classifier(const char* file, ccv_bbf_stage_classifier_t* classifier) { FILE* r = fopen(file, "r"); if (r == 0) return -1; APPROX int stat = 0; stat |= fscanf(r, "%d", &classifier->count); union { float fl; int i; } fli; stat |= fscanf(r, "%d", &fli.i); classifier->threshold = fli.fl; classifier->feature = (ccv_bbf_feature_t*)ccmalloc(ENDORSE(classifier->count) * sizeof(ccv_bbf_feature_t)); classifier->alpha = (float*)DEDORSE(ccmalloc(ENDORSE(classifier->count) * 2 * sizeof(float))); int i, j; for (i = 0; i < ENDORSE(classifier->count); i++) { stat |= fscanf(r, "%d", &classifier->feature[i].size); for (j = 0; j < ENDORSE(classifier->feature[i].size); j++) { stat |= fscanf(r, "%d %d %d", &classifier->feature[i].px[j], &classifier->feature[i].py[j], &classifier->feature[i].pz[j]); stat |= fscanf(r, "%d %d %d", &classifier->feature[i].nx[j], &classifier->feature[i].ny[j], &classifier->feature[i].nz[j]); } union { float fl; int i; } flia, flib; stat |= fscanf(r, "%d %d", &flia.i, &flib.i); classifier->alpha[i * 2] = flia.fl; classifier->alpha[i * 2 + 1] = flib.fl; } fclose(r); return 0; }
ccv_dense_matrix_t* ccv_dense_matrix_new(int rows, int cols, int type, void* data, uint64_t sig) { ccv_dense_matrix_t* mat; if (ccv_cache_opt && sig != 0 && !data && !(type & CCV_NO_DATA_ALLOC)) { uint8_t type; mat = (ccv_dense_matrix_t*)ccv_cache_out(&ccv_cache, sig, &type); if (mat) { assert(type == 0); mat->type |= CCV_GARBAGE; // set the flag so the upper level function knows this is from recycle-bin mat->refcount = 1; return mat; } } if (type & CCV_NO_DATA_ALLOC) { mat = (ccv_dense_matrix_t*)ccmalloc(sizeof(ccv_dense_matrix_t)); mat->type = (CCV_GET_CHANNEL(type) | CCV_GET_DATA_TYPE(type) | CCV_MATRIX_DENSE | CCV_NO_DATA_ALLOC) & ~CCV_GARBAGE; mat->data.u8 = data; } else { mat = (ccv_dense_matrix_t*)(data ? data : ccmalloc(ccv_compute_dense_matrix_size(rows, cols, type))); mat->type = (CCV_GET_CHANNEL(type) | CCV_GET_DATA_TYPE(type) | CCV_MATRIX_DENSE) & ~CCV_GARBAGE; mat->type |= data ? CCV_UNMANAGED : CCV_REUSABLE; // it still could be reusable because the signature could be derived one. mat->data.u8 = (unsigned char*)(mat + 1); } mat->sig = sig; mat->rows = rows; mat->cols = cols; mat->step = (cols * CCV_GET_DATA_TYPE_SIZE(type) * CCV_GET_CHANNEL(type) + 3) & -4; mat->refcount = 1; return mat; }
static void _ccv_dense_vector_expand(ccv_sparse_matrix_t* mat, ccv_dense_vector_t* vector) { if (vector->prime == -1) return; vector->prime++; int new_length = CCV_GET_SPARSE_PRIME(vector->prime); int cell_width = CCV_GET_DATA_TYPE_SIZE(mat->type) * CCV_GET_CHANNEL(mat->type); int new_step = (new_length * cell_width + 3) & -4; ccv_matrix_cell_t new_data; new_data.u8 = (unsigned char*)ccmalloc(new_step + sizeof(int) * new_length); int* new_indice = (int*)(new_data.u8 + new_step); int i; for (i = 0; i < new_length; i++) new_indice[i] = -1; for (i = 0; i < vector->length; i++) if (vector->indice[i] != -1) { int index = vector->indice[i]; int h = (index * 33) % new_length, j = 0; while (new_indice[(h + j * j) % new_length] != index && new_indice[(h + j * j) % new_length] != -1) j++; j = (h + j * j) % new_length; new_indice[j] = index; memcpy(new_data.u8 + j * cell_width, vector->data.u8 + i * cell_width, cell_width); } vector->length = new_length; ccfree(vector->data.u8); vector->data = new_data; vector->indice = new_indice; }
ccv_sparse_matrix_t* ccv_sparse_matrix_new(int rows, int cols, int type, int major, uint64_t sig) { ccv_sparse_matrix_t* mat; mat = (ccv_sparse_matrix_t*)ccmalloc(sizeof(ccv_sparse_matrix_t)); mat->rows = rows; mat->cols = cols; mat->type = type | CCV_MATRIX_SPARSE | ((type & CCV_DENSE_VECTOR) ? CCV_DENSE_VECTOR : CCV_SPARSE_VECTOR); mat->major = major; mat->prime_index = 1; // See ccv_util.c to know why this is 1 and why size is 2. mat->size = 2; mat->rnum = 0; mat->refcount = 1; mat->index = (ccv_sparse_matrix_index_t*)cccalloc(sizeof(ccv_sparse_matrix_index_t), mat->size); mat->vector = (ccv_sparse_matrix_vector_t*)ccmalloc(sizeof(ccv_sparse_matrix_vector_t) * mat->size); return mat; }
static void _ccv_sparse_matrix_expand(ccv_sparse_matrix_t* mat) { int length = CCV_GET_SPARSE_PRIME(mat->prime); mat->prime++; int new_length = CCV_GET_SPARSE_PRIME(mat->prime); ccv_dense_vector_t* new_vector = (ccv_dense_vector_t*)ccmalloc(new_length * sizeof(ccv_dense_vector_t)); int i; for (i = 0; i < new_length; i++) { new_vector[i].index = -1; new_vector[i].length = 0; new_vector[i].next = 0; } for (i = 0; i < length; i++) if (mat->vector[i].index != -1) { int h = (mat->vector[i].index * 33) % new_length; if (new_vector[h].length == 0) { memcpy(new_vector + h, mat->vector + i, sizeof(ccv_dense_vector_t)); new_vector[h].next = 0; } else { ccv_dense_vector_t* t = (ccv_dense_vector_t*)ccmalloc(sizeof(ccv_dense_vector_t)); memcpy(t, mat->vector + i, sizeof(ccv_dense_vector_t)); t->next = new_vector[h].next; new_vector[h].next = t; } ccv_dense_vector_t* iter = mat->vector[i].next; while (iter != 0) { ccv_dense_vector_t* iter_next = iter->next; h = (iter->index * 33) % new_length; if (new_vector[h].length == 0) { memcpy(new_vector + h, iter, sizeof(ccv_dense_vector_t)); new_vector[h].next = 0; ccfree(iter); } else { iter->next = new_vector[h].next; new_vector[h].next = iter; } iter = iter_next; } } ccfree(mat->vector); mat->vector = new_vector; }
ccv_dense_matrix_t* ccv_dense_matrix_new(int rows, int cols, int type, void* data, uint64_t sig) { ccv_dense_matrix_t* mat; if (ccv_cache_opt && sig != 0 && !data && !(type & CCV_NO_DATA_ALLOC)) { uint8_t type; mat = (ccv_dense_matrix_t*)ccv_cache_out(&ccv_cache, sig, &type); if (mat) { assert(type == 0); mat->type |= CCV_GARBAGE; // set the flag so the upper level function knows this is from recycle-bin mat->refcount = 1; return mat; } } if (type & CCV_NO_DATA_ALLOC) { mat = (ccv_dense_matrix_t*)ccmalloc(sizeof(ccv_dense_matrix_t)); mat->type = (CCV_GET_CHANNEL(type) | CCV_GET_DATA_TYPE(type) | CCV_MATRIX_DENSE | CCV_NO_DATA_ALLOC) & ~CCV_GARBAGE; mat->data.u8 = data; } else { const size_t hdr_size = (sizeof(ccv_dense_matrix_t) + 15) & -16; mat = (ccv_dense_matrix_t*)(data ? data : ccmalloc(ccv_compute_dense_matrix_size(rows, cols, type))); mat->type = (CCV_GET_CHANNEL(type) | CCV_GET_DATA_TYPE(type) | CCV_MATRIX_DENSE) & ~CCV_GARBAGE; mat->type |= data ? CCV_UNMANAGED : CCV_REUSABLE; // it still could be reusable because the signature could be derived one. mat->data.u8 = (unsigned char*)mat + hdr_size; } mat->sig = sig; #if CCV_NNC_TENSOR_TFB mat->resides = CCV_TENSOR_CPU_MEMORY; mat->format = CCV_TENSOR_FORMAT_NHWC; mat->datatype = CCV_GET_DATA_TYPE(type); mat->channels = CCV_GET_CHANNEL(type); mat->reserved = 0; #endif mat->rows = rows; mat->cols = cols; mat->step = CCV_GET_STEP(cols, type); mat->refcount = 1; return mat; }
ccv_sparse_matrix_t* ccv_sparse_matrix_new(int rows, int cols, int type, int major, uint64_t sig) { ccv_sparse_matrix_t* mat; mat = (ccv_sparse_matrix_t*)ccmalloc(sizeof(ccv_sparse_matrix_t)); mat->rows = rows; mat->cols = cols; mat->type = type | CCV_MATRIX_SPARSE | ((type & CCV_DENSE_VECTOR) ? CCV_DENSE_VECTOR : CCV_SPARSE_VECTOR); mat->major = major; mat->prime = 0; mat->load_factor = 0; mat->refcount = 1; mat->vector = (ccv_dense_vector_t*)ccmalloc(CCV_GET_SPARSE_PRIME(mat->prime) * sizeof(ccv_dense_vector_t)); int i; for (i = 0; i < CCV_GET_SPARSE_PRIME(mat->prime); i++) { mat->vector[i].index = -1; mat->vector[i].length = 0; mat->vector[i].next = 0; } return mat; }
ccv_bbf_classifier_cascade_t* ccv_bbf_classifier_cascade_read_binary(char* s) { int i; ccv_bbf_classifier_cascade_t* cascade = (ccv_bbf_classifier_cascade_t*)ccmalloc(sizeof(ccv_bbf_classifier_cascade_t)); APPROX int* count_ptr = DEDORSE(&cascade->count); memcpy(count_ptr, s, sizeof(cascade->count)); s += sizeof(cascade->count); memcpy(&cascade->size.width, s, sizeof(cascade->size.width)); s += sizeof(cascade->size.width); memcpy(&cascade->size.height, s, sizeof(cascade->size.height)); s += sizeof(cascade->size.height); ccv_bbf_stage_classifier_t* classifier = cascade->stage_classifier = (ccv_bbf_stage_classifier_t*)ccmalloc(ENDORSE(cascade->count) * sizeof(ccv_bbf_stage_classifier_t)); for (i = 0; i < ENDORSE(cascade->count); i++, classifier++) { memcpy(&classifier->count, s, sizeof(classifier->count)); s += sizeof(classifier->count); memcpy(&classifier->threshold, s, sizeof(classifier->threshold)); s += sizeof(classifier->threshold); classifier->feature = (ccv_bbf_feature_t*)ccmalloc(ENDORSE(classifier->count) * sizeof(ccv_bbf_feature_t)); classifier->alpha = (float*)DEDORSE(ccmalloc(ENDORSE(classifier->count) * 2 * sizeof(float))); memcpy(classifier->feature, s, classifier->count * sizeof(ccv_bbf_feature_t)); s += classifier->count * sizeof(ccv_bbf_feature_t); memcpy(classifier->alpha, s, classifier->count * 2 * sizeof(float)); s += classifier->count * 2 * sizeof(float); } return cascade; }
void ccv_nnc_symbolic_graph_set_while_expr(ccv_nnc_symbolic_graph_t* const while_graph, const ccv_nnc_graph_while_f while_expr, const void* const while_data, const ccv_nnc_graph_exec_symbol_t* const breakpoints, const int breakpoint_size) { while_graph->while_expr = while_expr; while_graph->while_data = while_data; if (breakpoint_size > 0) { assert(breakpoints); while_graph->breakpoint_size = breakpoint_size; while_graph->breakpoints = (ccv_nnc_graph_exec_symbol_t*)ccmalloc(sizeof(ccv_nnc_graph_exec_symbol_t) * breakpoint_size); memcpy(while_graph->breakpoints, breakpoints, sizeof(ccv_nnc_graph_exec_symbol_t) * breakpoint_size); } }
int main(int argc, char** argv) { ccv_enable_default_cache(); assert(argc == 2); FILE *r = fopen(argv[1], "r"); char* file = (char*)malloc(1024); ccv_array_t* categorizeds = ccv_array_new(sizeof(ccv_categorized_t), 64, 0); size_t len = 1024; ssize_t read; while ((read = getline(&file, &len, r)) != -1) { while(read > 1 && isspace(file[read - 1])) read--; file[read] = 0; ccv_file_info_t input; input.filename = (char*)ccmalloc(1024); strncpy(input.filename, file, 1024); ccv_categorized_t categorized = ccv_categorized(0, 0, &input); ccv_array_push(categorizeds, &categorized); } fclose(r); free(file); /* MattNet parameters */ ccv_convnet_layer_param_t params[13] = { // first layer (convolutional => max pool => rnorm) { .type = CCV_CONVNET_CONVOLUTIONAL, .bias = 0, .glorot = sqrtf(2), .input = { .matrix = { .rows = 225, .cols = 225, .channels = 3, .partition = 1, }, }, .output = { .convolutional = { .count = 96, .strides = 2, .border = 1, .rows = 7, .cols = 7, .channels = 3, .partition = 2, }, }, }, { .type = CCV_CONVNET_LOCAL_RESPONSE_NORM,
ccv_bbf_classifier_cascade_t* ccv_bbf_read_classifier_cascade(const char* directory) { char buf[1024]; sprintf(buf, "%s/cascade.txt", directory); int s, i; FILE* r = fopen(buf, "r"); if (r == 0) return 0; ccv_bbf_classifier_cascade_t* cascade = (ccv_bbf_classifier_cascade_t*)ccmalloc(sizeof(ccv_bbf_classifier_cascade_t)); s = fscanf(r, "%d %d %d", &cascade->count, &cascade->size.width, &cascade->size.height); assert(s > 0); cascade->stage_classifier = (ccv_bbf_stage_classifier_t*)ccmalloc(ENDORSE(cascade->count) * sizeof(ccv_bbf_stage_classifier_t)); for (i = 0; i < ENDORSE(cascade->count); i++) { sprintf(buf, "%s/stage-%d.txt", directory, i); if (_ccv_read_bbf_stage_classifier(buf, &cascade->stage_classifier[i]) < 0) { cascade->count = i; break; } } fclose(r); return cascade; }
ccv_array_t* ccv_array_new(int rsize, int rnum, uint64_t sig) { ccv_array_t* array; if (ccv_cache_opt && sig != 0) { uint8_t type; array = (ccv_array_t*)ccv_cache_out(&ccv_cache, sig, &type); if (array) { assert(type == 1); array->type |= CCV_GARBAGE; array->refcount = 1; return array; } } array = (ccv_array_t*)ccmalloc(sizeof(ccv_array_t)); array->sig = sig; array->type = CCV_REUSABLE & ~CCV_GARBAGE; array->rnum = 0; array->rsize = rsize; array->size = ccv_max(rnum, 2 /* allocate memory for at least 2 items */); array->data = ccmalloc((size_t)array->size * (size_t)rsize); return array; }
void ccv_compress_sparse_matrix(ccv_sparse_matrix_t* mat, ccv_compressed_sparse_matrix_t** csm) { int i, j; int nnz = 0; int length = CCV_GET_SPARSE_PRIME(mat->prime); for (i = 0; i < length; i++) { ccv_dense_vector_t* vector = &mat->vector[i]; #define while_block(_, _while_get) \ while (vector != 0) \ { \ if (vector->index != -1) \ { \ if (mat->type & CCV_DENSE_VECTOR) \ { \ for (j = 0; j < vector->length; j++) \ if (_while_get(vector->data.u8, j, 0) != 0) \ nnz++; \ } else { \ nnz += vector->load_factor; \ } \ } \ vector = vector->next; \ } ccv_matrix_getter(mat->type, while_block); #undef while_block } ccv_compressed_sparse_matrix_t* cm = *csm = (ccv_compressed_sparse_matrix_t*)ccmalloc(sizeof(ccv_compressed_sparse_matrix_t) + nnz * sizeof(int) + nnz * CCV_GET_DATA_TYPE_SIZE(mat->type) + (((mat->major == CCV_SPARSE_COL_MAJOR) ? mat->cols : mat->rows) + 1) * sizeof(int)); cm->type = (mat->type & ~CCV_MATRIX_SPARSE & ~CCV_SPARSE_VECTOR & ~CCV_DENSE_VECTOR) | ((mat->major == CCV_SPARSE_COL_MAJOR) ? CCV_MATRIX_CSC : CCV_MATRIX_CSR); cm->nnz = nnz; cm->rows = mat->rows; cm->cols = mat->cols; cm->index = (int*)(cm + 1); cm->offset = cm->index + nnz; cm->data.i32 = cm->offset + ((mat->major == CCV_SPARSE_COL_MAJOR) ? mat->cols : mat->rows) + 1; unsigned char* m_ptr = cm->data.u8; int* idx = cm->index; cm->offset[0] = 0; for (i = 0; i < ((mat->major == CCV_SPARSE_COL_MAJOR) ? mat->cols : mat->rows); i++) { ccv_dense_vector_t* vector = ccv_get_sparse_matrix_vector(mat, i); if (vector == 0) cm->offset[i + 1] = cm->offset[i]; else { if (mat->type & CCV_DENSE_VECTOR) { int k = 0; #define for_block(_, _for_set, _for_get) \ for (j = 0; j < vector->length; j++) \ if (_for_get(vector->data.u8, j, 0) != 0) \ { \ _for_set(m_ptr, k, _for_get(vector->data.u8, j, 0), 0); \ idx[k] = j; \ k++; \ } ccv_matrix_setter_getter(mat->type, for_block); #undef for_block cm->offset[i + 1] = cm->offset[i] + k; idx += k; m_ptr += k * CCV_GET_DATA_TYPE_SIZE(mat->type); } else { int k = 0; #define for_block(_, _for_set, _for_get) \ for (j = 0; j < vector->length; j++) \ if (vector->indice[j] != -1) \ { \ _for_set(m_ptr, k, _for_get(vector->data.u8, j, 0), 0); \ idx[k] = vector->indice[j]; \ k++; \ } ccv_matrix_setter_getter(mat->type, for_block); #undef for_block switch (CCV_GET_DATA_TYPE(mat->type)) { case CCV_8U: _ccv_indice_uchar_sort(idx, vector->load_factor, (unsigned char*)m_ptr); break; case CCV_32S: _ccv_indice_int_sort(idx, vector->load_factor, (int*)m_ptr); break; case CCV_32F: _ccv_indice_float_sort(idx, vector->load_factor, (float*)m_ptr); break; case CCV_64F: _ccv_indice_double_sort(idx, vector->load_factor, (double*)m_ptr); break; } cm->offset[i + 1] = cm->offset[i] + vector->load_factor; idx += vector->load_factor; m_ptr += vector->load_factor * CCV_GET_DATA_TYPE_SIZE(mat->type); } } } }
int main(int argc, char** argv) { static struct option bbf_options[] = { /* help */ {"help", 0, 0, 0}, /* required parameters */ {"positive-list", 1, 0, 0}, {"background-list", 1, 0, 0}, {"working-dir", 1, 0, 0}, {"negative-count", 1, 0, 0}, {"width", 1, 0, 0}, {"height", 1, 0, 0}, /* optional parameters */ {"base-dir", 1, 0, 0}, {"layer", 1, 0, 0}, {"positive-criteria", 1, 0, 0}, {"negative-criteria", 1, 0, 0}, {"balance", 1, 0, 0}, {"feature-number", 1, 0, 0}, {0, 0, 0, 0} }; char* positive_list = 0; char* background_list = 0; char* working_dir = 0; char* base_dir = 0; int negnum = 0; int width = 0, height = 0; ccv_bbf_new_param_t params = { .pos_crit = 0.9975, .neg_crit = 0.50, .balance_k = 1.0, .layer = 24, .feature_number = 100, .optimizer = CCV_BBF_GENETIC_OPT | CCV_BBF_FLOAT_OPT, }; int i, k; while (getopt_long_only(argc, argv, "", bbf_options, &k) != -1) { switch (k) { case 0: exit_with_help(); case 1: positive_list = optarg; break; case 2: background_list = optarg; break; case 3: working_dir = optarg; break; case 4: negnum = atoi(optarg); break; case 5: width = atoi(optarg); break; case 6: height = atoi(optarg); break; case 7: base_dir = optarg; break; case 8: params.layer = atoi(optarg); break; case 9: params.pos_crit = atof(optarg); break; case 10: params.neg_crit = atof(optarg); break; case 11: params.balance_k = atof(optarg); break; case 12: params.feature_number = atoi(optarg); break; } } assert(positive_list != 0); assert(background_list != 0); assert(working_dir != 0); assert(negnum > 0); assert(width > 0 && height > 0); ccv_enable_default_cache(); FILE* r0 = fopen(positive_list, "r"); assert(r0 && "positive-list doesn't exists"); FILE* r1 = fopen(background_list, "r"); assert(r1 && "background-list doesn't exists"); char* file = (char*)malloc(1024); int dirlen = (base_dir != 0) ? strlen(base_dir) + 1 : 0; size_t len = 1024; ssize_t read; int capacity = 32, size = 0; ccv_dense_matrix_t** posimg = (ccv_dense_matrix_t**)ccmalloc(sizeof(ccv_dense_matrix_t*) * capacity); while ((read = getline(&file, &len, r0)) != -1) { while(read > 1 && isspace(file[read - 1])) read--; file[read] = 0; char* posfile = (char*)ccmalloc(1024); if (base_dir != 0) { strncpy(posfile, base_dir, 1024); posfile[dirlen - 1] = '/'; } strncpy(posfile + dirlen, file, 1024 - dirlen); posimg[size] = 0; ccv_read(posfile, &posimg[size], CCV_IO_GRAY | CCV_IO_ANY_FILE); if (posimg != 0) { ++size; if (size >= capacity) { capacity *= 2; posimg = (ccv_dense_matrix_t**)ccrealloc(posimg, sizeof(ccv_dense_matrix_t*) * capacity); } } } fclose(r0); int posnum = size; capacity = 32; size = 0; char** bgfiles = (char**)ccmalloc(sizeof(char*) * capacity); while ((read = getline(&file, &len, r1)) != -1) { while(read > 1 && isspace(file[read - 1])) read--; file[read] = 0; bgfiles[size] = (char*)ccmalloc(1024); if (base_dir != 0) { strncpy(bgfiles[size], base_dir, 1024); bgfiles[size][dirlen - 1] = '/'; } strncpy(bgfiles[size] + dirlen, file, 1024 - dirlen); ++size; if (size >= capacity) { capacity *= 2; bgfiles = (char**)ccrealloc(bgfiles, sizeof(char*) * capacity); } } fclose(r1); int bgnum = size; free(file); ccv_bbf_classifier_cascade_new(posimg, posnum, bgfiles, bgnum, negnum, ccv_size(width, height), working_dir, params); for (i = 0; i < bgnum; i++) free(bgfiles[i]); for (i = 0; i < posnum; i++) ccv_matrix_free(&posimg[i]); free(posimg); free(bgfiles); ccv_disable_cache(); return 0; }
ccv_array_t* ccv_bbf_detect_objects(ccv_dense_matrix_t* a, ccv_bbf_classifier_cascade_t** _cascade, int count, ccv_bbf_param_t params) { int hr = a->rows / ENDORSE(params.size.height); int wr = a->cols / ENDORSE(params.size.width); double scale = pow(2., 1. / (params.interval + 1.)); APPROX int next = params.interval + 1; int scale_upto = (int)(log((double)ccv_min(hr, wr)) / log(scale)); ccv_dense_matrix_t** pyr = (ccv_dense_matrix_t**)alloca(ENDORSE(scale_upto + next * 2) * 4 * sizeof(ccv_dense_matrix_t*)); memset(pyr, 0, (scale_upto + next * 2) * 4 * sizeof(ccv_dense_matrix_t*)); if (ENDORSE(params.size.height != _cascade[0]->size.height || params.size.width != _cascade[0]->size.width)) ccv_resample(a, &pyr[0], 0, a->rows * ENDORSE(_cascade[0]->size.height / params.size.height), a->cols * ENDORSE(_cascade[0]->size.width / params.size.width), CCV_INTER_AREA); else pyr[0] = a; APPROX int i; int j, k, t, x, y, q; for (i = 1; ENDORSE(i < ccv_min(params.interval + 1, scale_upto + next * 2)); i++) ccv_resample(pyr[0], &pyr[i * 4], 0, (int)(pyr[0]->rows / pow(scale, i)), (int)(pyr[0]->cols / pow(scale, i)), CCV_INTER_AREA); for (i = next; ENDORSE(i < scale_upto + next * 2); i++) ccv_sample_down(pyr[i * 4 - next * 4], &pyr[i * 4], 0, 0, 0); if (params.accurate) for (i = next * 2; ENDORSE(i < scale_upto + next * 2); i++) { ccv_sample_down(pyr[i * 4 - next * 4], &pyr[i * 4 + 1], 0, 1, 0); ccv_sample_down(pyr[i * 4 - next * 4], &pyr[i * 4 + 2], 0, 0, 1); ccv_sample_down(pyr[i * 4 - next * 4], &pyr[i * 4 + 3], 0, 1, 1); } ccv_array_t* idx_seq; ccv_array_t* seq = ccv_array_new(sizeof(ccv_comp_t), 64, 0); ccv_array_t* seq2 = ccv_array_new(sizeof(ccv_comp_t), 64, 0); ccv_array_t* result_seq = ccv_array_new(sizeof(ccv_comp_t), 64, 0); /* detect in multi scale */ for (t = 0; t < count; t++) { ccv_bbf_classifier_cascade_t* cascade = _cascade[t]; APPROX float scale_x = (float) params.size.width / (float) cascade->size.width; APPROX float scale_y = (float) params.size.height / (float) cascade->size.height; ccv_array_clear(seq); for (i = 0; ENDORSE(i < scale_upto); i++) { APPROX int dx[] = {0, 1, 0, 1}; APPROX int dy[] = {0, 0, 1, 1}; APPROX int i_rows = pyr[i * 4 + next * 8]->rows - ENDORSE(cascade->size.height >> 2); APPROX int steps[] = { pyr[i * 4]->step, pyr[i * 4 + next * 4]->step, pyr[i * 4 + next * 8]->step }; APPROX int i_cols = pyr[i * 4 + next * 8]->cols - ENDORSE(cascade->size.width >> 2); int paddings[] = { pyr[i * 4]->step * 4 - i_cols * 4, pyr[i * 4 + next * 4]->step * 2 - i_cols * 2, pyr[i * 4 + next * 8]->step - i_cols }; for (q = 0; q < (params.accurate ? 4 : 1); q++) { APPROX unsigned char* u8[] = { pyr[i * 4]->data.u8 + dx[q] * 2 + dy[q] * pyr[i * 4]->step * 2, pyr[i * 4 + next * 4]->data.u8 + dx[q] + dy[q] * pyr[i * 4 + next * 4]->step, pyr[i * 4 + next * 8 + q]->data.u8 }; for (y = 0; ENDORSE(y < i_rows); y++) { for (x = 0; ENDORSE(x < i_cols); x++) { APPROX float sum; APPROX int flag = 1; ccv_bbf_stage_classifier_t* classifier = cascade->stage_classifier; for (j = 0; j < ENDORSE(cascade->count); ++j, ++classifier) { sum = 0; APPROX float* alpha = classifier->alpha; ccv_bbf_feature_t* feature = classifier->feature; for (k = 0; k < ENDORSE(classifier->count); ++k, alpha += 2, ++feature) sum += alpha[_ccv_run_bbf_feature(feature, ENDORSE(steps), u8)]; if (ENDORSE(sum) < ENDORSE(classifier->threshold)) { flag = 0; break; } } if (ENDORSE(flag)) { ccv_comp_t comp; comp.rect = ccv_rect((int)((x * 4 + dx[q] * 2) * scale_x + 0.5), (int)((y * 4 + dy[q] * 2) * scale_y + 0.5), (int)(cascade->size.width * scale_x + 0.5), (int)(cascade->size.height * scale_y + 0.5)); comp.neighbors = 1; comp.classification.id = t; comp.classification.confidence = sum; ccv_array_push(seq, &comp); } u8[0] += 4; u8[1] += 2; u8[2] += 1; } u8[0] += paddings[0]; u8[1] += paddings[1]; u8[2] += paddings[2]; } } scale_x *= scale; scale_y *= scale; } /* the following code from OpenCV's haar feature implementation */ if(params.min_neighbors == 0) { for (i = 0; ENDORSE(i < seq->rnum); i++) { ccv_comp_t* comp = (ccv_comp_t*)ENDORSE(ccv_array_get(seq, i)); ccv_array_push(result_seq, comp); } } else { idx_seq = 0; ccv_array_clear(seq2); // group retrieved rectangles in order to filter out noise int ncomp = ccv_array_group(seq, &idx_seq, _ccv_is_equal_same_class, 0); ccv_comp_t* comps = (ccv_comp_t*)ccmalloc((ncomp + 1) * sizeof(ccv_comp_t)); memset(comps, 0, (ncomp + 1) * sizeof(ccv_comp_t)); // count number of neighbors for(i = 0; ENDORSE(i < seq->rnum); i++) { ccv_comp_t r1 = *(ccv_comp_t*)ENDORSE(ccv_array_get(seq, i)); int idx = *(int*)ENDORSE(ccv_array_get(idx_seq, i)); if (ENDORSE(comps[idx].neighbors) == 0) comps[idx].classification.confidence = r1.classification.confidence; ++comps[idx].neighbors; comps[idx].rect.x += r1.rect.x; comps[idx].rect.y += r1.rect.y; comps[idx].rect.width += r1.rect.width; comps[idx].rect.height += r1.rect.height; comps[idx].classification.id = r1.classification.id; comps[idx].classification.confidence = ccv_max(comps[idx].classification.confidence, r1.classification.confidence); } // calculate average bounding box for(i = 0; ENDORSE(i < ncomp); i++) { int n = ENDORSE(comps[i].neighbors); if(n >= params.min_neighbors) { ccv_comp_t comp; comp.rect.x = (comps[i].rect.x * 2 + n) / (2 * n); comp.rect.y = (comps[i].rect.y * 2 + n) / (2 * n); comp.rect.width = (comps[i].rect.width * 2 + n) / (2 * n); comp.rect.height = (comps[i].rect.height * 2 + n) / (2 * n); comp.neighbors = comps[i].neighbors; comp.classification.id = comps[i].classification.id; comp.classification.confidence = comps[i].classification.confidence; ccv_array_push(seq2, &comp); } } // filter out small face rectangles inside large face rectangles for(i = 0; ENDORSE(i < seq2->rnum); i++) { ccv_comp_t r1 = *(ccv_comp_t*)ENDORSE(ccv_array_get(seq2, i)); APPROX int flag = 1; for(j = 0; ENDORSE(j < seq2->rnum); j++) { ccv_comp_t r2 = *(ccv_comp_t*)ENDORSE(ccv_array_get(seq2, j)); APPROX int distance = (int)(r2.rect.width * 0.25 + 0.5); if(ENDORSE(i != j && r1.classification.id == r2.classification.id && r1.rect.x >= r2.rect.x - distance && r1.rect.y >= r2.rect.y - distance && r1.rect.x + r1.rect.width <= r2.rect.x + r2.rect.width + distance && r1.rect.y + r1.rect.height <= r2.rect.y + r2.rect.height + distance && (r2.neighbors > ccv_max(3, r1.neighbors) || r1.neighbors < 3))) { flag = 0; break; } } if(ENDORSE(flag)) ccv_array_push(result_seq, &r1); } ccv_array_free(idx_seq); ccfree(comps); } } ccv_array_free(seq); ccv_array_free(seq2); ccv_array_t* result_seq2; /* the following code from OpenCV's haar feature implementation */ if (params.flags & CCV_BBF_NO_NESTED) { result_seq2 = ccv_array_new(sizeof(ccv_comp_t), 64, 0); idx_seq = 0; // group retrieved rectangles in order to filter out noise int ncomp = ccv_array_group(result_seq, &idx_seq, _ccv_is_equal, 0); ccv_comp_t* comps = (ccv_comp_t*)ccmalloc((ncomp + 1) * sizeof(ccv_comp_t)); memset(comps, 0, (ncomp + 1) * sizeof(ccv_comp_t)); // count number of neighbors for(i = 0; ENDORSE(i < result_seq->rnum); i++) { ccv_comp_t r1 = *(ccv_comp_t*)ENDORSE(ccv_array_get(result_seq, i)); int idx = *(int*)ENDORSE(ccv_array_get(idx_seq, i)); if (ENDORSE(comps[idx].neighbors == 0 || comps[idx].classification.confidence < r1.classification.confidence)) { comps[idx].classification.confidence = r1.classification.confidence; comps[idx].neighbors = 1; comps[idx].rect = r1.rect; comps[idx].classification.id = r1.classification.id; } } // calculate average bounding box for(i = 0; ENDORSE(i < ncomp); i++) if(ENDORSE(comps[i].neighbors)) ccv_array_push(result_seq2, &comps[i]); ccv_array_free(result_seq); ccfree(comps); } else { result_seq2 = result_seq; } for (i = 1; ENDORSE(i < scale_upto + next * 2); i++) ccv_matrix_free(pyr[i * 4]); if (params.accurate) for (i = next * 2; ENDORSE(i < scale_upto + next * 2); i++) { ccv_matrix_free(pyr[i * 4 + 1]); ccv_matrix_free(pyr[i * 4 + 2]); ccv_matrix_free(pyr[i * 4 + 3]); } if (ENDORSE(params.size.height != _cascade[0]->size.height || params.size.width != _cascade[0]->size.width)) ccv_matrix_free(pyr[0]); return result_seq2; }
int main(int argc, char** argv) { #ifdef HAVE_AVCODEC #ifdef HAVE_AVFORMAT #ifdef HAVE_SWSCALE assert(argc == 6); ccv_rect_t box = ccv_rect(atoi(argv[2]), atoi(argv[3]), atoi(argv[4]), atoi(argv[5])); box.width = box.width - box.x + 1; box.height = box.height - box.y + 1; printf("%d,%d,%d,%d,%f\n", box.x, box.y, box.width + box.x - 1, box.height + box.y - 1, 1.0f); // init av-related structs AVFormatContext* ic = 0; int video_stream = -1; AVStream* video_st = 0; AVFrame* picture = 0; AVFrame rgb_picture; memset(&rgb_picture, 0, sizeof(AVPicture)); AVPacket packet; memset(&packet, 0, sizeof(AVPacket)); av_init_packet(&packet); av_register_all(); avformat_network_init(); // load video and codec avformat_open_input(&ic, argv[1], 0, 0); avformat_find_stream_info(ic, 0); int i; for (i = 0; i < ic->nb_streams; i++) { AVCodecContext* enc = ic->streams[i]->codec; enc->thread_count = 2; if (AVMEDIA_TYPE_VIDEO == enc->codec_type && video_stream < 0) { AVCodec* codec = avcodec_find_decoder(enc->codec_id); if (!codec || avcodec_open2(enc, codec, 0) < 0) continue; video_stream = i; video_st = ic->streams[i]; picture = avcodec_alloc_frame(); rgb_picture.data[0] = (uint8_t*)ccmalloc(avpicture_get_size(PIX_FMT_RGB24, enc->width, enc->height)); avpicture_fill((AVPicture*)&rgb_picture, rgb_picture.data[0], PIX_FMT_RGB24, enc->width, enc->height); break; } } int got_picture = 0; while (!got_picture) { int result = av_read_frame(ic, &packet); if (result == AVERROR(EAGAIN)) continue; avcodec_decode_video2(video_st->codec, picture, &got_picture, &packet); } ccv_enable_default_cache(); struct SwsContext* picture_ctx = sws_getCachedContext(0, video_st->codec->width, video_st->codec->height, video_st->codec->pix_fmt, video_st->codec->width, video_st->codec->height, PIX_FMT_RGB24, SWS_BICUBIC, 0, 0, 0); sws_scale(picture_ctx, (const uint8_t* const*)picture->data, picture->linesize, 0, video_st->codec->height, rgb_picture.data, rgb_picture.linesize); ccv_dense_matrix_t* x = 0; ccv_read(rgb_picture.data[0], &x, CCV_IO_RGB_RAW | CCV_IO_GRAY, video_st->codec->height, video_st->codec->width, rgb_picture.linesize[0]); ccv_tld_t* tld = ccv_tld_new(x, box, ccv_tld_default_params); ccv_dense_matrix_t* y = 0; for (;;) { got_picture = 0; int result = av_read_frame(ic, &packet); if (result == AVERROR(EAGAIN)) continue; avcodec_decode_video2(video_st->codec, picture, &got_picture, &packet); if (!got_picture) break; sws_scale(picture_ctx, (const uint8_t* const*)picture->data, picture->linesize, 0, video_st->codec->height, rgb_picture.data, rgb_picture.linesize); ccv_read(rgb_picture.data[0], &y, CCV_IO_RGB_RAW | CCV_IO_GRAY, video_st->codec->height, video_st->codec->width, rgb_picture.linesize[0]); ccv_tld_info_t info; ccv_comp_t newbox = ccv_tld_track_object(tld, x, y, &info); printf("%04d: performed learn: %d, performed track: %d, successfully track: %d; %d passed fern detector, %d passed nnc detector, %d merged, %d confident matches, %d close matches\n", tld->count, info.perform_learn, info.perform_track, info.track_success, info.ferns_detects, info.nnc_detects, info.clustered_detects, info.confident_matches, info.close_matches); ccv_dense_matrix_t* image = 0; ccv_read(rgb_picture.data[0], &image, CCV_IO_RGB_RAW | CCV_IO_RGB_COLOR, video_st->codec->height, video_st->codec->width, rgb_picture.linesize[0]); // draw out // for (i = 0; i < tld->top->rnum; i++) if (tld->found) { ccv_comp_t* comp = &newbox; // (ccv_comp_t*)ccv_array_get(tld->top, i); if (comp->rect.x >= 0 && comp->rect.x + comp->rect.width < image->cols && comp->rect.y >= 0 && comp->rect.y + comp->rect.height < image->rows) { int x, y; for (x = comp->rect.x; x < comp->rect.x + comp->rect.width; x++) { image->data.u8[image->step * comp->rect.y + x * 3] = image->data.u8[image->step * (comp->rect.y + comp->rect.height - 1) + x * 3] = 255; image->data.u8[image->step * comp->rect.y + x * 3 + 1] = image->data.u8[image->step * (comp->rect.y + comp->rect.height - 1) + x * 3 + 1] = image->data.u8[image->step * comp->rect.y + x * 3 + 2] = image->data.u8[image->step * (comp->rect.y + comp->rect.height - 1) + x * 3 + 2] = 0; } for (y = comp->rect.y; y < comp->rect.y + comp->rect.height; y++) { image->data.u8[image->step * y + comp->rect.x * 3] = image->data.u8[image->step * y + (comp->rect.x + comp->rect.width - 1) * 3] = 255; image->data.u8[image->step * y + comp->rect.x * 3 + 1] = image->data.u8[image->step * y + (comp->rect.x + comp->rect.width - 1) * 3 + 1] = image->data.u8[image->step * y + comp->rect.x * 3 + 2] = image->data.u8[image->step * y + (comp->rect.x + comp->rect.width - 1) * 3 + 2] = 0; } } } char filename[1024]; sprintf(filename, "tld-out/output-%04d.png", tld->count); ccv_write(image, filename, 0, CCV_IO_PNG_FILE, 0); ccv_matrix_free(image); if (tld->found) printf("%d,%d,%d,%d,%f\n", newbox.rect.x, newbox.rect.y, newbox.rect.width + newbox.rect.x - 1, newbox.rect.height + newbox.rect.y - 1, newbox.confidence); else printf("NaN,NaN,NaN,NaN,NaN\n"); x = y; y = 0; } ccv_matrix_free(x); ccv_tld_free(tld); ccfree(rgb_picture.data[0]); ccv_disable_cache(); #endif #endif #endif return 0; }
void ccv_set_sparse_matrix_cell(ccv_sparse_matrix_t* mat, int row, int col, void* data) { int i; int index = (mat->major == CCV_SPARSE_COL_MAJOR) ? col : row; int vidx = (mat->major == CCV_SPARSE_COL_MAJOR) ? row : col; int length = CCV_GET_SPARSE_PRIME(mat->prime); ccv_dense_vector_t* vector = ccv_get_sparse_matrix_vector(mat, index); if (vector == 0) { mat->load_factor++; if (mat->load_factor * 4 > CCV_GET_SPARSE_PRIME(mat->prime) * 3) { _ccv_sparse_matrix_expand(mat); length = CCV_GET_SPARSE_PRIME(mat->prime); } vector = &mat->vector[(index * 33) % length]; if (vector->index != -1) { vector = (ccv_dense_vector_t*)ccmalloc(sizeof(ccv_dense_vector_t)); vector->index = -1; vector->length = 0; vector->next = mat->vector[(index * 33) % length].next; mat->vector[(index * 33) % length].next = vector; } } int cell_width = CCV_GET_DATA_TYPE_SIZE(mat->type) * CCV_GET_CHANNEL(mat->type); if (mat->type & CCV_DENSE_VECTOR) { if (vector->index == -1) { vector->prime = -1; vector->length = (mat->major == CCV_SPARSE_COL_MAJOR) ? mat->rows : mat->cols; vector->index = index; vector->step = (vector->length * cell_width + 3) & -4; vector->data.u8 = (unsigned char*)calloc(vector->step, 1); } if (data != 0) memcpy(vector->data.u8 + vidx * cell_width, data, cell_width); } else { if (vector->index == -1) { vector->prime = 0; vector->load_factor = 0; vector->length = CCV_GET_SPARSE_PRIME(vector->prime); vector->index = index; vector->step = (vector->length * cell_width + 3) & -4; vector->data.u8 = (unsigned char*)ccmalloc(vector->step + sizeof(int) * vector->length); vector->indice = (int*)(vector->data.u8 + vector->step); for (i = 0; i < vector->length; i++) vector->indice[i] = -1; } vector->load_factor++; if (vector->load_factor * 2 > vector->length) { _ccv_dense_vector_expand(mat, vector); } i = 0; int h = (vidx * 33) % vector->length; while (vector->indice[(h + i * i) % vector->length] != vidx && vector->indice[(h + i * i) % vector->length] != -1) i++; i = (h + i * i) % vector->length; vector->indice[i] = vidx; if (data != 0) memcpy(vector->data.u8 + i * cell_width, data, cell_width); } }
uint64_t u; uint8_t chr[8]; } sign; int i; for (i = 0; i < 8; i++) sign.chr[i] = rand() & 0xff; return sign.u; } #define N (1000000) TEST_CASE("random cache put/delete/get") { ccv_cache_t cache; ccv_cache_init(&cache, N, 1, ccfree); uint64_t* sigs = ccmalloc(sizeof(uint64_t) * N); void** mems = ccmalloc(sizeof(void*) * N); int i; for (i = 0; i < N; i++) { sigs[i] = uniqid(); mems[i] = ccmalloc(1); ccv_cache_put(&cache, sigs[i], mems[i], 1, 0); REQUIRE_EQ(i + 1, cache.size, "at %d should has cache size %d", i, i); } uint8_t deleted[N]; for (i = 0; i < N; i++) { deleted[i] = 1; if (deleted[i]) ccv_cache_delete(&cache, sigs[i]);
static void _ccv_set_union_mser(ccv_dense_matrix_t* a, ccv_dense_matrix_t* h, ccv_dense_matrix_t* b, ccv_array_t* seq, ccv_mser_param_t params) { assert(params.direction == CCV_BRIGHT_TO_DARK || params.direction == CCV_DARK_TO_BRIGHT); int v, i, j; ccv_mser_node_t* node = (ccv_mser_node_t*)ccmalloc(sizeof(ccv_mser_node_t) * a->rows * a->cols); ccv_mser_node_t** rnode = (ccv_mser_node_t**)ccmalloc(sizeof(ccv_mser_node_t*) * a->rows * a->cols); if (params.range <= 0) params.range = 255; // put it in a block so that the memory allocated can be released in the end int* buck = (int*)alloca(sizeof(int) * (params.range + 2)); memset(buck, 0, sizeof(int) * (params.range + 2)); ccv_mser_node_t* pnode = node; // this for_block is the only computation that can be shared between dark to bright and bright to dark // two MSER alternatives, and it only occupies 10% of overall time, we won't share this computation // at all (also, we need to reinitialize node for the two passes anyway). if (h != 0) { unsigned char* aptr = a->data.u8; unsigned char* hptr = h->data.u8; #define for_block(_for_get_a, _for_get_h) \ for (i = 0; i < a->rows; i++) \ { \ for (j = 0; j < a->cols; j++) \ if (!_for_get_h(hptr, j, 0)) \ ++buck[_for_get_a(aptr, j, 0)]; \ aptr += a->step; \ hptr += h->step; \ } \ for (i = 1; i <= params.range; i++) \ buck[i] += buck[i - 1]; \ buck[params.range + 1] = buck[params.range]; \ aptr = a->data.u8; \ hptr = h->data.u8; \ for (i = 0; i < a->rows; i++) \ { \ for (j = 0; j < a->cols; j++) \ { \ _ccv_mser_init_node(pnode, j, i); \ if (!_for_get_h(hptr, j, 0)) \ rnode[--buck[_for_get_a(aptr, j, 0)]] = pnode; \ else \ pnode->shortcut = 0; /* this means the pnode is not available */ \ ++pnode; \ } \ aptr += a->step; \ hptr += h->step; \ } ccv_matrix_getter_integer_only_a(a->type, ccv_matrix_getter_integer_only, h->type, for_block); #undef for_block } else { unsigned char* aptr = a->data.u8; #define for_block(_, _for_get) \ for (i = 0; i < a->rows; i++) \ { \ for (j = 0; j < a->cols; j++) \ ++buck[_for_get(aptr, j, 0)]; \ aptr += a->step; \ } \ for (i = 1; i <= params.range; i++) \ buck[i] += buck[i - 1]; \ buck[params.range + 1] = buck[params.range]; \ aptr = a->data.u8; \ for (i = 0; i < a->rows; i++) \ { \ for (j = 0; j < a->cols; j++) \ { \ _ccv_mser_init_node(pnode, j, i); \ rnode[--buck[_for_get(aptr, j, 0)]] = pnode; \ ++pnode; \ } \ aptr += a->step; \ } ccv_matrix_getter_integer_only(a->type, for_block); #undef for_block } ccv_array_t* history_list = ccv_array_new(sizeof(ccv_mser_history_t), 64, 0); for (v = 0; v <= params.range; v++) { int range_segment = buck[params.direction == CCV_DARK_TO_BRIGHT ? v : params.range - v]; int range_segment_cap = buck[params.direction == CCV_DARK_TO_BRIGHT ? v + 1 : params.range - v + 1]; for (i = range_segment; i < range_segment_cap; i++) { pnode = rnode[i]; // try to merge pnode with its neighbors static int dx[] = {-1, 0, 1, -1, 1, -1, 0, 1}; static int dy[] = {-1, -1, -1, 0, 0, 1, 1, 1}; ccv_mser_node_t* node0 = _ccv_mser_find_root(pnode); for (j = 0; j < 8; j++) { int x = dx[j] + pnode->point.x; int y = dy[j] + pnode->point.y; if (x >= 0 && x < a->cols && y >= 0 && y < a->rows) { ccv_mser_node_t* nnode = pnode + dx[j] + dy[j] * a->cols; if (nnode->shortcut == 0) // this is a void node, skip continue; ccv_mser_node_t* node1 = _ccv_mser_find_root(nnode); if (node0 != node1) { // grep the extended root information ccv_mser_history_t* root0 = (node0->root >= 0) ? (ccv_mser_history_t*)ccv_array_get(history_list, node0->root) : 0; ccv_mser_history_t* root1 = (node1->root >= 0) ? (ccv_mser_history_t*)ccv_array_get(history_list, node1->root) : 0; // swap the node if root1 has higher rank, or larger in size, or root0 is non-existent if ((root0 && root1 && (root1->value > root0->value || (root1->value == root0->value && root1->rank > root0->rank) || (root1->value == root0->value && root1->rank == root0->rank && root1->size > root0->size))) || (root1 && !root0)) { ccv_mser_node_t* exnode = node0; node0 = node1; node1 = exnode; ccv_mser_history_t* root = root0; root0 = root1; root1 = root; } if (!root0) { ccv_mser_history_t root = { .rank = 0, .size = 1, .value = v, .shortcut = history_list->rnum, .parent = history_list->rnum, .head = node0, .tail = node1 }; node0->root = history_list->rnum; ccv_array_push(history_list, &root); root0 = (ccv_mser_history_t*)ccv_array_get(history_list, history_list->rnum - 1); assert(node1->root == -1); } else if (root0->value < v) { // conceal the old root as history (er), making a new one and pointing to it root0->shortcut = root0->parent = history_list->rnum; ccv_mser_history_t root = *root0; root.value = v; node0->root = history_list->rnum; ccv_array_push(history_list, &root); root0 = (ccv_mser_history_t*)ccv_array_get(history_list, history_list->rnum - 1); root1 = (node1->root >= 0) ? (ccv_mser_history_t*)ccv_array_get(history_list, node1->root) : 0; // the memory may be reallocated root0->rank = ccv_max(root0->rank, (root1 ? root1->rank : 0)) + 1; } if (root1) { if (root1->value < root0->value) // in this case, root1 is sealed as well root1->parent = node0->root; // thus, if root1->parent == itself && root1->shortcut != itself // it is voided, and not sealed root1->shortcut = node0->root; } // merge the two node1->shortcut = node0; root0->size += root1 ? root1->size : 1; /* insert one endless double link list to another, see illustration: * 0->1->2->3->4->5->0 * a->b->c->d->a * set 5.next (0.prev.next) point to a * set 0.prev point to d * set d.next (a.prev.next) point to 0 * set a.prev point to 5 * the result endless double link list will be: * 0->1->2->3->4->5->a->b->c->d->0 */ node0->prev->next = node1; ccv_mser_node_t* prev = node0->prev; node0->prev = node1->prev; node1->prev->next = node0; // consider self-referencing node1->prev = prev; root0->head = node0; root0->tail = node0->prev; } } }
// compute harmonic mean of precision / recall of swt static void _ccv_evaluate_wolf(ccv_array_t* words, ccv_array_t* truth, ccv_swt_param_t params, double* precision, double* recall) { if (words->rnum == 0 || truth->rnum == 0) return; int j, k; double total_recall = 0, total_precision = 0; int* cG = (int*)ccmalloc(sizeof(int) * truth->rnum); int* cD = (int*)ccmalloc(sizeof(int) * words->rnum); memset(cG, 0, sizeof(int) * truth->rnum); memset(cD, 0, sizeof(int) * words->rnum); double* mG = (double*)ccmalloc(sizeof(double) * truth->rnum * words->rnum); double* mD = (double*)ccmalloc(sizeof(double) * truth->rnum * words->rnum); memset(mG, 0, sizeof(double) * truth->rnum * words->rnum); memset(mD, 0, sizeof(double) * truth->rnum * words->rnum); for (j = 0; j < truth->rnum; j++) { ccv_rect_t* rect = (ccv_rect_t*)ccv_array_get(truth, j); for (k = 0; k < words->rnum; k++) { ccv_rect_t* target = (ccv_rect_t*)ccv_array_get(words, k); int match = ccv_max(ccv_min(target->x + target->width, rect->x + rect->width) - ccv_max(target->x, rect->x), 0) * ccv_max(ccv_min(target->y + target->height, rect->y + rect->height) - ccv_max(target->y, rect->y), 0); if (match > 0) { mG[j * words->rnum + k] = (double)match / (double)(rect->width * rect->height); mD[k * truth->rnum + j] = (double)match / (double)(target->width * target->height); ++cG[j]; ++cD[k]; } } } unsigned char* tG = (unsigned char*)ccmalloc(truth->rnum); unsigned char* tD = (unsigned char*)ccmalloc(words->rnum); memset(tG, 0, truth->rnum); memset(tD, 0, words->rnum); // one to one match for (j = 0; j < truth->rnum; j++) { if (cG[j] != 1) continue; ccv_rect_t* rect = (ccv_rect_t*)ccv_array_get(truth, j); for (k = 0; k < words->rnum; k++) { if (cD[k] != 1) continue; ccv_rect_t* target = (ccv_rect_t*)ccv_array_get(words, k); if (mG[j * words->rnum + k] >= one_g && mD[k * truth->rnum + j] >= one_d) { double dx = (target->x + target->width * 0.5) - (rect->x + rect->width * 0.5); double dy = (target->y + target->height * 0.5) - (rect->y + rect->height * 0.5); double d = sqrt(dx * dx + dy * dy) * 2.0 / (sqrt(target->width * target->width + target->height * target->height) + sqrt(rect->width * rect->width + rect->height * rect->height)); if (d < center_diff_thr) { total_recall += 1.0; total_precision += 1.0; assert(tG[j] == 0); assert(tD[k] == 0); tG[j] = tD[k] = 1; } } } } int* many = (int*)ccmalloc(sizeof(int) * ccv_max(words->rnum, truth->rnum)); // one to many match, starts with ground truth for (j = 0; j < truth->rnum; j++) { if (tG[j] || cG[j] <= 1) continue; double one_sum = 0; int no_many = 0; for (k = 0; k < words->rnum; k++) { if (tD[k]) continue; double many_single = mD[k * truth->rnum + j]; if (many_single >= one_d) { one_sum += mG[j * words->rnum + k]; many[no_many] = k; ++no_many; } } if (no_many == 1) { // degrade to one to one match if (mG[j * words->rnum + many[0]] >= one_g && mD[many[0] * truth->rnum + j] >= one_d) { total_recall += 1.0; total_precision += 1.0; tG[j] = tD[many[0]] = 1; } } else if (one_sum >= one_g) { for (k = 0; k < no_many; k++) tD[many[k]] = 1; total_recall += om_one; total_precision += om_one / (1 + log(no_many)); } } // one to many match, with estimate for (k = 0; k < words->rnum; k++) { if (tD[k] || cD[k] <= 1) continue; double one_sum = 0; int no_many = 0; for (j = 0; j < truth->rnum; j++) { if (tG[j]) continue; double many_single = mG[j * words->rnum + k]; if (many_single >= one_g) { one_sum += mD[k * truth->rnum + j]; many[no_many] = j; ++no_many; } } if (no_many == 1) { // degrade to one to one match if (mG[many[0] * words->rnum + k] >= one_g && mD[k * truth->rnum + many[0]] >= one_d) { total_recall += 1.0; total_precision += 1.0; tG[many[0]] = tD[k] = 1; } } else if (one_sum >= one_g) { for (j = 0; j < no_many; j++) tG[many[j]] = 1; total_recall += om_one / (1 + log(no_many)); total_precision += om_one; } } ccfree(many); ccfree(tG); ccfree(tD); ccfree(cG); ccfree(cD); ccfree(mG); ccfree(mD); assert(total_precision < words->rnum + 0.1); assert(total_recall < truth->rnum + 0.1); if (precision) *precision = total_precision; if (recall) *recall = total_recall; }
int main(int argc, char** argv) { static struct option scd_options[] = { /* help */ {"help", 0, 0, 0}, /* required parameters */ {"positive-list", 1, 0, 0}, {"background-list", 1, 0, 0}, {"negative-count", 1, 0, 0}, {"working-dir", 1, 0, 0}, /* optional parameters */ {0, 0, 0, 0} }; char* positive_list = 0; char* background_list = 0; char* working_dir = 0; char* base_dir = 0; int negative_count = 0; int k; while (getopt_long_only(argc, argv, "", scd_options, &k) != -1) { switch (k) { case 0: exit_with_help(); case 1: positive_list = optarg; break; case 2: background_list = optarg; break; case 3: negative_count = atoi(optarg); break; case 4: working_dir = optarg; break; case 5: base_dir = optarg; } } assert(positive_list != 0); assert(background_list != 0); assert(working_dir != 0); assert(negative_count > 0); FILE* r0 = fopen(positive_list, "r"); assert(r0 && "positive-list doesn't exists"); FILE* r1 = fopen(background_list, "r"); assert(r1 && "background-list doesn't exists"); int dirlen = (base_dir != 0) ? strlen(base_dir) + 1 : 0; ccv_array_t* posfiles = ccv_array_new(sizeof(ccv_file_info_t), 32, 0); char* file = (char*)malloc(1024); size_t len = 1024; ssize_t read; while ((read = getline(&file, &len, r0)) != -1) { while(read > 1 && isspace(file[read - 1])) read--; file[read] = 0; ccv_file_info_t file_info; file_info.filename = (char*)ccmalloc(1024); if (base_dir != 0) { strncpy(file_info.filename, base_dir, 1024); file_info.filename[dirlen - 1] = '/'; } strncpy(file_info.filename + dirlen, file, 1024 - dirlen); ccv_array_push(posfiles, &file_info); } fclose(r0); ccv_array_t* hard_mine = (ccv_array_t*)ccv_array_new(sizeof(ccv_file_info_t), 32, 0); while ((read = getline(&file, &len, r1)) != -1) { while(read > 1 && isspace(file[read - 1])) read--; file[read] = 0; ccv_file_info_t file_info; file_info.filename = (char*)ccmalloc(1024); if (base_dir != 0) { strncpy(file_info.filename, base_dir, 1024); file_info.filename[dirlen - 1] = '/'; } strncpy(file_info.filename + dirlen, file, 1024 - dirlen); ccv_array_push(hard_mine, &file_info); } fclose(r1); free(file); ccv_scd_train_param_t params = { .boosting = 10, .size = ccv_size(48, 48), .feature = { .base = ccv_size(8, 8), .range_through = 4, .step_through = 4, }, .stop_criteria = { .hit_rate = 0.995, .false_positive_rate = 0.5, .accu_false_positive_rate = 1e-7, .auc_crit = 1e-5, .maximum_feature = 2048, .prune_stage = 3, .prune_feature = 4, }, .weight_trimming = 0.98,
int main(int argc, char** argv) { static struct option icf_options[] = { /* help */ {"help", 0, 0, 0}, /* required parameters */ {"positive-list", 1, 0, 0}, {"background-list", 1, 0, 0}, {"validate-list", 1, 0, 0}, {"working-dir", 1, 0, 0}, {"negative-count", 1, 0, 0}, {"positive-count", 1, 0, 0}, {"acceptance", 1, 0, 0}, {"size", 1, 0, 0}, {"feature-size", 1, 0, 0}, {"weak-classifier-count", 1, 0, 0}, /* optional parameters */ {"base-dir", 1, 0, 0}, {"grayscale", 1, 0, 0}, {"margin", 1, 0, 0}, {"deform-shift", 1, 0, 0}, {"deform-angle", 1, 0, 0}, {"deform-scale", 1, 0, 0}, {"min-dimension", 1, 0, 0}, {"bootstrap", 1, 0, 0}, {0, 0, 0, 0} }; char* positive_list = 0; char* background_list = 0; char* validate_list = 0; char* working_dir = 0; char* base_dir = 0; int negative_count = 0; int positive_count = 0; ccv_icf_new_param_t params = { .grayscale = 0, .margin = ccv_margin(0, 0, 0, 0), .size = ccv_size(0, 0), .deform_shift = 1, .deform_angle = 0, .deform_scale = 0.075, .feature_size = 0, .weak_classifier = 0, .min_dimension = 2, .bootstrap = 3, .detector = ccv_icf_default_params, }; params.detector.step_through = 4; // for faster negatives bootstrap time int i, k; char* token; char* saveptr; while (getopt_long_only(argc, argv, "", icf_options, &k) != -1) { switch (k) { case 0: exit_with_help(); case 1: positive_list = optarg; break; case 2: background_list = optarg; break; case 3: validate_list = optarg; break; case 4: working_dir = optarg; break; case 5: negative_count = atoi(optarg); break; case 6: positive_count = atoi(optarg); break; case 7: params.acceptance = atof(optarg); break; case 8: token = strtok_r(optarg, "x", &saveptr); params.size.width = atoi(token); token = strtok_r(0, "x", &saveptr); params.size.height = atoi(token); break; case 9: params.feature_size = atoi(optarg); break; case 10: params.weak_classifier = atoi(optarg); break; case 11: base_dir = optarg; break; case 12: params.grayscale = !!atoi(optarg); break; case 13: token = strtok_r(optarg, ",", &saveptr); params.margin.left = atoi(token); token = strtok_r(0, ",", &saveptr); params.margin.top = atoi(token); token = strtok_r(0, ",", &saveptr); params.margin.right = atoi(token); token = strtok_r(0, ",", &saveptr); params.margin.bottom = atoi(token); break; case 14: params.deform_shift = atof(optarg); break; case 15: params.deform_angle = atof(optarg); break; case 16: params.deform_scale = atof(optarg); break; case 17: params.min_dimension = atoi(optarg); break; case 18: params.bootstrap = atoi(optarg); break; } } assert(positive_list != 0); assert(background_list != 0); assert(validate_list != 0); assert(working_dir != 0); assert(positive_count > 0); assert(negative_count > 0); assert(params.size.width > 0); assert(params.size.height > 0); ccv_enable_cache(512 * 1024 * 1024); FILE* r0 = fopen(positive_list, "r"); assert(r0 && "positive-list doesn't exists"); FILE* r1 = fopen(background_list, "r"); assert(r1 && "background-list doesn't exists"); FILE* r2 = fopen(validate_list, "r"); assert(r2 && "validate-list doesn't exists"); char* file = (char*)malloc(1024); ccv_decimal_pose_t pose; int dirlen = (base_dir != 0) ? strlen(base_dir) + 1 : 0; ccv_array_t* posfiles = ccv_array_new(sizeof(ccv_file_info_t), 32, 0); // roll pitch yaw while (fscanf(r0, "%s %f %f %f %f %f %f %f", file, &pose.x, &pose.y, &pose.a, &pose.b, &pose.roll, &pose.pitch, &pose.yaw) != EOF) { ccv_file_info_t file_info; file_info.filename = (char*)ccmalloc(1024); if (base_dir != 0) { strncpy(file_info.filename, base_dir, 1024); file_info.filename[dirlen - 1] = '/'; } strncpy(file_info.filename + dirlen, file, 1024 - dirlen); file_info.pose = pose; ccv_array_push(posfiles, &file_info); } fclose(r0); size_t len = 1024; ssize_t read; ccv_array_t* bgfiles = (ccv_array_t*)ccv_array_new(sizeof(ccv_file_info_t), 32, 0); while ((read = getline(&file, &len, r1)) != -1) { while(read > 1 && isspace(file[read - 1])) read--; file[read] = 0; ccv_file_info_t file_info; file_info.filename = (char*)ccmalloc(1024); if (base_dir != 0) { strncpy(file_info.filename, base_dir, 1024); file_info.filename[dirlen - 1] = '/'; } strncpy(file_info.filename + dirlen, file, 1024 - dirlen); ccv_array_push(bgfiles, &file_info); } fclose(r1); ccv_array_t* validatefiles = ccv_array_new(sizeof(ccv_file_info_t), 32, 0); // roll pitch yaw while (fscanf(r2, "%s %f %f %f %f %f %f %f", file, &pose.x, &pose.y, &pose.a, &pose.b, &pose.roll, &pose.pitch, &pose.yaw) != EOF) { ccv_file_info_t file_info; file_info.filename = (char*)ccmalloc(1024); if (base_dir != 0) { strncpy(file_info.filename, base_dir, 1024); file_info.filename[dirlen - 1] = '/'; } strncpy(file_info.filename + dirlen, file, 1024 - dirlen); file_info.pose = pose; ccv_array_push(validatefiles, &file_info); } fclose(r2); free(file); ccv_icf_classifier_cascade_t* classifier = ccv_icf_classifier_cascade_new(posfiles, positive_count, bgfiles, negative_count, validatefiles, working_dir, params); char filename[1024]; snprintf(filename, 1024, "%s/final-cascade", working_dir); ccv_icf_write_classifier_cascade(classifier, filename); for (i = 0; i < posfiles->rnum; i++) { ccv_file_info_t* file_info = (ccv_file_info_t*)ccv_array_get(posfiles, i); free(file_info->filename); } ccv_array_free(posfiles); for (i = 0; i < bgfiles->rnum; i++) { ccv_file_info_t* file_info = (ccv_file_info_t*)ccv_array_get(bgfiles, i); free(file_info->filename); } ccv_array_free(bgfiles); for (i = 0; i < validatefiles->rnum; i++) { ccv_file_info_t* file_info = (ccv_file_info_t*)ccv_array_get(validatefiles, i); free(file_info->filename); } ccv_array_free(validatefiles); ccv_disable_cache(); return 0; }
int main(int argc, char** argv) { static struct option image_net_options[] = { /* help */ {"help", 0, 0, 0}, /* required parameters */ {"train-list", 1, 0, 0}, {"test-list", 1, 0, 0}, {"working-dir", 1, 0, 0}, /* optional parameters */ {"base-dir", 1, 0, 0}, {"max-epoch", 1, 0, 0}, {"iterations", 1, 0, 0}, {0, 0, 0, 0} }; char* train_list = 0; char* test_list = 0; char* working_dir = 0; char* base_dir = 0; ccv_convnet_train_param_t train_params = { .max_epoch = 100, .mini_batch = 64, .sgd_frequency = 1, // do sgd every sgd_frequency batches (mini_batch * device_count * sgd_frequency) .iterations = 50000, .device_count = 4, .peer_access = 1, .symmetric = 1, .image_manipulation = 0.2, .color_gain = 0.001, .input = { .min_dim = 257, .max_dim = 257, }, }; int i, c; while (getopt_long_only(argc, argv, "", image_net_options, &c) != -1) { switch (c) { case 0: exit_with_help(); case 1: train_list = optarg; break; case 2: test_list = optarg; break; case 3: working_dir = optarg; break; case 4: base_dir = optarg; break; case 5: train_params.max_epoch = atoi(optarg); break; case 6: train_params.iterations = atoi(optarg); break; } } if (!train_list || !test_list || !working_dir) exit_with_help(); ccv_enable_default_cache(); FILE *r0 = fopen(train_list, "r"); assert(r0 && "train-list doesn't exists"); FILE* r1 = fopen(test_list, "r"); assert(r1 && "test-list doesn't exists"); char* file = (char*)malloc(1024); int dirlen = (base_dir != 0) ? strlen(base_dir) + 1 : 0; ccv_array_t* categorizeds = ccv_array_new(sizeof(ccv_categorized_t), 64, 0); while (fscanf(r0, "%d %s", &c, file) != EOF) { char* filename = (char*)ccmalloc(1024); if (base_dir != 0) { strncpy(filename, base_dir, 1024); filename[dirlen - 1] = '/'; } strncpy(filename + dirlen, file, 1024 - dirlen); ccv_file_info_t file_info = { .filename = filename, }; // imageNet's category class starts from 1, thus, minus 1 to get 0-index ccv_categorized_t categorized = ccv_categorized(c - 1, 0, &file_info); ccv_array_push(categorizeds, &categorized); } fclose(r0); ccv_array_t* tests = ccv_array_new(sizeof(ccv_categorized_t), 64, 0); while (fscanf(r1, "%d %s", &c, file) != EOF) { char* filename = (char*)ccmalloc(1024); if (base_dir != 0) { strncpy(filename, base_dir, 1024); filename[dirlen - 1] = '/'; } strncpy(filename + dirlen, file, 1024 - dirlen); ccv_file_info_t file_info = { .filename = filename, }; // imageNet's category class starts from 1, thus, minus 1 to get 0-index ccv_categorized_t categorized = ccv_categorized(c - 1, 0, &file_info); ccv_array_push(tests, &categorized); } fclose(r1); free(file); // #define model_params vgg_d_params #define model_params matt_c_params int depth = sizeof(model_params) / sizeof(ccv_convnet_layer_param_t); ccv_convnet_t* convnet = ccv_convnet_new(1, ccv_size(257, 257), model_params, depth); if (ccv_convnet_verify(convnet, 1000) == 0) { ccv_convnet_layer_train_param_t layer_params[depth]; memset(layer_params, 0, sizeof(layer_params)); for (i = 0; i < depth; i++) { layer_params[i].w.decay = 0.0005; layer_params[i].w.learn_rate = 0.01; layer_params[i].w.momentum = 0.9; layer_params[i].bias.decay = 0; layer_params[i].bias.learn_rate = 0.01; layer_params[i].bias.momentum = 0.9; } // set the two full connect layers to last with dropout rate at 0.5 for (i = depth - 3; i < depth - 1; i++) layer_params[i].dor = 0.5; train_params.layer_params = layer_params; ccv_set_cli_output_levels(ccv_cli_output_level_and_above(CCV_CLI_INFO)); ccv_convnet_supervised_train(convnet, categorizeds, tests, working_dir, train_params); } else { PRINT(CCV_CLI_ERROR, "Invalid convnet configuration\n"); } ccv_convnet_free(convnet); ccv_disable_cache(); return 0; }
/* it is a supposely cleaner and faster implementation than original OpenCV (ccv_canny_deprecated, * removed, since the newer implementation achieve bit accuracy with OpenCV's), after a lot * profiling, the current implementation still uses integer to speed up */ void ccv_canny(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type, int size, double low_thresh, double high_thresh) { assert(a->type & CCV_C1); ccv_declare_matrix_signature(sig, a->sig != 0, ccv_sign_with_format(64, "ccv_canny(%d,%lf,%lf)", size, low_thresh, high_thresh), a->sig, 0); type = (type == 0) ? CCV_8U | CCV_C1 : CCV_GET_DATA_TYPE(type) | CCV_C1; ccv_dense_matrix_t* db = *b = ccv_dense_matrix_renew(*b, a->rows, a->cols, CCV_C1 | CCV_ALL_DATA_TYPE, type, sig); ccv_matrix_return_if_cached(, db); if ((a->type & CCV_8U) || (a->type & CCV_32S)) { ccv_dense_matrix_t* dx = 0; ccv_dense_matrix_t* dy = 0; ccv_sobel(a, &dx, 0, size, 0); ccv_sobel(a, &dy, 0, 0, size); /* special case, all integer */ int low = (int)(low_thresh + 0.5); int high = (int)(high_thresh + 0.5); int* dxi = dx->data.i32; int* dyi = dy->data.i32; int i, j; int* mbuf = (int*)alloca(3 * (a->cols + 2) * sizeof(int)); memset(mbuf, 0, 3 * (a->cols + 2) * sizeof(int)); int* rows[3]; rows[0] = mbuf + 1; rows[1] = mbuf + (a->cols + 2) + 1; rows[2] = mbuf + 2 * (a->cols + 2) + 1; for (j = 0; j < a->cols; j++) rows[1][j] = abs(dxi[j]) + abs(dyi[j]); dxi += a->cols; dyi += a->cols; int* map = (int*)ccmalloc(sizeof(int) * (a->rows + 2) * (a->cols + 2)); memset(map, 0, sizeof(int) * (a->cols + 2)); int* map_ptr = map + a->cols + 2 + 1; int map_cols = a->cols + 2; int** stack = (int**)ccmalloc(sizeof(int*) * a->rows * a->cols); int** stack_top = stack; int** stack_bottom = stack; for (i = 1; i <= a->rows; i++) { /* the if clause should be unswitched automatically, no need to manually do so */ if (i == a->rows) memset(rows[2], 0, sizeof(int) * a->cols); else for (j = 0; j < a->cols; j++) rows[2][j] = abs(dxi[j]) + abs(dyi[j]); int* _dx = dxi - a->cols; int* _dy = dyi - a->cols; map_ptr[-1] = 0; int suppress = 0; for (j = 0; j < a->cols; j++) { int f = rows[1][j]; if (f > low) { int x = abs(_dx[j]); int y = abs(_dy[j]); int s = _dx[j] ^ _dy[j]; /* x * tan(22.5) */ int tg22x = x * (int)(0.4142135623730950488016887242097 * (1 << 15) + 0.5); /* x * tan(67.5) == 2 * x + x * tan(22.5) */ int tg67x = tg22x + ((x + x) << 15); y <<= 15; /* it is a little different from the Canny original paper because we adopted the coordinate system of * top-left corner as origin. Thus, the derivative of y convolved with matrix: * |-1 -2 -1| * | 0 0 0| * | 1 2 1| * actually is the reverse of real y. Thus, the computed angle will be mirrored around x-axis. * In this case, when angle is -45 (135), we compare with north-east and south-west, and for 45, * we compare with north-west and south-east (in traditional coordinate system sense, the same if we * adopt top-left corner as origin for "north", "south", "east", "west" accordingly) */ #define high_block \ { \ if (f > high && !suppress && map_ptr[j - map_cols] != 2) \ { \ map_ptr[j] = 2; \ suppress = 1; \ *(stack_top++) = map_ptr + j; \ } else { \ map_ptr[j] = 1; \ } \ continue; \ } /* sometimes, we end up with same f in integer domain, for that case, we will take the first occurrence * suppressing the second with flag */ if (y < tg22x) { if (f > rows[1][j - 1] && f >= rows[1][j + 1]) high_block; } else if (y > tg67x) { if (f > rows[0][j] && f >= rows[2][j]) high_block; } else { s = s < 0 ? -1 : 1; if (f > rows[0][j - s] && f > rows[2][j + s]) high_block; } #undef high_block } map_ptr[j] = 0; suppress = 0; } map_ptr[a->cols] = 0; map_ptr += map_cols; dxi += a->cols; dyi += a->cols; int* row = rows[0]; rows[0] = rows[1]; rows[1] = rows[2]; rows[2] = row; } memset(map_ptr - map_cols - 1, 0, sizeof(int) * (a->cols + 2)); int dr[] = {-1, 1, -map_cols - 1, -map_cols, -map_cols + 1, map_cols - 1, map_cols, map_cols + 1}; while (stack_top > stack_bottom) { map_ptr = *(--stack_top); for (i = 0; i < 8; i++) if (map_ptr[dr[i]] == 1) { map_ptr[dr[i]] = 2; *(stack_top++) = map_ptr + dr[i]; } } map_ptr = map + map_cols + 1; unsigned char* b_ptr = db->data.u8; #define for_block(_, _for_set) \ for (i = 0; i < a->rows; i++) \ { \ for (j = 0; j < a->cols; j++) \ _for_set(b_ptr, j, (map_ptr[j] == 2), 0); \ map_ptr += map_cols; \ b_ptr += db->step; \ } ccv_matrix_setter(db->type, for_block); #undef for_block ccfree(stack); ccfree(map); ccv_matrix_free(dx); ccv_matrix_free(dy); } else { /* general case, use all ccv facilities to deal with it */ ccv_dense_matrix_t* mg = 0; ccv_dense_matrix_t* ag = 0; ccv_gradient(a, &ag, 0, &mg, 0, size, size); ccv_matrix_free(ag); ccv_matrix_free(mg); /* FIXME: Canny implementation for general case */ } }