home *** CD-ROM | disk | FTP | other *** search
- /*
- * xknn.c
- *
- * Practical Algorithms for Image Analysis
- *
- * Copyright (c) 1997, 1998, 1999 MLMSoftwareGroup, LLC
- */
-
- /*
- * XKNN(K-Nearest Neighbors)
- *
- * test knn.c module
- *
- */
-
- #include "xknn.h"
-
- #define BUFSZ 1024
- #define ON 1
- #define OFF 0
- extern short tiffInput; /* flag=0 if no ImageIn to set tags; else =1 */
-
- /*
- * Globals
- */
-
- int maxX;
- int maxY;
- int minX;
- int minY;
- int npoints;
- extern char *optarg;
- extern int optind, opterr;
-
- /*
- * usage of routine
- */
- void
- usage (char *progname)
- {
- progname = last_bs (progname);
- printf ("USAGE: %s infile knn outimg [-l][-L]\n", progname);
- printf ("\n%s finds K-nearest neighbors for each point\n", progname);
- printf ("in a list of x-y points\n\n");
- printf ("ARGUMENTS:\n");
- printf (" infile: input file with list of (x,y) pairs (ASCII)\n");
- printf (" knn: number of nearest neighbors to calculate (int)\n");
- printf (" outimg: output image filename (TIF)\n\n");
- printf ("OPTIONS:\n");
- printf (" -l: prints (x,y) point with neighbor list\n");
- printf (" -L: print Software License for this module\n");
- 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);
- }
-
- int
- dump_point (struct Point *p1, int knn)
- {
- struct KNN *pk;
- int i;
-
- pk = p1->Knn;
- printf ("struct for Point (%d, %d), nNN = %d\n", p1->x_pos, p1->y_pos, p1->nNN);
- for (i = 0; i < knn; i++) {
- printf ("pk[%d] = (%d, %d), distSqd = %d\n", i, pk[i].x_pos, pk[i].y_pos, pk[i].distSqd);
- }
- return (0);
- }
-
- /*
- * 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++) {
- /*for(j = 0, p2 = points; j < npoints; j++, p2++) { */
- if (p2 == p1)
- break;
- 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 && (p1->Knn[knn - 1].distSqd > 0) && ((yDist * yDist) > (p1->Knn[knn - 1].distSqd))) {
- //dump_point(p1, knn);
- 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;
- }
- //dump_point(p1, knn);
- 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;
- int i_arg;
- int print_list = 0;
-
- /*
- * cmd line options
- */
- static char *optstring = "lL";
-
-
- /*
- * parse command line
- */
- optind = 4; /* set getopt to point to the 4th arg */
- opterr = ON; /* give error messages */
-
-
- if (argc < 4)
- usage (argv[0]);
-
- while ((i_arg = getopt (argc, argv, optstring)) != EOF) {
- switch (i_arg) {
- case 'l':
- printf ("\n...option %c: print list of points with K-nn\n", i_arg);
- print_list = 1;
- break;
- case 'L':
- print_sos_lic ();
- exit (0);
- default:
- printf ("\ngetopt: unknown condition encountered\n");
- exit (1);
- break;
- }
- }
-
- if (sscanf (argv[2], "%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[1], 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);
-
- if (print_list) {
- 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);
- if (print_list)
- printf ("Nearest neighbors for Point %d = (%d, %d), %d\n", i, p->x_pos, p->y_pos, p->nNN);
- for (j = 0; j < p->nNN; j++) {
- if (print_list)
- 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);
- }
-