Ответ 1
Вот частичный ответ, основанный на моем понимании вашего вопроса (который отличается от других ответов, которые у вас были).
У вас приложение заблокировано для портретной ориентации. Таким образом, строка состояния всегда находится на верхней части телефона, независимо от ориентации телефона. Это успешно блокирует ваш интерфейс, включая интерфейс AVCapture. Но вы также хотите заблокировать подачу необработанного изображения с камеры, чтобы горизонт изображения всегда был параллелен строке состояния.
Это в идеале нужно делать непрерывно, так что, если у вас есть камера под углом 45 градусов, изображение будет вращаться на 45 градусов. В противном случае, в большинстве случаев изображение не будет правильно выровнено (альтернативой является то, что он всегда выходит за линию, пока не изменится ваш переключатель ориентации на 90 градусов, который повернет изображение на 90 градусов).
Для этого вам нужно использовать Core Motion и акселерометр. Вы хотите, чтобы угол Y по оси Y был верным и повернул изображение соответствующим образом. См. Здесь подробности геометрии:
Ориентация iPhone - как определить, какой путь вверх?
Используя Core Motion, вызовите этот метод из viewDidLoad
- (void)startAccelerometerUpdates {
self.coreMotionManager = [[CMMotionManager alloc] init];
if ([self.coreMotionManager isAccelerometerAvailable] == YES) {
CGFloat updateInterval = 0.1;
// Assign the update interval to the motion manager
[self.coreMotionManager setAccelerometerUpdateInterval:updateInterval];
[self.coreMotionManager startAccelerometerUpdatesToQueue:[NSOperationQueue mainQueue]
withHandler: ^(CMAccelerometerData *accelerometerData, NSError *error) {
CGFloat angle = -atan2( accelerometerData.acceleration.x,
accelerometerData.acceleration.y)
+ M_PI ;
CATransform3D rotate = CATransform3DMakeRotation(angle, 0, 0, 1);
self.previewLayer.transform = rotate;
}];
}
}
a
b
c
телефон (a) портрет; (b) вращение ~ 30deg; (c) пейзаж
,
Вы можете обнаружить, что это немного нерешительно, и между движением устройства и представлением наблюдается некоторое отставание. Вы можете играть с обновлениемInterval и углубляться в другие трюки Core Motion, чтобы ослабить движение. ( Я не рассматривал случай, когда телефон был точно перевернут, и если вы держите камеру лицевой стороной вниз или лицом вверх, результат undefined исправлен с обновленным кодом/использованием atan2
).
Теперь ориентация достаточно правильная, но ваше изображение не соответствует вашему представлению. Существует не так много, что вы можете сделать по этому поводу, так как формат подачи необработанной камеры фиксируется физическими размерами его сенсорной матрицы. Обходной путь - увеличить изображение, чтобы у вас было достаточно избыточных данных изображения под всеми углами, чтобы вы могли обрезать изображение в соответствии с желаемым форматом портрета.
Либо в Interface Builder:
- установите для параметра previewLayer значение квадрата с центром над ним, с шириной и высотой, равной диагонали области видимого изображения (sqrt (ширина 2 + height 2))
Или в коде:
- (void)resizeCameraView
{
CGSize size = self. videoPreviewView.bounds.size;
CGFloat diagonal = sqrt(pow(size.width,2)+pow(size.height,2));
diagonal = 2*ceil(diagonal/2); //rounding
self.videoPreviewView.bounds = (CGRect){0,0,diagonal,diagonal};
}
Если вы сделаете это в коде, resizeCameraView
должен работать, если вы вызываете его из viewDidLoad
. Убедитесь, что self.videoPreviewView
соответствует вашей ссылке IBOutlet на правильный вид.
Теперь, когда вы делаете снимок, вы будете захватывать все "сырые" данные изображения из массива камеры, которые будут в альбомном формате. Он будет сохранен с флагом ориентации для поворота изображения. Но вы можете захотеть сохранить фотографию, как показано на экране. Это означает, что вам нужно будет повернуть и обрезать фотографию в соответствии с вашим экранным представлением перед ее сохранением и удалить ее метаданные ориентации. Это для вас, чтобы выработать (другая часть "частичного ответа" ): я подозреваю, что вы можете решить, что весь этот подход не дает вам то, что вы хотите (я думаю, что вам действительно понравится датчик камеры, что аппаратное обеспечение -ротаты против вращения устройства, чтобы поддерживать стабильность горизонта).
Обновление
изменил startAccelerometerUpdates
, чтобы получить угол от atan2
вместо acos
, более плавный и учитывающий все направления без возиться
обновить 2
Из ваших комментариев кажется, что ваш вращающийся слой предварительного просмотра застревает? Я не могу воспроизвести вашу ошибку, это должно быть какое-то другое место в вашем коде или настройках.
Чтобы вы могли проверить с помощью чистого кода, я добавил свое решение в проект Apple AVCam, поэтому вы можете проверить его на это. Вот что делать:
- добавьте структуру Core Motion в AVCam.
В AVCamViewController.m
-
#import <CoreMotion/CoreMotion.h>
- добавить мой метод
startAccelerometerUpdates
- добавьте мой метод
resizeCameraView
(придерживайтесь обоих этих методов в верхней части файла класса или вы можете запутаться, в этом файле более одного@implementation
) - добавьте строку:
[self resizeCameraView];
вviewDidLoad
(это может быть первая строка метода) - добавить свойство
@property (strong, nonatomic) CMMotionManager* coreMotionManager
на @interface (это не должно быть свойство, но мой метод предполагает, что он существует, поэтому, если вы его не добавите, вам придется изменить мой метод).
В startAccelerometerUpdates
измените эту строку:
self.previewLayer.transform = rotate;
to:
self.captureVideoPreviewLayer.transform = rotate;
также в списке объектов в AVCamViewController.xib
переместите представление VideoPreview над панелью инструментов (в противном случае при его увеличении вы будете закрывать элементы управления)
Обязательно отключите вращения - для iOS и 6.0, это уже верно, но для 6.0+ вам нужно выбрать только портрет в поддерживаемых ориентациях в сводке цели.
Я думаю, что это полный список изменений, которые я внес в AVCam, и поворот/ориентация - все работает очень хорошо. Я предлагаю вам попробовать сделать то же самое. Если вы можете заставить это работать плавно, вы знаете, что где-то есть какой-то другой глюк. Если вы все еще найдете свои повороты, мне было бы интересно узнать больше о вашей аппаратной и программной среде, например о том, какие устройства вы тестируете.
Я компилирую на XCode 4.6/OSX10.8.2 и тестирую на:
- iPhone4S / iOS5.1
- iPhone3G / iOS6.1
- iPad mini / iOS6.1
Все результаты являются гладкими и точными.