2013-06-24 4 views
6

Я изменяю приложение для определения лица Apple SquareCam, чтобы оно обрезало лицо перед записью в рулон камеры, вместо того, чтобы рисовать красный квадрат вокруг лица. Я использую тот же CGRect, чтобы сделать обрезку, как было использовано для рисования красного квадрата. Однако поведение отличается. В портретном режиме, если лицо находится в горизонтальном центре экрана, оно обрывает лицо, как ожидалось (то же самое место было бы красным квадратом). Если лицо выключено влево или вправо, урожай всегда берется из середины экрана, а не там, где был бы красный квадрат.Обрезать лицо с распознаванием лица

Вот яблоки исходный код:

- (CGImageRef)newSquareOverlayedImageForFeatures:(NSArray *)features 
              inCGImage:(CGImageRef)backgroundImage 
             withOrientation:(UIDeviceOrientation)orientation 
              frontFacing:(BOOL)isFrontFacing 
{ 
    CGImageRef returnImage = NULL; 
    CGRect backgroundImageRect = CGRectMake(0., 0., CGImageGetWidth(backgroundImage), CGImageGetHeight(backgroundImage)); 
    CGContextRef bitmapContext = CreateCGBitmapContextForSize(backgroundImageRect.size); 
    CGContextClearRect(bitmapContext, backgroundImageRect); 
    CGContextDrawImage(bitmapContext, backgroundImageRect, backgroundImage); 
    CGFloat rotationDegrees = 0.; 

    switch (orientation) { 
     case UIDeviceOrientationPortrait: 
      rotationDegrees = -90.; 
      break; 
     case UIDeviceOrientationPortraitUpsideDown: 
      rotationDegrees = 90.; 
      break; 
     case UIDeviceOrientationLandscapeLeft: 
      if (isFrontFacing) rotationDegrees = 180.; 
      else rotationDegrees = 0.; 
      break; 
     case UIDeviceOrientationLandscapeRight: 
      if (isFrontFacing) rotationDegrees = 0.; 
      else rotationDegrees = 180.; 
      break; 
     case UIDeviceOrientationFaceUp: 
     case UIDeviceOrientationFaceDown: 
     default: 
      break; // leave the layer in its last known orientation 
    } 
    UIImage *rotatedSquareImage = [square imageRotatedByDegrees:rotationDegrees]; 

    // features found by the face detector 
    for (CIFaceFeature *ff in features) { 
     CGRect faceRect = [ff bounds]; 
     NSLog(@"faceRect=%@", NSStringFromCGRect(faceRect)); 
     CGContextDrawImage(bitmapContext, faceRect, [rotatedSquareImage CGImage]); 
    } 
    returnImage = CGBitmapContextCreateImage(bitmapContext); 
    CGContextRelease (bitmapContext); 

    return returnImage; 
} 

и моя замена:

- (CGImageRef)newSquareOverlayedImageForFeatures:(NSArray *)features 
              inCGImage:(CGImageRef)backgroundImage 
             withOrientation:(UIDeviceOrientation)orientation 
              frontFacing:(BOOL)isFrontFacing 
{ 
    CGImageRef returnImage = NULL; 

    //I'm only taking pics with one face. This is just for testing 
    for (CIFaceFeature *ff in features) { 
     CGRect faceRect = [ff bounds]; 
     returnImage = CGImageCreateWithImageInRect(backgroundImage, faceRect); 
    } 

    return returnImage; 
} 

Update *

на основе ввода Wains, я пытался сделать мой код больше похож на оригинал, но результатом был то же самое:

- (NSArray*)extractFaceImages:(NSArray *)features 
       fromCGImage:(CGImageRef)sourceImage 
      withOrientation:(UIDeviceOrientation)orientation 
       frontFacing:(BOOL)isFrontFacing 
{ 
NSMutableArray *faceImages = [[[NSMutableArray alloc] initWithCapacity:1] autorelease]; 


CGImageRef returnImage = NULL; 
CGRect backgroundImageRect = CGRectMake(0., 0., CGImageGetWidth(sourceImage), CGImageGetHeight(sourceImage)); 
CGContextRef bitmapContext = CreateCGBitmapContextForSize(backgroundImageRect.size); 
CGContextClearRect(bitmapContext, backgroundImageRect); 
CGContextDrawImage(bitmapContext, backgroundImageRect, sourceImage); 
CGFloat rotationDegrees = 0.; 

switch (orientation) { 
    case UIDeviceOrientationPortrait: 
     rotationDegrees = -90.; 
     break; 
    case UIDeviceOrientationPortraitUpsideDown: 
     rotationDegrees = 90.; 
     break; 
    case UIDeviceOrientationLandscapeLeft: 
     if (isFrontFacing) rotationDegrees = 180.; 
     else rotationDegrees = 0.; 
     break; 
    case UIDeviceOrientationLandscapeRight: 
     if (isFrontFacing) rotationDegrees = 0.; 
     else rotationDegrees = 180.; 
     break; 
    case UIDeviceOrientationFaceUp: 
    case UIDeviceOrientationFaceDown: 
    default: 
     break; // leave the layer in its last known orientation 
} 

// features found by the face detector 
for (CIFaceFeature *ff in features) { 
    CGRect faceRect = [ff bounds]; 

    NSLog(@"faceRect=%@", NSStringFromCGRect(faceRect)); 

    returnImage = CGBitmapContextCreateImage(bitmapContext); 
    returnImage = CGImageCreateWithImageInRect(returnImage, faceRect); 
    UIImage *clippedFace = [UIImage imageWithCGImage:returnImage]; 
    [faceImages addObject:clippedFace]; 
} 

CGContextRelease (bitmapContext); 

return faceImages; 

}

Я взял три фотографии и вошли faceRect с этими результатами;

Снимок сделан с лицом, расположенным рядом с левым краем устройства. Захват изображения полностью пропускает лицо вправо: faceRect = {{972, 43.0312}, {673.312, 673.312}}

Снимок сделан с лицом, расположенным в середине устройства. Захват изображения хорош: faceRect = {{1060.59, 536.625}, {668.25, 668.25}}

Снимок сделан с лицом, расположенным вблизи правого края устройства. Захват изображения полностью пропускает лицо влево: faceRect = {{982.125, 999.844}, {804.938, 804.938}}

Таким образом, оказывается, что «x» и «y» меняются на противоположные. Я держу устройство на портрете, но faceRect похоже на ландшафт. Тем не менее, я не могу понять, какая часть исходного кода Яблоков учитывает это. Код ориентации в этом методе, по-видимому, влияет только на изображение с красным квадратом.

+0

ли вы попробовать мой ответ, но все еще видите проблемы? – Wain

ответ

3

Вы должны сохранить все исходный код и просто добавить одну строки до возвращения (с подстройкой поставить генерацию изображения внутри цикла, как вы только кадрирование первого лица):

returnImage = CGImageCreateWithImageInRect(returnImage, faceRect); 

Этих позволяет визуализировать изображение с правильной ориентацией, что означает, что лицевой прямоугольник будет в правильном месте.

+0

Ориентационная логика в исходном коде просто поворачивает изображение красного квадрата (squarePNG.png), так как в нем есть слова «верх» и «снизу», запеченные в изображении. Я не думаю, что это важно. Во всяком случае, я пытался сделать это больше похоже на исходный код, но результат тот же. Он работает только в том случае, если лицо находится непосредственно в (горизонтальной) середине устройства. – ax123man

+0

Вращение должно быть применено к изображению с камеры. После того, как вращение было применено, исходное изображение является «фиксированным», а затем вы можете применить прямую прямую. – Wain

0

Вы столкнулись с этой проблемой, поскольку, когда изображение сохраняется, оно сохраняется вертикально. А позиция faceRect точно не совпадает с лицом. Вы можете решить эту проблему, изменив poistion faceRect таким образом, чтобы он был вертикально перевернут в пределах returnImage.

for (CIFaceFeature *ff in features) { 
     faceRect = [ff bounds]; 
     CGRect modifiedRect = CGRectFlipVertical(faceRect,CGRectMake(0,0,CGImageGetWidth(returnImage),CGImageGetHeight(returnImage))); 
     returnImage = CGImageCreateWithImageInRect(returnImage, modifiedRect); 
     UIImage *clippedFace = [UIImage imageWithCGImage:returnImage]; 
     [faceImages addObject:clippedFace]; 
    } 

CGRectFlipVertical(CGRect innerRect, CGRect outerRect) может быть определен как так,

CGRect CGRectFlipVertical(CGRect innerRect, CGRect outerRect) 
    { 
     CGRect rect = innerRect; 
     rect.origin.y = outerRect.origin.y + outerRect.size.height - (rect.origin.y + rect.size.height); 
     return rect; 
    }