Modyfikuję przykładową aplikację do wykrywania twarzy Apple SquareCam, dzięki czemu wykadruje twarz przed zapisaniem na rolce aparatu, zamiast rysować czerwony kwadrat wokół twarzy. Używam tego samego CGRect, aby wykonać kadrowanie, które było używane do rysowania czerwonego kwadratu. Jednak zachowanie jest inne. W trybie portretowym, jeśli twarz znajduje się w środkowej części ekranu, kadruje twarz zgodnie z oczekiwaniami (to samo miejsce, w którym znajdowałby się czerwony kwadrat). Jeśli twarz jest przesunięta w lewo lub w prawo, plon wydaje się być zawsze pobierany ze środka ekranu zamiast miejsca, w którym znajdowałby się czerwony kwadrat.Przycinanie do twarzy z wykrywaniem twarzy
Oto jabłka Kod oryginalny:
- (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;
}
i moja wymiana:
- (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;
}
Aktualizacja *
oparciu o wkład Wains, starałem się zrobić mój kod bardziej jak oryginał, ale wynik był sama:
- (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;
}
Wziąłem trzy zdjęcia i zalogowany faceRect z tych wyników;
Zdjęcie zrobione z twarzą umieszczoną w pobliżu lewej krawędzi urządzenia. Przechwytywanie obrazu całkowicie strzela twarz w prawo: faceRect = {{972, 43,0312}, {673,312, 673,312}}
Pic zrobione z twarzy umieszczonej w środku urządzenia. Obraz przechwytywania jest dobry: faceRect = {{106,59, 536.625}, {68,25, 668.25}}
Zdjęcie zrobione z twarzą umieszczoną w pobliżu prawej krawędzi urządzenia. Przechwytywanie obrazu całkowicie strzela twarz lewej: faceRect = {{982,125, 999,844}, {804,938, 804,938}}
Wygląda więc na to, że "x" i "y" są odwrócone. Trzymam urządzenie w pozycji pionowej, ale faceRect wydaje się być oparty na pejzażu. Jednak nie mogę się dowiedzieć, jaka część oryginalnego kodu Jabłek wyjaśnia to. Kod orientacji w tej metodzie wydaje się wpływać tylko na sam obraz na czerwonym kwadracie.
Czy spróbować moją odpowiedź, ale wciąż widzę problemów? – Wain