Преобразование результатов CGPoint, возвращенных из CIFaceFeature

Я пытаюсь понять, как преобразовать результаты CGPoint, возвращенные из CIFaceFeature, чтобы рисовать с ними в CALayer. Раньше я нормализовал свое изображение, чтобы оно имело 0 поворотов, чтобы упростить задачу, но это вызывает проблемы с изображениями, снятыми на устройстве, находящемся в ландшафтном режиме.

Я безуспешно работал над этим какое-то время, и я не уверен, что мое понимание задачи неверно, или мой подход неверен, или и то, и другое. Вот что я считаю правильным:

исходное изображение с камеры

Согласно документации по методу CIDetector featuresInImage:options:

A dictionary that specifies the orientation of the image. The detection is 
adjusted to account for the image orientation but the coordinates in the 
returned feature objects are based on those of the image.

изображение, отображаемое в UIImageView

В приведенном ниже коде я пытаюсь повернуть CGPoint, чтобы нарисовать его через слой CAShape, который перекрывает UIImageView.

То, что я делаю (... или думаю, что делаю...), - это перевод точки CGPoint левого глаза в центр изображения, поворот на 90 градусов, а затем перевод точки обратно туда, где она была. Это неправильно, но я не знаю, где я ошибаюсь. Это мой подход неправильный или способ, которым я его реализую?

#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI)

-- leftEyePosition является CGPoint

CGAffineTransform  transRot = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(90));

float x = self.center.x;
float y = self.center.y;
CGAffineTransform tCenter = CGAffineTransformMakeTranslation(-x, -y);
CGAffineTransform tOffset = CGAffineTransformMakeTranslation(x, y);

leftEyePosition = CGPointApplyAffineTransform(leftEyePosition, tCenter);
leftEyePosition = CGPointApplyAffineTransform(leftEyePosition, transRot);
leftEyePosition = CGPointApplyAffineTransform(leftEyePosition, tOffset);

Из этого сообщения: https://stackoverflow.com/a/14491293/840992 мне нужно сделать повороты на основе изображениеОриентация

Ориентация

Apple/UIImage.imageOrientation Jpeg/файл kCGImagePropertyOrientation

UIImageOrientationUp    = 0  =  Landscape left  = 1
UIImageOrientationDown  = 1  =  Landscape right = 3
UIImageOrientationLeft  = 2  =  Portrait  down  = 8
UIImageOrientationRight = 3  =  Portrait  up    = 6

Сообщение было отредактировано skinnyTOD 01.02.13 в 16:09.


person spring    schedule 01.02.2013    source источник


Ответы (2)


Мне нужно разобраться с точно такой же проблемой. Образец Apple «SquareCam» работает непосредственно с видеовыходом, но мне нужны результаты из еще UIImage. Поэтому я расширил класс CIFaceFeature некоторыми методами преобразования, чтобы получить правильные местоположения и границы точек по отношению к UIImage и его UIImageView (или CALayer UIView). Полная реализация размещена здесь: https://gist.github.com/laoyang/5747004. Вы можете использовать напрямую.

Вот самое простое преобразование точки из CIFaceFeature, возвращаемый CGPoint преобразуется на основе ориентации изображения:

- (CGPoint) pointForImage:(UIImage*) image fromPoint:(CGPoint) originalPoint {

    CGFloat imageWidth = image.size.width;
    CGFloat imageHeight = image.size.height;

    CGPoint convertedPoint;

    switch (image.imageOrientation) {
        case UIImageOrientationUp:
            convertedPoint.x = originalPoint.x;
            convertedPoint.y = imageHeight - originalPoint.y;
            break;
        case UIImageOrientationDown:
            convertedPoint.x = imageWidth - originalPoint.x;
            convertedPoint.y = originalPoint.y;
            break;
        case UIImageOrientationLeft:
            convertedPoint.x = imageWidth - originalPoint.y;
            convertedPoint.y = imageHeight - originalPoint.x;
            break;
        case UIImageOrientationRight:
            convertedPoint.x = originalPoint.y;
            convertedPoint.y = originalPoint.x;
            break;
        case UIImageOrientationUpMirrored:
            convertedPoint.x = imageWidth - originalPoint.x;
            convertedPoint.y = imageHeight - originalPoint.y;
            break;
        case UIImageOrientationDownMirrored:
            convertedPoint.x = originalPoint.x;
            convertedPoint.y = originalPoint.y;
            break;
        case UIImageOrientationLeftMirrored:
            convertedPoint.x = imageWidth - originalPoint.y;
            convertedPoint.y = originalPoint.x;
            break;
        case UIImageOrientationRightMirrored:
            convertedPoint.x = originalPoint.y;
            convertedPoint.y = imageHeight - originalPoint.x;
            break;
        default:
            break;
    }
    return convertedPoint;
}

И вот методы категории, основанные на приведенном выше преобразовании:

// Get converted features with respect to the imageOrientation property
- (CGPoint) leftEyePositionForImage:(UIImage *)image;
- (CGPoint) rightEyePositionForImage:(UIImage *)image;
- (CGPoint) mouthPositionForImage:(UIImage *)image;
- (CGRect) boundsForImage:(UIImage *)image;

// Get normalized features (0-1) with respect to the imageOrientation property
- (CGPoint) normalizedLeftEyePositionForImage:(UIImage *)image;
- (CGPoint) normalizedRightEyePositionForImage:(UIImage *)image;
- (CGPoint) normalizedMouthPositionForImage:(UIImage *)image;
- (CGRect) normalizedBoundsForImage:(UIImage *)image;

// Get feature location inside of a given UIView size with respect to the imageOrientation property
- (CGPoint) leftEyePositionForImage:(UIImage *)image inView:(CGSize)viewSize;
- (CGPoint) rightEyePositionForImage:(UIImage *)image inView:(CGSize)viewSize;
- (CGPoint) mouthPositionForImage:(UIImage *)image inView:(CGSize)viewSize;
- (CGRect) boundsForImage:(UIImage *)image inView:(CGSize)viewSize;

(Еще одна вещь, которую нужно отметить, это указание правильной ориентации EXIF ​​при извлечении функций лица из ориентации UIImage. Довольно запутанно... вот что я сделал:

int exifOrientation;
switch (self.image.imageOrientation) {
    case UIImageOrientationUp:
        exifOrientation = 1;
        break;
    case UIImageOrientationDown:
        exifOrientation = 3;
        break;
    case UIImageOrientationLeft:
        exifOrientation = 8;
        break;
    case UIImageOrientationRight:
        exifOrientation = 6;
        break;
    case UIImageOrientationUpMirrored:
        exifOrientation = 2;
        break;
    case UIImageOrientationDownMirrored:
        exifOrientation = 4;
        break;
    case UIImageOrientationLeftMirrored:
        exifOrientation = 5;
        break;
    case UIImageOrientationRightMirrored:
        exifOrientation = 7;
        break;
    default:
        break;
}

NSDictionary *detectorOptions = @{ CIDetectorAccuracy : CIDetectorAccuracyHigh };
CIDetector *faceDetector = [CIDetector detectorOfType:CIDetectorTypeFace context:nil options:detectorOptions];

NSArray *features = [faceDetector featuresInImage:[CIImage imageWithCGImage:self.image.CGImage]
                                          options:@{CIDetectorImageOrientation:[NSNumber numberWithInt:exifOrientation]}];

)

person X.Y.    schedule 10.06.2013

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

Можете ли вы попробовать с этим преобразованием:

CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformTranslate(transform, 0.0f, image.size.height);
transform = CGAffineTransformScale(transform, 1.0f, -1.0f);
[path applyTransform:transform];

Это преобразование работает только в том случае, если мы установили для image.imageOrientation значение 0 перед поиском лиц.

person foundry    schedule 01.02.2013
comment
Нет, не работает. Координаты нужно повернуть (я полагаю). Я добавил несколько изображений, чтобы показать, что я думаю о задаче. - person spring; 02.02.2013
comment
@skinnyTOD, извините, я ошибся - это преобразование работает, только если мы нормализуем (установим ориентацию на imageOrientation 0). Я опубликую обновление в ближайшее время - person foundry; 02.02.2013