// // MPT_CERT.mm // AUCoderDemo // // Created by Andrew Salamon on 5/17/06. // Copyright (c) 2006 Machine Perception Laboratory // University of California San Diego. // #import "MPT_CERT.h" #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import "NSImageToRimage.h" #import "MPT_Face.h" #import "MPT_RimageAdaptor.h" #import "MPT_PluginController.h" #import "MPT_PluginProtocolPlusPlus.h" #import "MPT_PluginProtocolSVM.h" #import "MPT_PluginProtocolFeatures.h" #import "MPT_PluginProtocolFrequencies.h" #import "MPT_PluginProtocolResults.h" #import "MPT_FeatureBase.h" #ifdef __APPLE_CC__ #include #endif //#ifdef xxDEBUG typedef MP_Gabor GABOR_CLASS; //#else //typedef mp_threadedGabor GABOR_CLASS; //#endif typedef mp_FDEyes EYEFINDER_CLASS; @interface MPT_CERT(PrivateMethods) - (void)processRImageImp:(RImage *)rimage; - (void)rotateImage:(RImage *)rimage into:(RImage *)destImage byRadians:(float)rad; - (BOOL)loadFeaturePlugins; - (ObjectWithFeatures)findFaces:(OWFList &)objects inRImage:(RImage &)rimage; - (void)featureAveragingChanged_imp:(id)faplugin; @end @implementation MPT_CERT + (void)initialize { // Make sure the correct alignment method is used by default unless the user overrides it. NSUserDefaults *_prefs = [NSUserDefaults standardUserDefaults]; NSDictionary *defPrefs = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:FeatureAlignment::unconstrained_least_squares], @"alignmentMethod", [NSNumber numberWithFloat:[self defaultEyefinderOffset]], @"eyefinderOffset", [NSNumber numberWithFloat:[self defaultEyefinderDropoff]], @"eyefinderDropoff", [NSNumber numberWithBool:NO], @"useSequence", [NSNumber numberWithInt:0], @"windowMinScale", [NSNumber numberWithInt:20], @"windowMaxScale", nil]; [_prefs registerDefaults:defPrefs]; } - (id)init { if( self = [super init] ) { prefs = [NSUserDefaults standardUserDefaults]; pluginResults = [[NSMutableDictionary alloc] init]; faceArray = [[NSMutableArray alloc] init]; featuresByName = [[NSMutableDictionary alloc] init]; myPlugins = [MPT_PluginController defaultController]; #ifdef USING_ROTATING_EYEFINDER // Updated to try to use the feature detector, but it's still not working. float _angles[] = { 15.0, -15.0, 30.0, -30.0, 45.0, -45.0 }; std::vector angles( _angles, _angles+6 ); rotatingEyefinder = new mp_rotatingEyefinder( angles, false ); //((mp_rotatingEyefinder *)rotatingEyefinder)->setUseSequence( [self doingSequence] ); #endif mpeyefinder = new EYEFINDER_CLASS(); // ((EYEFINDER_CLASS *)mpeyefinder)->setWinshift( 0.0 ); [self setDoingSequence:[self doingSequence]]; // ((EYEFINDER_CLASS *)mpeyefinder)->setMinScale( 1 ); ((EYEFINDER_CLASS *)mpeyefinder)->setCERT3_3_FaceBox(); // Make sure we're up to date with the Feature Averaging prefs. id faPlugin = [[MPT_PluginController defaultController] pluginForPluginID:@"edu.ucsd.mplab.plugins.features.MPT_FeatureAveraging"]; if( faPlugin ) [self featureAveragingChanged_imp:faPlugin]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(featureAveragingChanged:) name:@"MPT_FeatureAveraging" object:nil]; // Loop through all features looking for any that return processors and add them to the feature detector NSArray *plugins = [[MPT_PluginController defaultController] pluginsForStep:MPT_PluginStep_Features]; NSEnumerator *pluginEnum = [plugins objectEnumerator]; MPT_FeatureBase *plugin; while( plugin = [pluginEnum nextObject] ) { void *proc = [plugin processor]; if( proc ) ((EYEFINDER_CLASS *)mpeyefinder)->addProcessor( (mpt::OWF::ProcessorBase *)proc ); } [prefs addObserver:self forKeyPath:@"useSequence" options:NSKeyValueObservingOptionNew context:NULL]; [prefs addObserver:self forKeyPath:@"windowMinScale" options:NSKeyValueObservingOptionNew context:NULL]; [prefs addObserver:self forKeyPath:@"windowMaxScale" options:NSKeyValueObservingOptionNew context:NULL]; [self setMinScale:[self minScale]]; [self setMaxScale:[self maxScale]]; patch = new RImage( 96, 96 ); RImage &lpatch = *((RImage *)patch); gabor = new GABOR_CLASS( lpatch, lpatch.width, lpatch.height ); rotator = new MP_RotateFace( 96 ); // face patches are 96x96 pixels ((MP_RotateFace *)rotator)->setEyeLenRate( 0.48 ); //((MP_RotateFace *)rotator)->setEyeTopRate( 0.20 ); [prefs addObserver:self forKeyPath:@"eyefinderOffset" options:NSKeyValueObservingOptionNew context:NULL]; [prefs addObserver:self forKeyPath:@"eyefinderDropoff" options:NSKeyValueObservingOptionNew context:NULL]; [self setEyefinderOffset:[self eyefinderOffset]]; [self setEyefinderDropoff:[self eyefinderDropoff]]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pluginChangedNotification:) name:[MPT_PluginController pluginStateChangedNotification] object:[MPT_PluginController defaultController]]; [self pluginStateHasChanged:nil]; // [self loadFeaturePlugins]; } return self; } - (void)dealloc { [grayImage release]; [faceArray release]; [featuresByName release]; [myPlugins release]; if( mpeyefinder ) delete (EYEFINDER_CLASS *)mpeyefinder; if( rotatingEyefinder ) delete (mp_rotatingEyefinder *)rotatingEyefinder; if( gabor ) delete (GABOR_CLASS *)gabor; if( rotator ) delete (MP_RotateFace *)rotator; if( patch ) delete (RImage *)patch; [prefs removeObserver:self forKeyPath:@"eyefinderOffset"]; [prefs removeObserver:self forKeyPath:@"eyefinderDropoff"]; [prefs removeObserver:self forKeyPath:@"windowMinScale"]; [prefs removeObserver:self forKeyPath:@"windowMaxScale"]; [featureLock release]; [[NSNotificationCenter defaultCenter] removeObserver:self]; [super dealloc]; } - (void)process:(NSDictionary *)inputs { [self clearResults]; [pluginResults addEntriesFromDictionary:inputs]; // We could have one or more of: image path, NSImage, RImage NSImage *image = [inputs objectForKey:@"CERT.image"]; NSString *path = [inputs objectForKey:@"CERT.path"]; MPT_RimageAdaptor *rimageAdaptor = [inputs objectForKey:@"CERT.rimage"]; RImage *rimage = NULL; if( rimageAdaptor ) { rimage = (RImage *)[rimageAdaptor rimage]; } else if( image ) { // rimage = [image rimageRep]; rimage = rimageFromImage( image ); rimageAdaptor = [[MPT_RimageAdaptor alloc] initWithRimage:rimage]; [pluginResults setObject:rimageAdaptor forKey:@"CERT.rimage"]; [rimageAdaptor release]; } else if( path ) { std::string filename( [path UTF8String] ); rimage = new RImage; if( restoreRImageFromFile( *rimage, filename ) ) { rimageAdaptor = [[MPT_RimageAdaptor alloc] initWithRimage:rimage]; [pluginResults setObject:rimageAdaptor forKey:@"CERT.rimage"]; [rimageAdaptor release]; } else { delete rimage; rimage = NULL; } } if( rimage ) [self processRImageImp:rimage]; } - (void)processImage:(NSImage *)image fromPath:(NSString *)imagePath { [self clearResults]; RImage *rimage = [image rimageRep]; if( rimage ) { [pluginResults setObject:imagePath forKey:@"CERT.path"]; [self processRImageImp:rimage]; [grayImage release]; if( [self displayGray] ) { grayImage = [[NSImage imageFromRImage:rimage] retain]; } else grayImage = nil; delete rimage; } } - (void)processRImageFile:(NSString *)rimagePath { [self clearResults]; RImage rimage; std::string filename( [rimagePath UTF8String] ); if( restoreRImageFromFile( rimage, filename ) ) { [pluginResults setObject:rimagePath forKey:@"CERT.path"]; [self processRImageImp:&rimage]; [grayImage release]; if( [self displayGray] ) { grayImage = [[NSImage imageFromRImage:&rimage] retain]; } else grayImage = nil; } } - (void)processRImageAdaptor:(MPT_RimageAdaptor *)rimageAdaptor fromPath:(NSString *)imagePath { [self clearResults]; RImage *rimage = (RImage *)[rimageAdaptor rimage]; if( rimage ) { [pluginResults setObject:imagePath forKey:@"CERT.path"]; [self processRImageImp:rimage]; [grayImage release]; if( [self displayGray] ) { grayImage = [[NSImage imageFromRImage:rimage] retain]; } else grayImage = nil; } } - (void)processRImageImp:(RImage *)rimage { ObjectWithFeatures largestObject; FaceObject *largestFace = nil; // rimage->print( 5 ); if( [self findFaces] ) { try { OWFList objects; largestObject = [self findFaces:objects inRImage:*rimage]; } catch( ... ) { // Probably not much we can do, except possibly keep track of how many exceptions are thrown in what amount of time // and possibly warn the user if it happens too often NSLog( @"Exception thrown while trying to find eyes." ); return; } } // Criteria are eye x-positions are nonzero and at least 50 pix apart. // That criteria is really only for data sets, but we might want it to be a preference. if( (leftEye.x > 0) && (rightEye.x > 0) && ( (leftEye.x-rightEye.x) > 0) ) { NSArray *SVMPlugins = [myPlugins enabledPluginsForStep:MPT_PluginStep_SVM]; if( [SVMPlugins count] > 0 ) { // Before doing any CERT processing we should see if there are any enabled SVM plugins. RImage &lpatch = *((RImage *)patch); BOOL didRotate = false; OWFList allFaces; allFaces.push_back( largestObject ); // eyes_only, procrustes, unconstrained_least_squares FeatureAlignment::alignment_method method = static_cast([self alignmentMethod]); try { didRotate = ((MP_RotateFace *)rotator)->rotateImageUsingFeatures( ((EYEFINDER_CLASS *)mpeyefinder), rimage, allFaces, lpatch, method ); } catch( const char *msg ) { NSLog( @"%s", msg ); } catch( const std::exception &ex ) { NSLog( @"%s", ex.what() ); } catch(...) { NSLog( @"Unable to align face patch." ); } if( didRotate ) { [pluginResults setObject:[MPT_RimageAdaptor adaptorWithRimage:new RImage( lpatch )] forKey:@"CERT.patch"]; if( !gabor ) gabor = new GABOR_CLASS( lpatch, lpatch.width, lpatch.height ); else ((GABOR_CLASS *)gabor)->setPixels( lpatch ); ((GABOR_CLASS *)gabor)->CERT_Gabor(); // Collect results for each enabled plugin { NSEnumerator *pluginEnum = [SVMPlugins objectEnumerator]; while( id plugin = [pluginEnum nextObject] ) { std::vector resultsForCategory = ((GABOR_CLASS *)gabor)->resultsForCategory( [[plugin internalName] UTF8String] ); NSMutableDictionary *tmpResults = [NSMutableDictionary dictionary]; NSEnumerator *labelEnum = [[plugin labels] objectEnumerator]; NSString *label; unsigned int ind = 0; //NSAssert( (resultsForCategory.size() == [[plugin labels] count]), @"Mismatch between results and labels." ); while( label = [labelEnum nextObject] ) { [tmpResults setObject:[NSNumber numberWithDouble:resultsForCategory[ind++]] forKey:label]; } if( [plugin conformsToProtocol:@protocol(MPT_PluginProtocolSVM_Post)] ) tmpResults = [[[plugin postProcess:tmpResults] mutableCopy] autorelease]; [pluginResults setObject:tmpResults forKey:[plugin pluginID]]; } } // Get results for any plugins that need the gabor frequency data { NSArray *mlrPlugins = [myPlugins enabledPluginsForStep:MPT_PluginStep_Frequencies]; std::map< std::string, mp_AUResults > freqs = ((GABOR_CLASS *)gabor)->getFrequencies(); NSEnumerator *pluginEnum = [mlrPlugins objectEnumerator]; while( id plugin = [pluginEnum nextObject] ) { double mlrRes = 0.0; try { mlrRes = [plugin processFrequencyResults:freqs]; [pluginResults setObject:[NSNumber numberWithDouble:mlrRes] forKey:[plugin pluginID]]; } catch( std::exception &exc ) { NSLog( @"Unable to process frequency plugin '%@': %s", [plugin localizedName], exc.what() ); } } } if( [faceArray count] > 0 ) { // Get the points that define the rotated/cropped face CFourCoordinates faceCoords = ((MP_RotateFace *)rotator)->getFaceBox(); MPT_Face *firstFace = [faceArray objectAtIndex:0]; NSPoint aPoint1; NSPoint aPoint2; NSPoint aPoint3; NSPoint aPoint4; aPoint1.x = faceCoords.m_tx1; aPoint1.y = faceCoords.m_ty1; aPoint2.x = faceCoords.m_tx2; aPoint2.y = faceCoords.m_ty2; aPoint3.x = faceCoords.m_tx3; aPoint3.y = faceCoords.m_ty3; aPoint4.x = faceCoords.m_tx4; aPoint4.y = faceCoords.m_ty4; [firstFace setPoints:[NSArray arrayWithObjects:NSStringFromPoint(aPoint1), NSStringFromPoint(aPoint2), NSStringFromPoint(aPoint3), NSStringFromPoint(aPoint4), nil]]; } } } FaceObject tempFace; if( [faceArray count] > 0 ) { EYEFINDER_CLASS::FaceFromObject( tempFace, largestObject ); largestFace = &tempFace; } if( largestFace ) { EyeFaceList largestFaceList; NSArray *facePlugins = [myPlugins enabledPluginsForStep:MPT_PluginStep_AfterFaces]; NSEnumerator *pluginEnum = [facePlugins objectEnumerator]; largestFaceList.push_back( *largestFace ); while( id plugin = [pluginEnum nextObject] ) { largestFaceList.begin()->activation = 0.0; id res = NULL; //if( [plugin respondsToSelector:@selector(processFace:fromFeatureDetector:withImage:)] ) if( [plugin conformsToProtocol:@protocol(MPT_PluginProtocolFD)] ) { res = [plugin processFace:largestObject fromFeatureDetector:(EYEFINDER_CLASS *)mpeyefinder withImage:*rimage]; } else { res = [plugin processFaces:largestFaceList fromEyefinder:(EYEFINDER_CLASS *)mpeyefinder withImage:*rimage]; } if( res ) [pluginResults setObject:res forKey:[plugin pluginID]]; } // Add the facefinder results [pluginResults setObject:[NSString stringWithFormat:@"{x:%.0lf, y:%.0lf, width:%.0lf, height:%.0lf, scale:%.0lf}", largestFace->x, largestFace->y, largestFace->xSize, largestFace->ySize, largestFace->scale] forKey:@"edu.ucsd.mplab.plugins.FaceFinderStub"]; } } else { // No face found } [pluginResults setObject:faceArray forKey:@"CERT.faces"]; // This had to be moved to MPT_AUAppDelegate so that images would be post processed in the proper order // MPT_PluginController *pluginController = [MPT_PluginController defaultController]; // NSEnumerator *pluginEnum = [[myPlugins enabledPluginsForStep:MPT_PluginStep_Results] objectEnumerator]; // id plugin; // while( plugin = [pluginEnum nextObject] ) // { // NSMutableDictionary *postProc = [plugin processResults:pluginResults usingController:pluginController]; // if( postProc && ([postProc count] > 0) ) // [pluginResults setObject:postProc forKey:[plugin pluginID]]; // } } - (ObjectWithFeatures)findFaces:(OWFList &)objects inRImage:(RImage &)rimage { //bool foundRotatedFace = false; // Square face( 333, 212, 114, 10 ); // ((EYEFINDER_CLASS *)mpeyefinder)->setTrackedFace( face ); [featureLock lock]; ((EYEFINDER_CLASS *)mpeyefinder)->findAllFaces( rimage, false ); [featureLock unlock]; objects = ((EYEFINDER_CLASS *)mpeyefinder)->allFaces(); ObjectWithFeatures largestObject; #ifdef USING_ROTATING_EYEFINDER // if( [self multipleRotations] && (0 == objects.size()) ) // { // ((mp_rotatingEyefinder *)rotatingEyefinder)->findRotatedEyes( rimage, objects ); // // if( objects.size() > 0 ) // { // rimage = ((mp_rotatingEyefinder *)rotatingEyefinder)->getBestImage(); //// foundRotatedFace = true; // NSLog( @"Best Angle: %f", ((mp_rotatingEyefinder *)rotatingEyefinder)->getBestAngle() ); // } // } #endif double largestArea = 0.0; for( OWFList::iterator faceIter = objects.begin(), last_face = objects.end(); faceIter != last_face; ++faceIter ) { NSRect faceRect = NSMakeRect( faceIter->x, faceIter->y, faceIter->xSize, faceIter->ySize ); MPT_Face *mptFace = [[MPT_Face alloc] initWithFace:faceRect]; bool isLargest(false); [faceArray addObject:mptFace]; [mptFace release]; double faceArea = faceIter->xSize * faceIter->ySize; if( faceArea > largestArea ) { if( (faceIter->x >= 0.0) && (faceIter->y >= 0.0) ) { // face = faceRect; // face.origin.x = faceIter->x; // face.origin.y = faceIter->y; // face.size.width = faceIter->xSize; // face.size.height = faceIter->ySize; largestObject = *faceIter; largestArea = faceArea; isLargest = true; } } // loop through all of the features // make a feature object from each and add it to the face // also set the leftEye and rightEye member variables. for( std::vector::iterator featureIter = faceIter->finalBestFeature.begin(), lastFeature = faceIter->finalBestFeature.end(); featureIter != lastFeature; ++featureIter ) { NSString *type = [NSString stringWithCString:featureIter->type.c_str()]; NSPoint loc = NSMakePoint( featureIter->x, featureIter->y); MPT_Feature *feature = [MPT_Feature featureOfType:type AtLocation:loc]; [mptFace addFeature:feature]; id plugin = [featuresByName objectForKey:type]; if( plugin ) { [pluginResults setObject:NSStringFromPoint(loc) forKey:[plugin pluginID]]; [feature setColor:[plugin displayColor]]; } else { // Walk through all the feature plugins to see if any of them handle it. Usually this will be a Feature Processor plugin. NSArray *plugins = [[MPT_PluginController defaultController] pluginsForStep:MPT_PluginStep_Features]; NSEnumerator *pluginEnum = [plugins objectEnumerator]; MPT_FeatureBase *plugin; while( (plugin = [pluginEnum nextObject]) && [plugin respondsToSelector:@selector(labelForFeatureType:)] ) { NSString *label = [plugin performSelector:@selector(labelForFeatureType:) withObject:type]; if( [label length] > 0 ) { NSMutableDictionary *impResults = [pluginResults objectForKey:[plugin pluginID]]; if( !impResults ) { impResults = [NSMutableDictionary dictionary]; [pluginResults setObject:impResults forKey:[plugin pluginID]]; } [impResults setObject:NSStringFromPoint(loc) forKey:label]; } } } if( isLargest ) { if( [type isEqualToString:@"left_eye"] ) { leftEye = loc; } else if( [type isEqualToString:@"right_eye"] ) { rightEye = loc; } } } // if we have a feature processor, get it's processedFeatures map and create MPT_Features for the new locations. } return largestObject; } - (NSMutableDictionary *)pluginResults { return pluginResults; } - (NSImage *)grayImage { return grayImage; } - (NSImage *)patchImage { return [NSImage imageFromRImage:(RImage *)patch]; } - (NSImage *)videoImage { return videoImage; } - (NSPoint)left { return leftEye; } - (NSPoint)right { return rightEye; } - (NSArray *)faces { if( [faceArray count] > 0 ) return faceArray; else return nil; } - (MPT_Face *)findLargestFace { MPT_Face *largest = nil; float area = 0.0; NSEnumerator *faceEnum = [faceArray objectEnumerator]; MPT_Face *aFace; while( aFace = [faceEnum nextObject] ) { NSRect faceRect = [aFace face]; float faceArea = faceRect.size.width * faceRect.size.height; if( faceArea > area ) { largest = aFace; area = faceArea; } } return largest; } - (void)clearResults { leftEye = NSMakePoint( -1.0, -1.0 ); rightEye = leftEye; [pluginResults release]; pluginResults = [[NSMutableDictionary alloc] init]; [faceArray release]; faceArray = [[NSMutableArray alloc] init]; } - (void)setDoingSequence:(BOOL)seq { ((EYEFINDER_CLASS *)mpeyefinder)->setUseSequence( false ); } - (BOOL)doingSequence { return [prefs boolForKey:@"useSequence"]; } - (BOOL)findFaces { return [prefs boolForKey:@"findFaces"]; } - (BOOL)displayGray { return [prefs boolForKey:@"displayGray"]; } - (unsigned int)alignmentMethod { int method = [prefs integerForKey:@"alignmentMethod"]; if( (method < FeatureAlignment::begin_methods) || (method >= FeatureAlignment::end_methods) ) return FeatureAlignment::begin_methods; return method; } - (FeatureAlignment::FeatureAveraging *)FAFromDictionary:(NSDictionary *)dict { FeatureAlignment::FeatureAveraging::featureList list; NSEnumerator *keyEnum = [[dict allKeys] objectEnumerator]; NSString *key; while( key = [keyEnum nextObject] ) { std::vector< std::string > flist; NSArray *feats = [dict objectForKey:key]; NSEnumerator *featEnum = [feats objectEnumerator]; NSString *feat; while( feat = [featEnum nextObject] ) { flist.push_back( [feat UTF8String] ); } if( flist.size() > 0 ) list.push_back( FeatureAlignment::FeatureAveraging::featureListPair( [key UTF8String], flist ) ); } if( list.size() > 0 ) return new FeatureAlignment::FeatureAveraging( list ); else return nil; } - (void)featureAveragingChanged:(NSNotification *)notification { [self featureAveragingChanged_imp:[notification object]]; } - (void)featureAveragingChanged_imp:(id)faplugin { if( [faplugin enabled] && [faplugin respondsToSelector:@selector(generateSetup)]) { FeatureAlignment::FeatureAveraging *avg = [self FAFromDictionary:[faplugin performSelector:@selector(generateSetup)]]; ((EYEFINDER_CLASS *)mpeyefinder)->setFeatureProcessor( avg ); } else { ((EYEFINDER_CLASS *)mpeyefinder)->setFeatureProcessor( nil ); } } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if( [keyPath isEqualToString:@"useSequence"] ) { [self setDoingSequence:[[change objectForKey:NSKeyValueChangeNewKey] boolValue]]; } else if( [keyPath isEqualToString:@"eyefinderOffset"] ) { [self setEyefinderOffset:[[change objectForKey:NSKeyValueChangeNewKey] boolValue]]; } else if( [keyPath isEqualToString:@"eyefinderDropoff"] ) { [self setEyefinderDropoff:[[change objectForKey:NSKeyValueChangeNewKey] boolValue]]; } else if( [keyPath isEqualToString:@"windowMinScale"] ) { [self setMinScale:[[change objectForKey:NSKeyValueChangeNewKey] intValue]]; } else if( [keyPath isEqualToString:@"windowMaxScale"] ) { [self setMaxScale:[[change objectForKey:NSKeyValueChangeNewKey] intValue]]; } // // be sure to call the super implementation // // if the superclass implements it // [super observeValueForKeyPath:keyPath // ofObject:object // change:change // context:context]; } - (float)eyefinderOffset { return [prefs floatForKey:@"eyefinderOffset"]; } + (float)defaultEyefinderOffset { return 1.0f; // cascadeThreshAdjustor::default_cascade_adjust[0]; } - (void)setEyefinderOffset:(float)value { ((EYEFINDER_CLASS *)mpeyefinder)->setCascadeThresholds( value, [self eyefinderDropoff] ); } - (float)eyefinderDropoff { return [prefs floatForKey:@"eyefinderDropoff"]; } + (float)defaultEyefinderDropoff { return 1.0f; // cascadeThreshAdjustor::default_cascade_adjust[1]; } - (void)setEyefinderDropoff:(float)value { ((EYEFINDER_CLASS *)mpeyefinder)->setCascadeThresholds( [self eyefinderOffset], value ); } - (int)minScale { return [prefs floatForKey:@"windowMinScale"]; } - (void)setMinScale:(int)value { ((EYEFINDER_CLASS *)mpeyefinder)->setMinScale( value ); } - (int)maxScale { return [prefs floatForKey:@"windowMaxScale"]; } - (void)setMaxScale:(int)value { ((EYEFINDER_CLASS *)mpeyefinder)->setMaxScale( value ); } - (BOOL)multipleRotations { return [prefs boolForKey:@"multipleRotations"]; } - (BOOL)inputIsFaces { return inputIsFaces; } - (void)setInputIsFaces:(BOOL)value { inputIsFaces = value; } - (void)pluginChangedNotification:(NSNotification *)notification { id plugin = [[notification userInfo] objectForKey:@"plugin"]; [self pluginStateHasChanged:plugin]; } /** One or more plugins has had their enabled state changed. * We need to let the gabor processor know which SVM plugins are still enabled. * We also need to update the enabled state of any copies in myPlugins. */ - (void)pluginStateHasChanged:(id)plugin { if( plugin ) { if( MPT_PluginStep_SVM == [plugin step] ) { std::string name( [[plugin internalName] UTF8String] ); if( [plugin enabled] ) { ((GABOR_CLASS *)gabor)->addCategory( name ); } else { ((GABOR_CLASS *)gabor)->removeCategory( name ); } } else if( MPT_PluginStep_Features == [plugin step] ) { // If this is a special feature plugin (like MPT_FeatureAveraging), don't bother reloading all of the features // if( ([[plugin featureDataFile] length] > 0) && ([[plugin gpriorFile] length] > 0) ) if( [plugin gprior] && [plugin featuredata] ) [self loadFeaturePlugins]; } id myPlugin = [myPlugins pluginForPluginID:[plugin pluginID]]; [myPlugin setEnabled:[plugin enabled]]; } else { std::vector< std::string > categories; NSArray *plugins = [[MPT_PluginController defaultController] pluginsForStep:MPT_PluginStep_SVM]; NSEnumerator *pluginEnum = [plugins objectEnumerator]; id aplugin; while( aplugin = [pluginEnum nextObject] ) { if( [aplugin enabled] ) { std::string name( [[aplugin internalName] UTF8String] ); categories.push_back(name); } } ((GABOR_CLASS *)gabor)->setCategories( categories ); [self loadFeaturePlugins]; } } - (BOOL)loadFeaturePlugins { NSArray *plugins = [[MPT_PluginController defaultController] pluginsForStep:MPT_PluginStep_Features]; NSEnumerator *pluginEnum = [plugins objectEnumerator]; MPT_FeatureBase *plugin; [featureLock lock]; ((EYEFINDER_CLASS *)mpeyefinder)->clearFeatures(); [featuresByName removeAllObjects]; while( plugin = [pluginEnum nextObject] ) { [featuresByName setObject:plugin forKey:[plugin internalName]]; if( [plugin enabled] ) { Gprior *gp = (Gprior *)[plugin gprior]; FeatureData *fd = (FeatureData *)[plugin featuredata]; if( gp && fd ) { ((EYEFINDER_CLASS *)mpeyefinder)->addFeatureAndGprior( *fd, *gp ); } // NSString *weights = [plugin featureDataFile]; // NSString *priors = [plugin gpriorFile]; // if( ([weights length] > 0) && ([priors length] > 0) ) // { // ((EYEFINDER_CLASS *)mpeyefinder)->loadFeatureFromFiles( [weights UTF8String], [priors UTF8String] ); // } } } [featureLock unlock]; return YES; } - (void)makeThreadsafe { myPlugins = [MPT_PluginController copyForProcessing]; featureLock = [[NSLock alloc] init]; } // This method is no longer being used. - (void)rotateImage:(RImage *)rimage into:(RImage *)destImage byRadians:(float)rad { // source image vImage_Buffer vImgSrc = {(void*)rimage->array, rimage->height, rimage->width, rimage->width*sizeof(float)}; // destination image vImage_Buffer vImgDst = {(void*)destImage->array, destImage->height, destImage->width, destImage->width*sizeof(float)}; Pixel_F black = 0.0; vImageRotate_PlanarF( &vImgSrc, &vImgDst, NULL, rad, black, (kvImageBackgroundColorFill | kvImageHighQualityResampling) ); } - (BOOL)savePatchToFile:(NSString *)path; { bool res = false; if( [path length] > 0 ) { RImage &patchRef = *((RImage *)patch); std::string filename( [path UTF8String] ); res = saveRImageToFile( patchRef, filename ); } return res; } @end