Обнаружение лица в UIImage

Я пытаюсь написать процедуру, которая принимает UIImage и возвращает новый UIImage, содержащий только лицо. Это может показаться очень простым, но у моего мозга проблемы с тем, чтобы обойти пространства CoreImage и UIImage.

Вот основы:

- (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;
}

Изображение, которое возвращается, является перевернутым изображением. Я попытался настроить faceFeature.bounds, используя что-то вроде этого:

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

... но это дает мне результаты за пределами изображения.

Я уверен, что есть что-то простое, чтобы исправить это, но, если не считать вычисления снизу-вниз, а затем создания нового прямоугольника, используя его как X, есть ли «правильный» способ сделать это?

Спасибо!


person Tim Sullivan    schedule 23.02.2012    source источник


Ответы (3)


Гораздо проще и менее запутанно просто использовать CIContext, чтобы вырезать свое лицо из изображения. Что-то вроде этого:

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

Где inputImage — ваш объект UIImage, а объект faceFeature имеет тип CIFaceFeature, который вы получаете из метода [CIDetector featuresInImage:].

person jlajlar    schedule 02.07.2013

Поскольку простого способа сделать это не существует, я просто написал код для этого:

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);

Это сработало.

person Tim Sullivan    schedule 23.02.2012
comment
Я изучаю то же самое, не могли бы вы объяснить расчет, который вы выполнили для оси Y, пожалуйста? А что такое «крупнейшее лицо»? - person Rory Lester; 20.08.2012

Простого способа добиться этого нет, проблема в том, что изображения с камеры iPhone всегда в портретном режиме, а для корректного их отображения используются настройки метаданных. Вы также повысите точность вызова при обнаружении лиц, если заранее сообщите ему поворот изображения. Просто чтобы все усложнить, вы должны передать ему ориентацию изображения в формате EXIF.

К счастью, есть пример проекта Apple, который охватывает все это, под названием Squarecam, я предлагаю вам проверить подробности

person Tark    schedule 23.02.2012
comment
Да, я уже приспосабливаюсь к вращению изображения. Моя проблема связана с разным происхождением UIImage и подпрограмм CG. - person Tim Sullivan; 24.02.2012