mirror of
https://github.com/bspeice/libcvautomation
synced 2025-01-08 06:51:27 -05: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>
|
|
|
|
*/
|