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_C,IN_END} ; enum {OUT_ASGN=0} ; vl_uint* asgn ; vl_ikm_acc* centers ; vl_uint8* data ; int M,N,j,K=0 ; int opt ; int next = IN_END ; mxArray const *optarg ; int method_type = VL_IKM_LLOYD ; 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") ; } if(mxGetClassID(in[IN_C]) != mxINT32_CLASS) { mexErrMsgTxt("C must be of class INT32") ; } M = mxGetM(in[IN_X]) ; /* n of components */ N = mxGetN(in[IN_X]) ; /* n of elements */ K = mxGetN(in[IN_C]) ; /* n of centers */ if( (int) mxGetM(in[IN_C]) != M ) { mexErrMsgTxt("DATA and CENTERS must have the same number of columns.") ; } while ((opt = vlmxNextOption (in, nin, options, &next, &optarg)) >= 0) { char buf [1024] ; switch (opt) { case opt_verbose : ++ verb ; 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 cost type.") ; } break ; default : abort() ; } } /** ----------------------------------------------------------------- ** Check the arguments ** -------------------------------------------------------------- */ 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("ikmeanspush: Method = %s\n", method_name) ; mexPrintf("ikmeanspush: ndata = %d\n", N) ; } out[OUT_ASGN] = mxCreateNumericMatrix (1, N, mxUINT32_CLASS, mxREAL) ; data = (vl_uint8*) mxGetData (in[IN_X]) ; centers = (vl_ikm_acc*) mxGetData (in[IN_C]) ; asgn = (vl_uint*) mxGetData (out[OUT_ASGN]) ; ikmf = vl_ikm_new (method_type) ; vl_ikm_set_verbosity (ikmf, verb) ; vl_ikm_init (ikmf, centers, M, K) ; vl_ikm_push (ikmf, asgn, data, N) ; /* adjust for MATLAB indexing */ for(j = 0 ; j < N ; ++j) ++ asgn[j] ; vl_ikm_delete (ikmf) ; }
/* 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") ; } }
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; }
PyObject * vl_ikmeanspush_python( PyArrayObject & inputData, PyArrayObject & centers, char * method, int verb) { // check types assert(inputData.descr->type_num == PyArray_UBYTE); assert(inputData.flags & NPY_FORTRAN); assert(centers.descr->type_num == PyArray_INT32); assert(centers.flags & NPY_FORTRAN); vl_ikm_acc* centers_data = (vl_ikm_acc *) centers.data; vl_uint8 * data = (vl_uint8 *) inputData.data; int j; npy_intp M, N, K = 0; VlIKMFilt *ikmf; /** ----------------------------------------------------------------- ** Check the arguments ** -------------------------------------------------------------- */ M = inputData.dimensions[0]; //mxGetM(in[IN_X]) ; /* n of components */ N = inputData.dimensions[1]; //mxGetN(in[IN_X]) ; /* n of elements */ K = centers.dimensions[1]; //mxGetN(in[IN_C]) ; /* n of centers */ if (centers.dimensions[0] != M) { printf("DATA and CENTERS must have the same number of columns."); } 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); } /** ----------------------------------------------------------------- ** Check the arguments ** -------------------------------------------------------------- */ 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("ikmeanspush: Method = %s\n", method_name); printf("ikmeanspush: ndata = %d\n", (int)N); } PyArrayObject * asgn = (PyArrayObject *) PyArray_SimpleNew( 1, (npy_intp*) &N, PyArray_UINT32); unsigned int * asgn_data = (unsigned int*) asgn->data; ikmf = vl_ikm_new(method_type); vl_ikm_set_verbosity(ikmf, verb); vl_ikm_init(ikmf, centers_data, M, K); vl_ikm_push(ikmf, asgn_data, data, N); vl_ikm_delete(ikmf); return PyArray_Return(asgn); }