/* * ===================================================================================== * * Filename: cva-match.c * * Description: Match an image to its parent image, and return the coordinates * * Version: 0.1 * Created: 06/20/2012 * Revision: none * Compiler: gcc * * Author: Bradlee Speice, bspeice@uncc.edu * Organization: MOSAIC at University of North Carolina at Charlotte * * ===================================================================================== */ #include #include #include #include #include #include void usage (); /// \cond struct list { char *fileName; struct list *next; }; typedef struct list basic_list; /// \endcond int main( int argc, char** argv ) { cvaPoint result_point; result_point.x = result_point.y = 0; /* Set up everything for getopt */ char *separator = ","; char *root_location = "root.png"; char *sub_location = "sub.png"; int tolerance = INT_MAX; int search_method = CV_TM_SQDIFF; int useX = 0; /* bool useX = false; */ Bool useCenter = False; char *xDisplayLocation; Display *display = NULL; /* Set the default display */ xDisplayLocation = ""; /* Set up the linked list for slave images */ basic_list *list_head, *list_curr, *list_prev; list_head = list_curr = list_prev = NULL; int returnCode = 1; /* Start getopt */ while (1) { static struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"usage", no_argument, 0, 'u'}, {"version", no_argument, 0, 'v'}, {"root-image", required_argument, 0, 'r'}, {"sub-image", required_argument, 0, 's'}, {"separator", required_argument, 0, 'p'}, {"search-method",required_argument, 0, 'm'}, {"tolerance", required_argument, 0, 't'}, {"x-root", optional_argument, 0, 'x'}, {"center", no_argument, 0, 'c'}, {"sane-tolerance", required_argument, 0, 'o'}, {0, 0, 0, 0} }; int option_index = 0; opterr = 0; int c = getopt_long (argc, argv, "hur:s:p:m:t:x::c", long_options, &option_index); /* We're done with parsing options */ if (c == -1) break; switch (c) { case 0: break; case 'h': usage(); break; case 'u': usage(); break; case 'v': usage(); break; case 'r': root_location = optarg; break; case 's': if ( list_head == NULL ) { list_head = (basic_list *) malloc (sizeof(basic_list)); list_curr = list_head; } list_curr->fileName = optarg; list_curr->next = (basic_list *) malloc (sizeof(basic_list)); list_curr->next->fileName = NULL; list_curr = list_curr->next; break; case 'p': separator = optarg; break; case 'm': search_method = atoi(optarg); break; case 't': tolerance = atoi(optarg); break; case 'x': if ( optarg != NULL ) { useX = 1; xDisplayLocation = optarg; display = XOpenDisplay(xDisplayLocation); } else { useX = 1; xDisplayLocation = ""; display = XOpenDisplay(xDisplayLocation); } break; case 'c': useCenter = True; break; case 'o': tolerance = atoi(optarg); /* Provide a more sane way to configure tolerance: * --sane-tolerance=100 ~= INT_MAX */ tolerance = pow(1.2397076, tolerance); break; case '?': /* Error routine */ break; default: fprintf( stderr, "Unknown option..." ); exit(0); }; } /* Make sure we have a linked list, * and reset the linked list to go back through from the top */ if ( list_head == NULL ) return 1; else list_curr = list_head; do { sub_location = list_curr->fileName; if (useX && useCenter) result_point = matchSubImage_X11_location_center( display, sub_location, search_method, tolerance ); else if (useX && !useCenter) result_point = matchSubImage_X11_location( display, sub_location, search_method, tolerance ); else if (!useX && useCenter) result_point = matchSubImage_location_center( root_location, sub_location, search_method, tolerance ); else /* if (!useX && !useCenter) */ result_point = matchSubImage_location( root_location, sub_location, search_method, tolerance ); if ( result_point.x != -1 && result_point.y != -1 ) { /* Output the match location */ printf ("%s%s%i%s%i\n", list_curr->fileName, separator, result_point.x, separator, result_point.y ); returnCode = 0; } /* With the way we allocate the list, we ensure that we always * have at least one element past the end of the list. * Also, deconstruct the list as we go. */ list_prev = list_curr; list_curr = list_curr->next; free(list_prev); } while ( list_curr->fileName != NULL ); /* And free the final element */ free(list_curr); /* Clean up X */ if (useX) XCloseDisplay(display); return returnCode; } /* * === FUNCTION ====================================================================== * Name: usage * Description: I really shouldn't need to write this * ===================================================================================== */ void usage ( ) { fprintf( stderr, "\ Libcvautomation version: %s\n\ cva-match -r -s \n\ cva-match -s -x \n\ \n\ This program uses OpenCV in order to recognize an image within an image.\n\ The return code is 0 for at least one successful match, and 1 otherwise.\n\ \n\ Usage: \n\ \n\ \t-h, --help:\t\tDisplay this usage message.\n\ \t-u, --usage:\t\tDisplay this usage message.\n\ \t-r, --root-image:\tLocation of the root image to compare against.\n\ \t-s, --sub-image:\tLocation of the sub-image to find in root.\n\ \t-p, --separator:\tSeparator of the X and Y coordinates.\n\ \t-t, --tolerance:\tSet how strict the match is - 100 is recommended lowest value.\n\ \t\t\t\tNote: When using CCORR or CCOEFF tolerance works in opposite direction,\n\ \t\t\t\tso -50 is recommended highest value.\n\ \t-m, --search-method:\tSet which method is used to search for sub-images.\n\ \t\t\t\tMethods:\n\ \t\t\t\t\tCV_TM_SQDIFF = 0\n\ \t\t\t\t\tCV_TM_SQDIFF_NORMED = 1\n\ \t\t\t\t\tCV_TM_CCORR = 2\n\ \t\t\t\t\tCV_TM_CCORR_NORMED = 3\n\ \t\t\t\t\tCV_TM_CCOEFF = 4\n\ \t\t\t\t\tCV_TM_COEFF_NORMED = 5\n\ \t-x, --x-root[=DISPLAY]:\tSet the root image to come from X11\n\ \t\t\t\tThe DISPLAY variable is optional, not specifying it will cause X\n\ \t\t\t\tto use the default display (not specifically :0.0)\n\ \t\t\t\tPlease note also that the '-x' must come at the end\n\ \t\t\t\tsince it is an optional argument.\n\ \t-c, --center:\t\tThe output points should be centered on the sub-image, rather\n\ \t\t\t\tthan the top-left corner.\n\ \t-o, --sane-tolerance:\tSet the tolerance using a scale of 1-100,\n\ \t\t\t\trather than INT_MIN to INT_MAX (100 ~= INT_MAX)\n\ \n\ If you have any questions, comments, concerns, email <%s>\n", LIBCVAUTOMATION_VERSION, LIBCVAUTOMATION_BUGREPORT ); exit (0); } /* ----- end of function usage ----- */ /* Doxygen Information */ /** \file cva-match.c * \brief The cva-input program to demonstrate Libcvautomation's XTest functionality * \author Bradlee Speice */ /* The biggest purpose of documenting this code is to trick doxygen into making a man page for it. */ /** \page cva-match * * \author Bradlee Speice * \section usage Usage: * This program uses OpenCV in order to recognize an image within an image. The return code is 0 for at least one successful match, and 1 otherwise. * * \section example Example Usage: * Match two images against the root X11 window: * * cva-match --x-root -s "" -s "" * * Match a root and sub image with a custom tolerance and search method * * cva-match -r "" -s "" -o 75 -m 1 * * \section options Full Options: * -h, --help: Display this usage message. * * -u, --usage: Display this usage message. * * -r, --root-image: Location of the root image to compare against. * * -s, --sub-image: Location of the sub-image to find in root. * * -p, --separator: Separator of the X and Y coordinates. * * -t, --tolerance: Set how strict the match is - 100 is recommended lowest value. * * \note When using CCORR or CCOEFF tolerance works in opposite direction, so -50 is recommended highest value. * * -m, --search-method: Set which method is used to search for sub-images. * * \note Search Methods: CV_TM_SQDIFF = 0, CV_TM_SQDIFF_NORMED = 1, CV_TM_CCORR = 2, CV_TM_CCORR_NORMED = 3, CV_TM_CCOEFF = 4, CV_TM_COEFF_NORMED = 5 * * -x, --x-root[=DISPLAY]: Set the root image to come from X11 * * \note The DISPLAY variable is optional, not specifying it will cause X to use the default display (not specifically :0.0) * * -c, --center: The output points should be centered on the sub-image, rather than the top-left corner. * * -o, --sane-tolerance: Set the tolerance using a scale of 1-100, rather than INT_MIN to INT_MAX (100 ~= INT_MAX) * * * \section contact Contact Information: * Questions? Comments? Concerns? Suggestions? Send all feedback to Bradlee Speice at */