static VlHIKMNode * xmeans (VlHIKMTree *tree, vl_uint8 const *data, int N, int K, int height) { VlHIKMNode *node = vl_malloc (sizeof(VlHIKMNode)) ; vl_uint *ids = vl_malloc (sizeof(vl_uint) * N) ; node-> filter = vl_ikm_new (tree -> method) ; node-> children = (height == 1) ? 0 : vl_malloc (sizeof(VlHIKMNode*) * K) ; vl_ikm_set_max_niters (node->filter, tree->max_niters) ; vl_ikm_set_verbosity (node->filter, tree->verb - 1 ) ; vl_ikm_init_rand_data (node->filter, data, tree->M, N, K) ; vl_ikm_train (node->filter, data, N) ; vl_ikm_push (node->filter, ids, data, N) ; /* recurse for each child */ if (height > 1) { int k ; for (k = 0 ; k < K ; k ++) { int partition_N ; int partition_K ; vl_uint8 *partition ; partition = vl_hikm_copy_subset (data, ids, N, tree->M, k, &partition_N) ; partition_K = VL_MIN (K, partition_N) ; node->children [k] = xmeans (tree, partition, partition_N, partition_K, height - 1) ; vl_free (partition) ; if (tree->verb > tree->depth - height) { VL_PRINTF("hikmeans: branch at depth %d: %6.1f %% completed\n", tree->depth - height, (double) (k+1) / K * 100) ; } } } vl_free (ids) ; return node ; }
/* driver */ void mexFunction (int nout, mxArray * out[], int nin, const mxArray * in[]) { enum {IN_X = 0, IN_K, IN_END} ; enum {OUT_C = 0, OUT_I} ; int opt ; int next = IN_END ; mxArray const *optarg ; int M, N, K = 0 ; int err = 0 ; vl_uint *asgn = 0 ; vl_ikm_acc *centers = 0 ; vl_uint8 *data ; int method_type = VL_IKM_LLOYD ; int max_niters = 200 ; int verb = 0 ; VlIKMFilt *ikmf ; VL_USE_MATLAB_ENV ; /* ------------------------------------------------------------------ * Check the arguments * --------------------------------------------------------------- */ if (nin < 2) { mexErrMsgTxt ("At least two arguments required."); } else if (nout > 2) { mexErrMsgTxt ("Too many output arguments."); } if (mxGetClassID (in[IN_X]) != mxUINT8_CLASS) { mexErrMsgTxt ("X must be of class uint8"); } M = mxGetM (in[IN_X]); /* n of components */ N = mxGetN (in[IN_X]); /* n of elements */ if (!vlmxIsPlainScalar (in[IN_K]) || (K = (int) *mxGetPr(in[IN_K])) < 1 || K > N ) { mexErrMsgTxt ("K must be a positive integer not greater than the number of data."); } while ((opt = vlmxNextOption (in, nin, options, &next, &optarg)) >= 0) { char buf [1024] ; switch (opt) { case opt_verbose : ++ verb ; break ; case opt_max_niters : if (!vlmxIsPlainScalar(optarg) || (max_niters = (int) *mxGetPr(optarg)) < 1) { mexErrMsgTxt("MaxNiters must be not smaller than 1.") ; } break ; case opt_method : if (!vlmxIsString (optarg, -1)) { mexErrMsgTxt("'Method' must be a string.") ; } if (mxGetString (optarg, buf, sizeof(buf))) { mexErrMsgTxt("Option argument too long.") ; } if (strcmp("lloyd", buf) == 0) { method_type = VL_IKM_LLOYD ; } else if (strcmp("elkan", buf) == 0) { method_type = VL_IKM_ELKAN ; } else { mexErrMsgTxt("Unknown method type.") ; } break ; default : abort() ; } } /* ------------------------------------------------------------------ * Do the job * --------------------------------------------------------------- */ if (verb) { char const * method_name = 0 ; switch (method_type) { case VL_IKM_LLOYD: method_name = "Lloyd" ; break ; case VL_IKM_ELKAN: method_name = "Elkan" ; break ; default : abort() ; } mexPrintf("ikmeans: MaxInters = %d\n", max_niters) ; mexPrintf("ikmeans: Method = %s\n", method_name) ; } data = (vl_uint8*) mxGetPr(in[IN_X]) ; ikmf = vl_ikm_new (method_type) ; vl_ikm_set_verbosity (ikmf, verb) ; vl_ikm_set_max_niters (ikmf, max_niters) ; vl_ikm_init_rand_data (ikmf, data, M, N, K) ; err = vl_ikm_train (ikmf, data, N) ; if (err) mexWarnMsgTxt("ikmeans: possible overflow!") ; /* ------------------------------------------------------------------ * Return results * --------------------------------------------------------------- */ { out[OUT_C] = mxCreateNumericMatrix (M, K, mxINT32_CLASS, mxREAL) ; centers = mxGetData (out[OUT_C]) ; memcpy (centers, vl_ikm_get_centers (ikmf), sizeof(vl_ikm_acc) * M * K) ; } if (nout > 1) { int j ; out[OUT_I] = mxCreateNumericMatrix (1, N, mxUINT32_CLASS, mxREAL) ; asgn = mxGetData (out[OUT_I]) ; vl_ikm_push (ikmf, asgn, data, N) ; for (j = 0 ; j < N ; ++j) ++ asgn [j] ; } vl_ikm_delete (ikmf) ; if (verb) { mexPrintf("ikmeans: done\n") ; } }
void ikm() { const vl_size data_dim = 2; const vl_size num_data = 1000; vl_uint8 data[data_dim * num_data] = { 0, }; for (vl_size i = 0; i < data_dim * num_data; ++i) data[i] = (vl_uint8)std::floor((((float)std::rand() / RAND_MAX) * 255) + 0.5f); // std::cout << "start processing ..." << std::endl; const vl_size num_clusters = 3; const VlIKMAlgorithms algorithm = VL_IKM_LLOYD; // VL_IKM_LLOYD, VL_IKM_ELKAN. const vl_size num_max_iterations = 100; VlIKMFilt *ikm = vl_ikm_new(algorithm); vl_ikm_set_max_niters(ikm, num_max_iterations); // initialization. #if 1 vl_ikm_init_rand(ikm, data_dim, num_clusters); #elif 0 vl_ikm_init_rand_data(ikm, data, data_dim, num_data, num_clusters); #else vl_ikm_acc init_centers[data_dim * num_clusters] = { 0, }; for (vl_size i = 0; i < data_dim * num_clusters; ++i) init_centers[i] = (vl_ikm_acc)std::floor((((float)std::rand() / RAND_MAX) * 255) + 0.5f); vl_ikm_init(ikm, init_centers, data_dim, num_clusters); #endif // training. if (-1 != vl_ikm_train(ikm, data, num_data)) { const vl_ikmacc_t *centers = vl_ikm_get_centers(ikm); for (int i = 0; i < num_clusters; ++i) { std::cout << '('; for (int j = 0; j < data_dim; ++j) { if (j) std::cout << ','; std::cout << (int)centers[i * data_dim + j]; } std::cout << ')' << std::endl; } // { vl_uint assignments[num_data] = { 0, }; vl_ikm_push(ikm, assignments, data, num_data); for (int i = 0; i < num_data; ++i) { std::cout << '('; for (int j = 0; j < data_dim; ++j) { if (j) std::cout << ','; std::cout << (int)data[i * data_dim + j]; // TODO [check] >> is it correct? } std::cout << ") => " << assignments[i] << std::endl; } } // testing. { vl_uint8 test_sample[data_dim] = { 0, }; for (vl_size i = 0; i < data_dim; ++i) test_sample[i] = (vl_uint8)std::floor((((float)std::rand() / RAND_MAX) * 255) + 0.5f); const vl_uint assignment = vl_ikm_push_one(centers, test_sample, data_dim, num_clusters); } } else { std::cerr << "an overflow may have occurred." << std::endl; } std::cout << "end processing ..." << std::endl; // if (ikm) { vl_ikm_delete(ikm); ikm = NULL; } }
PyObject * vl_ikmeans_python( PyArrayObject & inputData, int K, int max_niters, char * method, int verb) { // check types assert(inputData.descr->type_num == PyArray_UBYTE); assert(inputData.flags & NPY_FORTRAN); npy_intp M, N; int err = 0; vl_uint8 * data; VlIKMFilt *ikmf; M = inputData.dimensions[0]; /* n of components */ N = inputData.dimensions[1]; /* n of elements */ // K must be a positive integer not greater than the number of data. assert(K>0 && K<=N); int method_type = VL_IKM_LLOYD; if (strcmp("lloyd", method) == 0) { method_type = VL_IKM_LLOYD; } else if (strcmp("elkan", method) == 0) { method_type = VL_IKM_ELKAN; } else { assert(0); } /* ------------------------------------------------------------------ * Do the job * --------------------------------------------------------------- */ if (verb) { char const * method_name = 0; switch (method_type) { case VL_IKM_LLOYD: method_name = "Lloyd"; break; case VL_IKM_ELKAN: method_name = "Elkan"; break; default: assert (0); } printf("ikmeans: MaxInters = %d\n", max_niters); printf("ikmeans: Method = %s\n", method_name); } data = (vl_uint8*) inputData.data; ikmf = vl_ikm_new(method_type); vl_ikm_set_verbosity(ikmf, verb); vl_ikm_set_max_niters(ikmf, max_niters); vl_ikm_init_rand_data(ikmf, data, M, N, K); err = vl_ikm_train(ikmf, data, N); if (err) printf("ikmeans: possible overflow!"); /* ------------------------------------------------------------------ * Return results * --------------------------------------------------------------- */ // allocate PyArrayObject for centers (column-majored) npy_intp dims[2]; dims[0] = M; dims[1] = K; PyArrayObject * centers = (PyArrayObject*) PyArray_NewFromDescr( &PyArray_Type, PyArray_DescrFromType(PyArray_INT32), 2, dims, NULL, NULL, NPY_F_CONTIGUOUS, NULL); // copy data int * centers_data = (int*) centers->data; memcpy(centers_data, vl_ikm_get_centers(ikmf), sizeof(vl_ikm_acc) * M * K); // allocate PyArrayObject for cluster assignment array PyArrayObject * asgn = (PyArrayObject*) PyArray_SimpleNew( 1, (npy_intp*) &N, PyArray_UINT32); // copy data unsigned int * asgn_data = (unsigned int*) asgn->data; int j; vl_ikm_push(ikmf, (vl_uint*) asgn_data, data, N); // clean vl_ikm_delete(ikmf); if (verb) { printf("ikmeans: done\n"); } // construct tuple to return both results: (regions, frames) PyObject * tuple = PyTuple_New(2); PyTuple_SetItem(tuple, 0, PyArray_Return(centers)); PyTuple_SetItem(tuple, 1, PyArray_Return(asgn)); return tuple; }