mirror of
				https://github.com/bspeice/libcvautomation
				synced 2025-10-31 01:10:34 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			320 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			320 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * =====================================================================================
 | |
|  *
 | |
|  *       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 <stdlib.h>
 | |
| #include <stdio.h>
 | |
| #include <unistd.h>
 | |
| #include <getopt.h>
 | |
| #include <limits.h>
 | |
| 
 | |
| #include <libcvautomation/libcvautomation.h>
 | |
| 
 | |
| 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 <root_image> -s <sub_image> \n\
 | |
| cva-match -s <sub_image> -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 <bspeice@uncc.edu>
 | |
|  */
 | |
| 
 | |
| /* The biggest purpose of documenting this code is to trick doxygen into making a man page for it. */
 | |
| /** \page cva-match
 | |
|  *
 | |
|  * \author Bradlee Speice <bspeice@uncc.edu>
 | |
|  * \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 "<image_name>" -s "<image_name_2>"
 | |
|  *
 | |
|  * Match a root and sub image with a custom tolerance and search method
 | |
|  *
 | |
|  * cva-match -r "<root_image>" -s "<image_name>" -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 <bspeice@uncc.edu>
 | |
| 
 | |
|  */
 | 
