2012-02-23 9 views
8

Sto provando a scrivere una routine che richiede una UIImage e restituisce una nuova UIImage che contiene solo la faccia. Questo sembra essere molto semplice, ma il mio cervello sta avendo problemi ad aggirare gli spazi CoreImage vs. UIImage.UIImage face detection

Ecco i principi fondamentali:

- (UIImage *)imageFromImage:(UIImage *)image inRect:(CGRect)rect { 
    CGImageRef sourceImageRef = [image CGImage]; 
    CGImageRef newImageRef = CGImageCreateWithImageInRect(sourceImageRef, rect); 
    UIImage *newImage = [UIImage imageWithCGImage:newImageRef]; 
    CGImageRelease(newImageRef); 
    return newImage; 
} 


-(UIImage *)getFaceImage:(UIImage *)picture { 
    CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeFace 
              context:nil 
              options:[NSDictionary dictionaryWithObject: CIDetectorAccuracyHigh forKey: CIDetectorAccuracy]]; 

    CIImage *ciImage = [CIImage imageWithCGImage: [picture CGImage]]; 
    NSArray *features = [detector featuresInImage:ciImage]; 

    // For simplicity, I'm grabbing the first one in this code sample, 
    // and we can all pretend that the photo has one face for sure. :-) 
    CIFaceFeature *faceFeature = [features objectAtIndex:0]; 

    return imageFromImage:picture inRect:faceFeature.bounds; 
} 

L'immagine che viene restituito è da l'immagine ribaltata. Ho provato a regolare faceFeature.bounds usando qualcosa di simile:

CGAffineTransform t = CGAffineTransformMakeScale(1.0f,-1.0f); 
CGRect newRect = CGRectApplyAffineTransform(faceFeature.bounds,t); 

... ma che dà i risultati all'esterno dell'immagine.

Sono sicuro che c'è qualcosa di semplice da risolvere, ma non calcolando il bottom-down e quindi creando un nuovo rect usando quello come X, c'è un modo "corretto" per farlo?

Grazie!

risposta

3

Dal momento non sembra essere un modo semplice per fare questo, ho appena scritto qualche codice per farlo:

CGRect newBounds = CGRectMake(faceFeature.bounds.origin.x, 
           _picture.size.height - faceFeature.bounds.origin.y - largestFace.bounds.size.height, 
           faceFeature.bounds.size.width, 
           faceFeature.bounds.size.height); 

Questo ha funzionato un fascino.

+5

Sto osservando la stessa cosa, potresti spiegare il calcolo eseguito per l'asse y per favore ?. E che cos'è il "più grande"? –

0

Non esiste un modo semplice per raggiungere questo obiettivo, il problema è che le immagini della fotocamera dell'iPhone sono sempre in modalità verticale e le impostazioni dei metadati vengono utilizzate per visualizzarle correttamente. Otterrai anche una maggiore precisione nella chiamata per il rilevamento del volto se pronunci prima la rotazione dell'immagine. Solo per complicare le cose, devi passare l'orientamento dell'immagine nel formato EXIF.

Fortunatamente c'è un progetto di esempio di Apple che copre tutto questo chiamato Squarecam, ti suggerisco di controllare per i dettagli

+0

Sì, sono già pronto per la rotazione dell'immagine. Il mio problema è legato alla diversa origine di UIImage e delle routine CG. –

5

È molto più semplice e meno complicato usare CIContext per ritagliare il tuo volto dall'immagine. Qualcosa di simile a questo:

CGImageRef cgImage = [_ciContext createCGImage:[CIImage imageWithCGImage:inputImage.CGImage] fromRect:faceFeature.bounds]; 
UIImage *croppedFace = [UIImage imageWithCGImage:cgImage]; 

Dove inputImage è l'oggetto UIImage e faceFeature oggetto è di tipo CIFaceFeature che si ottiene da [CIDetector featuresInImage:] metodo.