#include "mp_NRL.h" #include // for cout and cerr #include #include #include #include #include #include // For system independent path support #include #include #include // For basename and extension namespace bf = boost::filesystem; #include "rimage.h" #include "ImageDirIterator.h" #include "ImageLoader.h" #include "VideoIterator.h" #include "CERT_Config.h" #include "CERT_Arguments.h" #include "PluginController.h" #include "AfterFacePlugin.h" #include "FacePlugin.h" #include "SVMPlugin.h" #include "FeaturePlugin.h" #include "IntervalCRP.h" #ifdef THREADED_LOADER #include "CERT_Loader.h" #endif //#ifdef CERT_WIN_DEMO #include "mp_CERT.h" typedef MP_CERT CERT_CLASS; std::string defaultFD( "../../featuredetector/frozenData/" ); std::string defaultSVM( "../../mp_auCoder/SVMWeights" ); std::string defaultConfigPath( "../../CERTWrapper/CERT_Win.cfg" ); void processPath( std::vector< RImage > &rimages, const std::string &path ); void processDir( std::vector< RImage > &rimages, const std::string &path ); bool processImage( std::vector< RImage > &rimages, const std::string &path ); std::ostream &mout(); ///< Get an output stream, either cout or a file stream depending on user options. CERT::Config *defaultConfig(); std::string getimagepath(); CERT::VideoIterator videos; CERT::ImageLoader loader; int main( int argc, char *argv[] ) { if( !CERT::Arguments::processArgs( argc, argv, defaultConfigPath ) ) { // We still want to output the verision info std::cout << "CERT v" << CERT_CLASS::getVersion() << " (build " << CERT_CLASS::getBuildString() << ")" << std::endl; return -1; } mout() << "CERT v" << CERT_CLASS::getVersion() << " (build " << CERT_CLASS::getBuildString() << ")" << std::endl; // Now set up the plugin controller and let it load the config file try { CERT::PluginController::getPluginController( CERT::Arguments::configPath() ); } catch( const CERT::Config::exception &error ) { std::cerr << "Unable to read configuration file from: " << CERT::Arguments::configPath() << ". Using default values." << std::endl; std::cerr << "The error was: " << error.what() << std::endl; // If we failed to load from the given config file, create a new controller with the default config CERT::PluginController *pc = CERT::PluginController::getPluginController(); pc->loadPluginsFromConfig( defaultConfig() ); } CERT_CLASS *cert(NULL); std::cout << "Loading data files... " << std::endl; // CERT will load all SVM and Feature plugins from the plugin controller. try { cert = new CERT_CLASS( true ); } catch( const std::exception &error ) { std::cerr << error.what() << std::endl; return -4; } catch( const std::string error ) { // The feature detector throws strings if there is an error loading data files. std::cerr << error << std::endl; return -2; } std::auto_ptr certDeleter(cert); // make sure cert get's deleted std::cout << "Finished loading data files" << std::endl; std::vector< RImage > rimageSequence; const std::vector< std::string > &paths( CERT::Arguments::paths() ); unsigned int pathCount = paths.size(); if( pathCount > 0 ) { for( unsigned int index = 0; index < pathCount; ++index ) { processPath( rimageSequence, paths[index] ); } } else { do { std::string path = getimagepath(); if( "quit" == path ) break; processPath( rimageSequence, path ); } while( true ); } // std::cout << "Count of rimages: " << rimageSequence.size() << std::endl; mp_NRL nrl; nrl.setCERT( cert ); std::vector res = nrl.calcAUs( rimageSequence ); for( unsigned int i = 0; i < res.size(); ++i ) { std::cout << res[i] << '\t'; } std::cout << std::endl; /* guess how many images there will be and resize the vector. Or build a complete list of all images, sort them, then proceed Read in each image and add it to the vector, adjusting the vector's size if necessary Pass all images to calcAUs output results */ CERT::PluginController::cleanup(); CERT::Arguments::cleanup(); loader.cleanup(); videos.cleanup(); return 0; } void processPath( std::vector< RImage > &rimages, const std::string &path ) { bf::path bfPath( path, bf::native ); if( bf::exists( bfPath ) ) { if( bf::is_directory( bfPath ) ) processDir( rimages, path ); else { processImage( rimages, path ); } } } void processDir( std::vector< RImage > &rimages, const std::string &path ) { ImageDirIterator images( path ); while( ++images ) { std::string fileName = *images; processImage( rimages, fileName ); } } bool processImage( std::vector< RImage > &rimages, const std::string &path ) { RImage pixels; bool ok(false); if( loader.loadRImage(pixels, path ) ) // handles loading an image from file into an RImage { rimages.push_back( pixels ); ok = true; } else { videos.setPath( path ); if( videos.isVideo() ) { while( videos.nextFrame( pixels ) ) { // std::ostringstream frameStream; // frameStream << path << ":" << videos.getFrameNumber(); rimages.push_back( pixels ); } ok = true; } else { // This really ought to be in the StandardOutput plugin. // Maybe a processNoFile( path ) method on cert which just calls doResultsPlugins. mout() << path; if( !CERT::Arguments::tabDelim() ) mout() << std::endl; mout() << "\tUnable to read file" << std::endl; if( !CERT::Arguments::tabDelim() ) mout() << std::endl; } videos.setPath( "" ); // This should release the movie, so it doesn't stick around in memory. } return ok; } std::string getimagepath() { std::string path; std::cout << "Enter path to image"; #ifdef WIN32 std::cout << " (Windows demo only accepts 24 bit bitmaps)"; #endif std::cout << " or ctrl-c to exit" << std::endl; std::cout << "--> "; // std::cin >> path; std::getline( std::cin, path ); if( std::cin.eof() ) path = "quit"; return(path); } std::ostream &mout() { return CERT::Arguments::outputStream(); } /** A Function to generate a default config object if no config file is found. * It also gives a good example of how to hard code config settings instead of using a file. */ CERT::Config *defaultConfig() { CERT::Config *tmp = new CERT::Config; CERT::ConfigItem *item = new CERT::ConfigItem; item->setPluginID( "defaultID" ); item->setName( "FACS Codes 4.0" ); item->setInternalName( "CERT4_0_Weights" ); item->setPluginType( "MPT_PluginStep_SVM" ); item->setEnabled( true ); item->setValueForKey( defaultSVM, "dir" ); std::vector labels; labels.push_back( "(AU 1) Inner Brow Raise" ); labels.push_back( "(AU 2) Outer Brow Raise" ); labels.push_back( "(AU 4) Brow Lower" ); labels.push_back( "(AU 5) Eye Widen" ); labels.push_back( "(AU 9) Nose Wrinkle" ); labels.push_back( "(AU 10) Lip Raise" ); labels.push_back( "(AU 12) Lip Corner Pull" ); labels.push_back( "(AU 14) Dimpler" ); labels.push_back( "(AU 15) Lip Corner Depressor" ); labels.push_back( "(AU 17) Chin Raise" ); labels.push_back( "(AU 20) Lip stretch" ); item->setValueForKey( labels, "labels" ); tmp->addItem( item ); CERT::ConfigItem *feature = new CERT::ConfigItem; feature->setPluginID( "left_eye" ); feature->setName( "Left Eye" ); feature->setInternalName( "left_eye" ); feature->setPluginType( "MPT_PluginStep_Features" ); feature->setEnabled( true ); feature->setDisplay( false ); feature->setValueForKey( (defaultFD + "left_eye_CERT3.fdtxml"), "feature" ); feature->setValueForKey( (defaultFD + "left_eye_CERT3.gpriorxml"), "gprior" ); tmp->addItem( feature ); feature = new CERT::ConfigItem; feature->setPluginID( "right_eye" ); feature->setName( "Right Eye" ); feature->setInternalName( "right_eye" ); feature->setPluginType( "MPT_PluginStep_Features" ); feature->setEnabled( true ); feature->setDisplay( false ); feature->setValueForKey( (defaultFD + "right_eye_CERT3.fdtxml"), "feature" ); feature->setValueForKey( (defaultFD + "right_eye_CERT3.gpriorxml"), "gprior" ); tmp->addItem( feature ); feature = new CERT::ConfigItem; feature->setPluginID( "nose" ); feature->setName( "Nose" ); feature->setInternalName( "nose" ); feature->setPluginType( "MPT_PluginStep_Features" ); feature->setEnabled( true ); feature->setDisplay( false ); feature->setValueForKey( (defaultFD + "nose_CERT3.fdtxml"), "feature" ); feature->setValueForKey( (defaultFD + "nose_CERT3.gpriorxml"), "gprior" ); tmp->addItem( feature ); feature = new CERT::ConfigItem; feature->setPluginID( "mouth" ); feature->setName( "Mouth" ); feature->setInternalName( "mouth" ); feature->setPluginType( "MPT_PluginStep_Features" ); feature->setEnabled( true ); feature->setDisplay( false ); feature->setValueForKey( (defaultFD + "mouth_CERT3_1.fdtxml"), "feature" ); feature->setValueForKey( (defaultFD + "mouth_CERT3_1.gpriorxml"), "gprior" ); tmp->addItem( feature ); item = new CERT::ConfigItem; item->setPluginID( "standardoutput" ); item->setName( "Standard Output" ); item->setInternalName( "standardoutput" ); item->setPluginType( "MPT_PluginStep_Output" ); item->setEnabled( true ); item->setDisplay( true ); tmp->addItem( item ); return tmp; } std::vector mp_NRL::calcAUs( const std::vector< RImage > &rimageSequence ) { // Make sure the standard output plugin is turned off // set the window size for the interval plugin to the size of the image sequence // run each image // output the final results of the interval plugin CERT::PluginController &pc = cert->pluginController(); CERT::PluginBase *output = pc.pluginWithID( "edu.ucsd.mplab.plugins.features.StandardOutput", true ); if( !output ) output = pc.pluginWithID( "standardoutput", true ); if( output ) output->setEnabled( false ); CERT::IntervalCRP *interval = dynamic_cast(pc.pluginWithID( "edu.ucsd.mplab.plugins.IntervalCRP" ) ); if( !interval ) { std::cerr << "No Interval TT plugin found." << std::endl; return std::vector(); } interval->setWindow( rimageSequence.size() ); for( unsigned int i = 0; i < rimageSequence.size(); ++i ) { cert->calcAUs( const_cast &>(rimageSequence[i]), "" ); } return interval->getResults(); }