/** * internal help method to find the k nearest neighbors */ void spKNNSearch(SPPoint queryFeature, const SPKDTreeNode node, SPBPQueue q){ SPListElement element; int index, distance; bool distanceFlag = false; if(!node){ return; } if(node->dim==INVALID){ //** this is a leaf **// index = spPointGetIndex(node->data); distance = spPointL2SquaredDistance(queryFeature, node->data); element = spListElementCreate(index, distance); spBPQueueEnqueue(q, element); spListElementDestroy(element); return; } //** go to the left sub tree **// if(spPointGetAxisCoor(queryFeature, node->dim)<= node->val){ spKNNSearch(queryFeature, node->left, q); distance = pow((spPointGetAxisCoor(queryFeature, node->dim) - node->val),2); distanceFlag = distance < spBPQueueMaxValue(q); if(!spBPQueueIsFull(q) || distanceFlag){ spKNNSearch(queryFeature, node->right, q); } }else{ spKNNSearch(queryFeature, node->right, q); distance = pow((spPointGetAxisCoor(queryFeature, node->dim) - node->val),2); distanceFlag = distance < spBPQueueMaxValue(q); if(!spBPQueueIsFull(q) || distanceFlag){ spKNNSearch(queryFeature, node->left, q); } } return; }
void SPKDTreeKNNRecursive(SPKDTreeNode treeNode, SPPoint p, SPBPQueue bpq, SP_KDTREE_MSG* msg) { SPListElement listElement; SPPoint treePoint; bool searchedLeft; double dist; if(bpq == NULL || treeNode == NULL) { *msg = SP_KDTREE_INVALID_ARGUMENT; return; } // If treeNode is a leaf if(treeNode->left == NULL && treeNode->right == NULL) { treePoint = *(treeNode->data); listElement = spListElementCreate(spPointGetIndex(treePoint), spPointL2SquaredDistance(p, treePoint)); spBPQueueEnqueue(bpq, listElement); spListElementDestroy(listElement); *msg = SP_KDTREE_SUCCESS; return; } // Turn to search the tree that would've contain the point p (if it was in the tree) if(spPointGetAxisCoor(p, treeNode->dim) <= treeNode->val) { searchedLeft = true; SPKDTreeKNNRecursive(treeNode->left, p, bpq, msg); if (*msg != SP_KDTREE_SUCCESS) return; } else { searchedLeft = false; SPKDTreeKNNRecursive(treeNode->right, p, bpq, msg); if (*msg != SP_KDTREE_SUCCESS) return; } // dist = |treeNode.val - p[treeNode.dim]| dist = treeNode->val - spPointGetAxisCoor(p, treeNode->dim); if(dist < 0) dist *= -1; //dist *= dist; if(!spBPQueueIsFull(bpq) || dist < spBPQueueMaxValue(bpq)) { if(searchedLeft) SPKDTreeKNNRecursive(treeNode->right, p, bpq, msg); else SPKDTreeKNNRecursive(treeNode->left, p, bpq, msg); } }
bool pointGettersTest() { double data1[3] = { 1.0, 1.0, 2.0 }; int dim1 = 3; int index1 = 1; SPPoint p = spPointCreate((double *)data1, dim1, index1); ASSERT_TRUE(spPointGetAxisCoor(p, 0) == 1.0); ASSERT_TRUE(spPointGetAxisCoor(p, 1) == 1.0); ASSERT_FALSE(spPointGetAxisCoor(p, 2) == 1.0); ASSERT_TRUE(spPointGetAxisCoor(p, 2) == 2.0); ASSERT_TRUE(spPointGetIndex(p) == 1); ASSERT_TRUE(spPointGetDimension(p) == 3); spPointDestroy(p); return true; }
// Comparator for aforementioned sorting int SPSortingHelperCompare(const void* t1, const void* t2) { SPSortingHelper *s1, *s2; assert(t1 != NULL && t2 != NULL); s1 = (SPSortingHelper*) t1; s2 = (SPSortingHelper*) t2; if (spPointGetAxisCoor((*s1)->point, (*s1)->dim) == spPointGetAxisCoor((*s2)->point, (*s2)->dim)) { return spPointGetIndex((*s1)->point) - spPointGetIndex((*s2)->point); } else if (spPointGetAxisCoor((*s1)->point, (*s1)->dim) > spPointGetAxisCoor((*s2)->point, (*s2)->dim)) { return 1; } return -1; }
//Checks if copy Works bool pointBasicCopyTest() { double data[2] = { 1.0, 1.0 }; int dim = 2; int index = 1; SPPoint p = spPointCreate(data, dim, index); SPPoint q = spPointCopy(p); ASSERT_TRUE(spPointGetIndex(p) == spPointGetIndex(q)); ASSERT_TRUE(spPointGetDimension(p) == spPointGetDimension(q)); int i; for (i = 0; i < spPointGetDimension(p); i++) { ASSERT_TRUE(spPointGetAxisCoor(p, i) == spPointGetAxisCoor(q, i)); } spPointDestroy(p); spPointDestroy(q); return true; }
int spFeatureCreateFeatureFile(SPPoint* pointArray, const char* filename, int numOfImages,int numOfFeatures, int numOfDim){ FILE *featureFile = NULL; int i,j; char errorMsg[1025]; spLoggerPrintInfo("Creating features file..."); if(filename == NULL){ spLoggerPrintError("filename is NULL", "main.cpp", "main", 182);//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! return 1; //ERROR } //Opening the file featureFile = fopen(filename,"w"); if (featureFile == NULL){ sprintf(errorMsg, "The features file %s couldn’t be open", filename); spLoggerPrintError(errorMsg, "SPFeaturesFiles.c", "spFeatureCreateFeatureFile", 14); return 1; //ERROR } //Writing the file //First line - 1- number of images 2- overall number of features 3- number of dimensions of the features fprintf(featureFile,"%d;;%d;;%d\n",numOfImages,numOfFeatures,numOfDim); for (i = 0; i < numOfFeatures; ++i) { //Feature line - First the matching index of the img and the each coordinate fprintf(featureFile,"%d;;",spPointGetIndex(pointArray[i])); for (j = 0; j < numOfDim; ++j) { fprintf(featureFile,"%f;;",spPointGetAxisCoor(pointArray[i],j)); } fprintf(featureFile, "\n"); } spLoggerPrintInfo("Done creating features file"); fclose(featureFile); return 0; }
/** * Given a kd-tree and a point p, the function stores the nearest neighbors of p to bpq * * @param curr - the kd-tree containing the points * @param bpq - the bounded priority queue to store the nearest neighbors in * @param p - the point to find the nearest neighbors to * * does nothing if curr == NULL or bpq == NULL or p == NULL */ void nearestNeighbors(KDTreeNode curr, SPBPQueue bpq, SPPoint p) { SPListElement node; SPPoint q; bool isLeft; double coorDis; if (curr == NULL || bpq == NULL || p == NULL ) return; q = curr->data; /* Add the current point to the BPQ. Note that this is a no-op if the * point is not as good as the points we've seen so far.*/ if (curr->dim == -1) { int index; double dis; index = spPointGetIndex(q); dis = spPointL2SquaredDistance(p, curr->data); node = spListElementCreate(index, dis); spBPQueueEnqueue(bpq, node); spListElementDestroy(node); return; } /* Recursively search the half of the tree that contains the test point. */ if (spPointGetAxisCoor(p, curr->dim) <= curr->val) { nearestNeighbors(curr->left, bpq, p); isLeft = true; } else { nearestNeighbors(curr->right, bpq, p); isLeft = false; } /* If the candidate hypersphere crosses this splitting plane, look on the * other side of the plane by examining the other subtree*/ coorDis = abs(spPointGetAxisCoor(p, curr->dim) - curr->val); if (!spBPQueueIsFull(bpq) || coorDis*coorDis < spBPQueueMaxValue(bpq)) { if (isLeft) nearestNeighbors(curr->right, bpq, p); else nearestNeighbors(curr->left, bpq, p); } }
double spPointL2SquaredDistance(SPPoint p, SPPoint q){ double sum = 0.0; // Holds temporary sum double pVal; // holds current p_i value double qVal; // holds current q_i value double pqSub; // holds current p_i-q_i value int dim; // dim of p and q int i; assert(p!=NULL && q!=NULL && p->dim == q->dim); dim = p->dim; for (i=0; i<dim; i++){ pVal = spPointGetAxisCoor(p, i); // get current p_i value qVal = spPointGetAxisCoor(q, i); // get current q_i value pqSub = pVal-qVal; sum += (pqSub*pqSub); } return sum; }
/** * prints the tree for debuging */ void printTree(KDTreeNode kdTree) { int i; if (kdTree == NULL ) { return; } printf(" ("); printTree(kdTree->left); if (kdTree->data == NULL ) printf("dim: %d, val: %f", kdTree->dim, kdTree->val); else { printf("index: %d,point: ", spPointGetIndex(kdTree->data)); for (i = 0; i < spPointGetDimension(kdTree->data); i++) { printf("%lf,", spPointGetAxisCoor(kdTree->data, i)); } } printTree(kdTree->right); printf(" )"); }
SP_CONFIG_MSG writeImageFeaturesToFile(SPPoint* imFeatures, int numOfFeats, SPConfig config, int imageIndex) { FILE* featsFile; SP_CONFIG_MSG msg = getFeatsFile(config, imageIndex, &featsFile, "w+"); int i, j; if (msg != SP_CONFIG_SUCCESS) { return msg; } fprintf(featsFile, "%d\n", numOfFeats); for (i = 0; i < numOfFeats; i++) { SPPoint point = imFeatures[i]; fprintf(featsFile, "%d,%d\n", spPointGetIndex(point), spPointGetDimension(point)); for (j = 0; j < spPointGetDimension(point); j++) { fprintf(featsFile, "%f\n", spPointGetAxisCoor(point, j)); } } fflush(featsFile); fclose(featsFile); return SP_CONFIG_SUCCESS; }
/** * A recursive function to construct the kd-tree */ KDTreeNode constructTree(KDArray mat, int size, int dim, int splitMethod, int lastLevelDim) { KDTreeNode newNode; KDArray left, right; SPPoint* p; int splitDim = -1; double medianVal; assert(size > 0); p = kdArrayGetPoints(mat); newNode = (KDTreeNode) malloc(sizeof(*newNode)); if (newNode == NULL ) { spLoggerPrintError(ALLOC_ERROR_MSG, __FILE__, __func__, __LINE__); return NULL ; } if (size == 1) { // creates a new leaf which represents a point newNode->dim = -1; newNode->val = -1; newNode->left = NULL; newNode->right = NULL; newNode->data = spPointCopy(p[0]); return newNode; } if (splitMethod == 0) { // RANDOM srand(time(NULL )); splitDim = rand() % dim; } else if (splitMethod == 1) { // MAX SPREAD double maxSpread; int i; maxSpread = 0; for (i = 0; i < dim; i++) { int minIndex, maxIndex; double spread; minIndex = kdArrayGet(mat, i, 0); maxIndex = kdArrayGet(mat, i, size - 1); spread = spPointGetAxisCoor(p[maxIndex], i) - spPointGetAxisCoor(p[minIndex], i); if (spread >= maxSpread) { maxSpread = spread; splitDim = i; } } } else if (splitMethod == 2) { // INCREMENTAL splitDim = (lastLevelDim + 1) % dim; } left = kdArrayInitEmpty(); if (left == NULL ) return NULL ; right = kdArrayInitEmpty(); if (right == NULL ) { kdArrayDestroy(left); return NULL ; } // compute the median to split according to it medianVal = spPointGetAxisCoor(p[kdArrayGet(mat, splitDim, (size - 1) / 2)], splitDim); kdArraySplit(mat, splitDim, left, right); newNode->dim = splitDim; newNode->val = medianVal; // recursively create the left sub-tree newNode->left = constructTree(left, kdArrayGetSize(left), dim, splitMethod, splitDim); // recursively create the right sub-tree newNode->right = constructTree(right, kdArrayGetSize(right), dim, splitMethod, splitDim); newNode->data = NULL; // not a leaf // free data not needed anymore kdArrayDestroy(left); kdArrayDestroy(right); return newNode; }
SPKDArray Init(SPPoint* arr, int size){ SPKDArray KDArray; int d; // d = the dimension of the points (assuming dimension is the same for all points) double** index_val_arr; //double array containing n rows. each row contains the index and the value of a specific coordinate in the point of that index int i,j; int malloc_result; // holds the result of the call to mallocForNewKdArray //check validation of the parameters if (size<1){ spLoggerPrintError(INVALID_ARG_ERROR, __FILE__, __func__, __LINE__); spLoggerPrintDebug(PARAMETER_SIZE_INVALID, __FILE__, __func__, __LINE__); return NULL; } if (arr==NULL){ spLoggerPrintError(INVALID_ARG_ERROR, __FILE__, __func__, __LINE__); spLoggerPrintDebug(PARAMETER_ARR_INVALID, __FILE__, __func__, __LINE__); return NULL; } //initialize d d = spPointGetDimension(arr[0]); // allocate memory for KDArray and its fields malloc_result = mallocForNewKdArray(&KDArray, size, d); if (malloc_result==-1){ // the memory freeing would already be done inside mallocForInitKdArray return NULL; } //copy each point from arr to KDArray->array_of_points for (i=0; i<size; i++){ KDArray->array_of_points[i] = spPointCopy(arr[i]); //spPointCopy returns NULL if an allocation error occurred if (KDArray->array_of_points[i] == NULL){ spLoggerPrintError(GENERAL_ERROR_MSG, __FILE__, __func__, __LINE__); spLoggerPrintDebug(SPPOINTCOPY_RETURNED_NULL, __FILE__, __func__, __LINE__); destroyKDArray(KDArray); return NULL; } } //allocate memory for index_val_arr: n rows, 2 columns if ( (index_val_arr = (double**)malloc(size*sizeof(double*))) == NULL){ spLoggerPrintError(ALLOC_ERROR_MSG, __FILE__, __func__, __LINE__); destroyKDArray(KDArray); return NULL; } for (i=0; i<size; i++){ if( (index_val_arr[i]=(double*)malloc(2*sizeof(double))) == NULL){ spLoggerPrintError(ALLOC_ERROR_MSG, __FILE__, __func__, __LINE__); for (j=0; j<i; j++){ free(index_val_arr[j]); } free(index_val_arr); destroyKDArray(KDArray); return NULL; } } // for each coordinate for (i=0; i<d; i++){ // i=coordinate // fill index and value of coordinate to val_index_arr for (j=0; j<size; j++){ //j=index of point index_val_arr[j][0] = (double)j; index_val_arr[j][1] = spPointGetAxisCoor(arr[j],i); } /* sort the rows in index_val_arr by the value in the second column, * meaning by the value of the coordinate of each point. * the first column will be the indexes of the points sorted by the values of the coordinate */ qsort(index_val_arr, size, sizeof(index_val_arr[0]), copmareByValue); // fill the sorted indexes in to KDArray->Array for (j=0; j<size; j++){ //j=index of point KDArray->matrix_of_sorted_indexes[i][j] = (int)index_val_arr[j][0]; } } // initialize n and d KDArray->n = size; KDArray->d = d; for (j=0; j<size; j++){ free(index_val_arr[j]); } free(index_val_arr); return KDArray; }
SPKDTreeNode SPKDTreeInitHelp(SPKDArray kdArr, int size, SP_KDTREE_SPLIT_METHOD splitMethod, int lastIndex, SP_KDTREE_MSG * msg) { int dim, dims, maxSpread, maxSpreadIndex, spread, i, minVal, maxVal; SP_KDARRAY_MSG kdArrMsg; SPKDArray* split; SPKDTreeNode ret; SPPoint workPoint; assert(msg != NULL); if (kdArr == NULL || size <= 0 || lastIndex < -1) { *msg = SP_KDTREE_INVALID_ARGUMENT; return NULL; } // Allocate memory ret = (SPKDTreeNode)malloc(sizeof(*ret)); if (ret == NULL) { *msg = SP_KDTREE_ALLOC_FAIL; return NULL; } if (size == 1) { // Returned node will be a leaf ret->dim = -1; ret->val = -1.0; ret->left = (ret->right = NULL); ret->data = (SPPoint*)malloc(sizeof(SPPoint)); if (ret->data == NULL) { *msg = SP_KDTREE_ALLOC_FAIL; free(ret); return NULL; } *(ret->data) = SPKDArrayGetPointByDim(kdArr, 0, -1, &kdArrMsg); // Gets the only point in the KD-Array } else { // Returned node is not a leaf dims = SPKDArrayGetDims(kdArr, &kdArrMsg); // Calculate the splitting dimension switch (splitMethod) { case SP_KDTREE_MAX_SPREAD: maxSpread = 0; maxSpreadIndex = 0; // calculate the maximum spread dimension for (i = 0; i < dims; i++) { workPoint = SPKDArrayGetPointByDim(kdArr, 0, i, &kdArrMsg); minVal = spPointGetAxisCoor(workPoint, i); spPointDestroy(workPoint); workPoint = SPKDArrayGetPointByDim(kdArr, size - 1, i, &kdArrMsg); maxVal = spPointGetAxisCoor(workPoint, i); spPointDestroy(workPoint); spread = maxVal - minVal; if (spread > maxSpread) { maxSpread = spread; maxSpreadIndex = i; } } dim = maxSpreadIndex; break; case SP_KDTREE_RANDOM: dim = rand() % dims; break; case SP_KDTREE_INCREMENTAL: dim = (lastIndex + 1) % dims; break; } split = SPKDArraySplit(kdArr, dim, &kdArrMsg); // Split the KD-Array according to the splitting dimension workPoint = SPKDArrayGetPointByDim(split[0], SPKDArrayGetSize(split[0], &kdArrMsg) - 1, dim, &kdArrMsg); ret->dim = dim; ret->val = spPointGetAxisCoor(workPoint, dim); // Employ recursion to calculate subtrees ret->left = SPKDTreeInitHelp(split[0], SPKDArrayGetSize(split[0], &kdArrMsg), splitMethod, lastIndex + 1, msg); ret->right = SPKDTreeInitHelp(split[1], SPKDArrayGetSize(split[1], &kdArrMsg), splitMethod, lastIndex + 1, msg); ret->data = NULL; // Get rid of unneeded memory SPKDArrayDestroy(split[0]); SPKDArrayDestroy(split[1]); free(split); spPointDestroy(workPoint); } // All done *msg = SP_KDTREE_SUCCESS; return ret; }
/**** * The purpose of the test is to compare the features before and after the saving. */ bool main_saveLoad() { LoadedFeatures loadedFeatures = NULL; LoadedFeatures features = NULL; int numOfImages = 0; int numOfFeatures = 0; int numOfCoords = 0; SPPoint * orgArr = NULL; SPPoint pointOrg = NULL; SPPoint * loadedArr = NULL; SPPoint pointLoad = NULL; SP_CONFIG_MSG msg; char fileName[30] = "./tests/config/saveLoad.cfg"; SPConfig conf = spConfigCreate(fileName, &msg); ASSERT_TRUE(NULL != conf); /**** * Allocates, creates(by imageProc) and saves the features ****/ features = allocateFeaturesList(conf); ASSERT_TRUE(NULL != features); ASSERT_TRUE(true == debugSaveFeatures(conf, features)); /**** * Load the features from the files *****/ loadedFeatures = allocateFeaturesList(conf); ASSERT_TRUE(NULL != loadedFeatures); ASSERT_TRUE(true == loadFeatures(conf, loadedFeatures)); /**************************************** * Compare original and loaded features * ****************************************/ ASSERT_TRUE(getFeaturesImagesNumber(features) == getFeaturesImagesNumber(loadedFeatures)); numOfImages = getFeaturesImagesNumber(features); for (int index_image=0; index_image<numOfImages ; index_image++) { numOfFeatures = getFeaturesNumber(features, index_image); ASSERT_TRUE(numOfFeatures == getFeaturesNumber(loadedFeatures, index_image)); for (int index_feature=0; index_feature<numOfFeatures ; index_feature++) { orgArr = getFeatureArray(features, index_image); loadedArr = getFeatureArray(loadedFeatures, index_image); pointOrg = orgArr[index_feature]; pointLoad = loadedArr[index_feature]; numOfCoords = spPointGetDimension(pointOrg); ASSERT_TRUE(numOfCoords == spPointGetDimension(pointLoad)); ASSERT_TRUE(spPointGetIndex(pointOrg) == spPointGetIndex(pointLoad)); for (int index_coor=0; index_coor<numOfCoords ; index_coor++) { ASSERT_TRUE(spPointGetAxisCoor(pointOrg, index_coor) == spPointGetAxisCoor(pointLoad, index_coor)); } } } loadedFeaturesDestroy(loadedFeatures); loadedFeaturesDestroy(features); return true; }