/* * Arguments.cpp * * Copyright (c) 2008 Machine Perception Laboratory * University of California San Diego. * * Authors: Andrew Salamon * * Please read the disclaimer and notes about redistribution * at the end of this file. * */ #include "CERT_Arguments.h" #include #include // For system independent path support //#include #include //#include // For basename and extension namespace bf = boost::filesystem; #include "PluginController.h" namespace CERT { static std::ostream &operator<<( std::ostream &os, const std::vector< std::string > &vec ) { for( unsigned int ind = 0; ind < vec.size(); ++ind ) { os << vec[ind]; if( ind < (vec.size() - 1) ) os << ", "; } return os; } Arguments & Arguments::getArgs() { static Arguments args; return args; } void Arguments::cleanup() { getArgs()._cleanup(); } bool Arguments::processArgs( int argc, char *argv[], const std::string &defaultConfigPath ) { return getArgs()._processArgs( argc, argv, defaultConfigPath ); } void Arguments::usage( char *prog ) { std::cout << "Usage: CERTDemo [-h] [-f] [-p ] [-t] [-s] [-m] [-c ] [{-gt|-gc} ] [-o ] [|]" << std::endl; std::cout << " -h Output this help message then quit." << std::endl; std::cout << " -f Input images are already cropped and rotated faces." << std::endl; std::cout << " -p Generate cropped and rotated face patches in the given directory. Filenames will have '_face' appended to them." << std::endl; std::cout << " -pf Format for generated patch files. Valid types are: " << Images::knownFiletypes() << std::endl; std::cout << " -t Output simple tab delimited results: ." << std::endl; std::cout << " -s Use the face box found in a previous image as a starting place for searching the current image." << std::endl; std::cout << " -m Limit how many scales we search when using a previously found face (i.e. the '-s' flag)." << std::endl; std::cout << " -c Read configuration info from a non-default location. Default is: " << getArgs()._defaultConfigPath << "." << std::endl; std::cout << " -o Output will be written to the given file rather than standard out." << std::endl; std::cout << " -gt Train GKR models and write them to the given file." << std::endl; std::cout << " -gc Use GKR models from the given file to adjust CERT AU outputs." << std::endl; std::vector types = CERT::PluginController::knownPluginTypes(); std::cout << " Known plugin types: " << types << std::endl; std::vector< std::string > methods = CERT::PluginController::validFaceAlignmentMethods(); std::cout << " Valid face alignment methods: " << methods << std::endl; std::cout << " Note: If images or directories are given on the command line they will all be processed then the application will quit." << std::endl; } bool Arguments::ready() { return getArgs()._ready; } bool Arguments::inputIsFaces() { return getArgs()._inputIsFaces; } bool Arguments::sequential() { return getArgs()._sequential; } bool Arguments::outputPatches() { return getArgs()._outputPatches; } std::string Arguments::patchDir() { return getArgs()._patchDir; } int Arguments::maxTries() { return getArgs()._maxTries; } bool Arguments::tabDelim() { return getArgs()._tabDelim; } bool Arguments::outputToFile() { return getArgs()._outputToFile; } std::string Arguments::outputPath() { return getArgs()._outputPath; } std::ostream & Arguments::outputStream() { if( getArgs()._outputToFile && getArgs()._outputStream.good() ) return getArgs()._outputStream; return std::cout; } std::string Arguments::configPath() { return getArgs()._configPath; } const std::vector< std::string > & Arguments::paths() { return getArgs()._paths; } Images::filetype Arguments::patchFiletype() { return getArgs()._patchFiletype; } bool Arguments::GKRTraining() { return getArgs()._GKRTraining; } std::string Arguments::GKRModelPath() { return getArgs()._GKRModelPath; } Arguments::Arguments() : _ready(false), _inputIsFaces(false), _sequential(false), _outputPatches(false), _patchDir("/tmp"), _maxTries(-1), _tabDelim(false), _outputToFile(false), _patchFiletype(Images::bmp), _GKRTraining(false) { } Arguments::~Arguments() { _cleanup(); } void Arguments::_cleanup() { _ready = false; // Not sure if this is necessary or not. if( _outputStream.is_open() ) _outputStream.close(); } bool Arguments::_processArgs( int argc, char *argv[], const std::string &defaultConfigPath ) { bool argsOK = true; _defaultConfigPath = defaultConfigPath; _configPath = defaultConfigPath; for( int argIndex = 1; argIndex < argc; ++argIndex ) { std::string arg1( argv[argIndex] ); if( "-f" == arg1) { _inputIsFaces = true; } else if( "-p" == arg1 ) { if( argIndex >= (argc - 1) ) { std::cerr << "A directory is required for the '-p' option." << std::endl; argsOK = false; } else { // get the next arg and if it's a directory, put the patches there char *nextArg = argv[argIndex+1]; bf::path bfArg( nextArg, bf::native ); if( bf::exists( bfArg ) && bf::is_directory( bfArg ) ) { _outputPatches = true; _patchDir = nextArg; ++argIndex; } else { std::cerr << "Invalid directory for the '-p' option: " << nextArg << "." << std::endl; argsOK = false; } } } else if( "-pf" == arg1 ) { if( argIndex >= (argc - 1) ) { std::cerr << "A file type is required for the '-pf' option."; std::cerr << " Valid options are: " << Images::knownFiletypes() << std::endl; argsOK = false; } else { std::string typeStr( argv[argIndex+1] ); Images::filetype type = Images::end_types; try { type = Images::filetypeFromString( typeStr ); } catch(...) { } if( Images::end_types == type ) { std::cerr << "Invalid file type for the '-pf' option."; std::cerr << " Valid options are: " << Images::knownFiletypes() << std::endl; argsOK = false; } else { _patchFiletype = type; } ++argIndex; } } else if( "-c" == arg1 ) { if( argIndex >= (argc - 1) ) { std::cerr << "A path is required for the '-c' option." << std::endl; argsOK = false; } else { char *nextArg = argv[argIndex+1]; _configPath = nextArg; ++argIndex; } } else if( "-t" == arg1 ) { _tabDelim = true; } else if( "-h" == arg1 ) { usage( argv[0] ); return false; } else if( "-s" == arg1 ) { _sequential = true; } else if( "-m" == arg1 ) { if( argIndex >= (argc - 1) ) { std::cerr << "An integer is required for the '-m' option (maximum number of tries when given an external face position)." << std::endl; argsOK = false; } else { int tries = -1; char *nextArg = argv[argIndex+1]; std::istringstream instr( nextArg ); if( instr >> tries ) { _maxTries = tries; } else { std::cerr << "An integer is required for the '-m' option (maximum number of tries when given an external face position)." << std::endl; argsOK = false; } ++argIndex; } } else if( "-o" == arg1 ) { if( argIndex >= (argc - 1) ) { std::cerr << "An output file name is required for the '-o' option." << std::endl; argsOK = false; } else { char *nextArg = argv[argIndex+1]; bf::path bfArg( nextArg, bf::native ); if( bf::exists(bfArg) && bf::is_directory( bfArg ) ) { std::cerr << "Output file '" << nextArg << "' is a directory. Unable to overwrite." << std::endl; argsOK = false; } else { _outputStream.open( nextArg, std::ios_base::out | std::ios_base::app ); if( !_outputStream.good() ) { std::cerr << "Unable to open output file '" << nextArg << "' for writing." << std::endl; argsOK = false; } else { _outputToFile = true; _outputPath = nextArg; ++argIndex; } } } } else if( "-gt" == arg1 ) { std::string errorMsg; std::string filename; if( !getFileArgument( argc, argv, argIndex, filename, true, "-gt", "GKR Model", errorMsg ) ) { std::cerr << errorMsg; argsOK = false; } else { _GKRTraining = true; _GKRModelPath = filename; } } else if( "-gc" == arg1 ) { std::string errorMsg; std::string filename; if( !getFileArgument( argc, argv, argIndex, filename, false, "-gc", "GKR Model", errorMsg ) ) { std::cerr << errorMsg; argsOK = false; } else { _GKRTraining = false; _GKRModelPath = filename; } } else { _paths.push_back( argv[argIndex] ); } } if( argsOK ) _ready = true; else usage( argv[0] ); return argsOK; } bool Arguments::getFileArgument( int argc, char *argv[], int &argIndex, std::string &filename, bool writeFlag, const std::string option, const std::string fileTitle, std::string &errorMsg ) { bool argsOK = true; std::stringstream errorStream; if( argIndex >= (argc - 1) ) { errorStream << "A file name is required for the " << option << " option." << std::endl; argsOK = false; } else { char *nextArg = argv[argIndex+1]; bf::path bfArg( nextArg, bf::native ); if( writeFlag ) { if( bf::exists(bfArg) && bf::is_directory( bfArg ) ) { errorStream << "Path for " << fileTitle << ", '" << nextArg << "', is a directory." << std::endl; argsOK = false; } else { filename = nextArg; ++argIndex; } } else { if( !bf::exists(bfArg) ) { errorStream << fileTitle << " does not exist at '" << nextArg << "'." << std::endl; argsOK = false; } else if( bf::is_directory( bfArg ) ) { errorStream << "Path for " << fileTitle << ", '" << nextArg << "', is a directory." << std::endl; argsOK = false; } else { filename = nextArg; ++argIndex; } } } if( !argsOK ) errorMsg = errorStream.str(); return argsOK; } } // End CERT namespace /* * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */