home *** CD-ROM | disk | FTP | other *** search
- /*
- ** xknn.c
- **
- ** Practical Algorithms for Image Analysis
- **
- ** Copyright (c) 1997 ????
- */
-
- /*
- ** XKNN(K-Nearest Neighbors)
- **
- ** test knn.c module
- **
- */
-
- #include "xknn.h"
-
- #define BUFSZ 1024
- extern short tiffInput; /* flag=0 if no ImageIn to set tags; else =1 */
-
- /*
- * Globals
- */
-
- int maxX;
- int maxY;
- int minX;
- int minY;
- int npoints;
-
- /*
- * usage of routine
- */
- void
- usage (char *progname)
- {
- progname = last_bs (progname);
- printf ("\nusage:\n");
- printf ("%s nearnbr input_points output_image [-l]\n", progname);
- printf (" nearnbr - number of nearest neighbors to calculate (int)\n");
- printf (" input_points - input file with list of (x,y) pairs\n");
- printf (" output_image - output image filename (TIFF format)\n");
- printf ("\noptions:\n");
- printf (" -l prints (x,y) point with neighbor list");
- exit (1);
- }
-
- struct Point *
- readPoints(char *filename, int nknn)
- {
- FILE *stream;
- struct Point *pointStruct, *p;
- int line_no, i, got_first_point;
- char inBuf[BUFSZ];
-
- line_no = 0;
- got_first_point = 0;
- if( (stream = fopen( filename, "r" )) != NULL ) {
- for(;;) {
- line_no++;
- if(fgets(inBuf, BUFSZ, stream) == (char *)NULL) {
- printf("Premature EOF encountered on line %d while reading points file %s\n", line_no, filename);
- exit(1);
- }
- /*
- * Throw away comments
- */
- if(inBuf[0] == '#')
- continue;
- else {
- if( sscanf( inBuf, "%d \n", &npoints ) != 1) {
- printf( "error getting number of points\n" );
- exit(1);
- }
- if( (pointStruct = (struct Point *)calloc(npoints, sizeof(struct Point)) ) == NULL) {
- printf("\n...mem allocation for retMatrix failed\n");
- exit(1);
- }
- break;
- }
- }
- /*
- ** Now read the (x,y) points in
- */
- i =0;
- p = pointStruct;
- for(;;) {
- line_no++;
- if(fgets(inBuf, BUFSZ, stream) == (char *)NULL) {
- printf("Premature EOF encountered on line %d while reading points file %s\n", line_no, filename);
- exit(1);
- }
- /*
- * Throw away comments
- */
- if(inBuf[0] == '#')
- continue;
- if( sscanf( inBuf, "%d %d\n", &(p->x_pos), &(p->y_pos) ) == 2) {
- if(!got_first_point) {
- maxX = p->x_pos;
- minX = p->x_pos;
- maxY = p->y_pos;
- minY = p->y_pos;
- got_first_point = 1;
- }
- else {
- maxX = (p->x_pos > maxX) ? p->x_pos : maxX;
- minX = (p->x_pos < minX) ? p->x_pos : minX;
- maxY = (p->y_pos > maxY) ? p->y_pos : maxY;
- minY = (p->y_pos < minY) ? p->y_pos : minY;
- }
- if( (p->Knn = (struct KNN *)calloc(nknn, sizeof(struct KNN)) ) == NULL) {
- printf("\n...mem allocation for Knn struct failed\n");
- exit(1);
- }
- p++;
- i++;
- if(i >= npoints)
- break;
- }
- else {
- printf( "error getting (x,y) value on line %d of file %s\n", line_no, filename);
- fclose( stream );
- exit(1);
- }
- }
- fclose( stream );
- return(pointStruct);
- }
- else {
- printf("Can not open points file: %s\n", filename);
- exit(1);
- }
- }
-
- /*
- * qsort comparison function for x-direction
- */
-
- int
- sortX(p1, p2)
- struct Point *p1;
- struct Point *p2;
- {
- if(p1->x_pos == p2->x_pos)
- return(0);
- else
- return((p1->x_pos < p2->x_pos) ? -1 : 1);
- }
-
- /*
- * qsort comparison function for y-direction
- */
-
- int
- sortY(p1, p2)
- struct Point *p1;
- struct Point *p2;
- {
- if(p1->y_pos == p2->y_pos)
- return(0);
- else
- return((p1->y_pos < p2->y_pos) ? -1 : 1);
- }
-
- /*
- * find_knn()
- * finds k-nearest neighbors for point array
- * if maxRange = 0, array is sorted in x-direction, otherwise y-direction
- */
-
- void
- find_knn(struct Point *points, int npoints, int knn, int maxRange)
- {
- int i, j;
- long xDist, yDist, distSqd;
- struct Point *p1, *p2;
-
- /* outer loop through all points */
- for(i = 0, p1 = points; i < npoints; i++, p1++) {
- for(j = i + 1, p2 = p1 + 1; j < npoints; j++, p2++) {
- xDist = p2->x_pos - p1->x_pos;
- yDist = p2->y_pos - p1->y_pos;
- distSqd = xDist * xDist + yDist * yDist;
- if(!maxRange && (xDist * xDist > p1->Knn[knn].distSqd))
- break;
- if(maxRange && (yDist * yDist > p1->Knn[knn].distSqd))
- break;
- insertNN(p1, p2, distSqd, knn);
- insertNN(p2, p1, distSqd, knn);
- }
- }
- }
-
- /*
- * insertNN()
- * p2 is inserted into p1's knn list if the
- * distance is less than any of the distances
- * currently in p1's knn list
- * RETURN VALUE:
- * 1 if p2 was inserted
- * 0 otherwise
- */
-
- int
- insertNN(struct Point *p1, struct Point *p2, long distSqd, int knn)
- {
- int i, j;
- int nnInsert = 0;
- struct KNN *pk;
-
- pk = p1->Knn;
- for(i = 0; i < knn; i++) {
- if(distSqd < pk[i].distSqd) {
- for(j = knn - 1; j > i; --j)
- pk[j] = pk[j-1];
- pk[i].x_pos = p2->x_pos;
- pk[i].y_pos = p2->y_pos;
- pk[i].distSqd = distSqd;
- if(p1->nNN < knn)
- p1->nNN++;
- nnInsert = 1;
- break;
- }
- }
- if(!nnInsert && p1->nNN < knn) {
- pk[p1->nNN].x_pos = p2->x_pos;
- pk[p1->nNN].y_pos = p2->y_pos;
- pk[p1->nNN].distSqd = distSqd;
- p1->nNN++;
- nnInsert = 1;
- }
- return(nnInsert);
- }
-
-
- /*
- * main() for xsgll
- */
-
- int
- main(int argc, char *argv[])
- {
-
- Image *imgOut;
- struct Point *points;
- struct Point *p;
- int rangeX;
- int rangeY;
- int maxRange;
- int knn;
- int i, j;
-
- if( argc < 4 )
- usage(argv[0]);
-
- if( sscanf( argv[1], "%d", &knn) != 1) {
- printf("Error getting value for nearnbr\n");
- usage(argv[0]);
- }
-
- /* reset tiffInput so that we write a grayscale file (i.e tags are not copied) */
- tiffInput = 0;
-
- /*
- ** Read in points
- */
- points = readPoints(argv[2], knn);
- /* determine the maximum range of values, whether over x or y */
- rangeX = maxX - minX;
- rangeY = maxY - minY;
- maxRange = (rangeX > rangeY) ? 0: 1; /* 0 or 1 for max X or Y range */
- /* order elements along x or y axes, whichever is maxRange */
- if (maxRange == 0)
- #if defined(LINUX)
- qsort(points, (size_t)npoints, sizeof(struct Point), (__compar_fn_t)sortX);
- else
- qsort(points, (size_t)npoints, sizeof(struct Point), (__compar_fn_t)sortY);
- #else
- qsort(points, (size_t)npoints, sizeof(struct Point), sortX);
- else
- qsort(points, (size_t)npoints, sizeof(struct Point), sortY);
- #endif
-
- /*
- ** Allocate memory for output image
- */
- imgOut = ImageAlloc((long)maxY + 10, (long)maxX + 10, (long)BPS);
-
- printf("Sorted array is:\n");
- for(i = 0, p = points; i < npoints; i++, p++)
- printf("Point %d = (%d, %d)\n", i, p->x_pos, p->y_pos);
-
- /*
- ** Find the nearest neighbors for all points
- */
- find_knn(points, npoints, knn, maxRange);
-
- /*
- ** Plot the lines
- */
- for(i = 0, p = points; i < npoints; i++, p++) {
- draw_cross(p->x_pos, p->y_pos, 10, imgOut, WHITE);
- printf("Nearest neighbors for Point %d = (%d, %d)\n", i, p->x_pos, p->y_pos);
- for(j = 0; j < p->nNN; j++) {
- printf("\t(%d, %d)\n", p->Knn[j].x_pos, p->Knn[j].y_pos);
- draw_line(p->x_pos, p->y_pos, p->Knn[j].x_pos, p->Knn[j].y_pos, imgOut, WHITE);
- }
- }
- /*
- ** Write the output image
- */
- ImageOut (argv[3], imgOut);
- return(1);
- }
-
-