Dej*_*ell 12 iphone xcode objective-c avfoundation uideviceorientation
我AVFoundation用来显示相机.
我想防止相机本身旋转,这样观看者只能以纵向方式看到相机,而且图像只能以人像模式拍摄.
我定义Supported Interface Orientation为仅支持肖像,视图本身仅在纵向模式下显示,但不是相机 - 正在按设备方向旋转
如何强制AVFoundation显示相机并仅像UIViewController一样以纵向捕捉图像?
我设置相机的代码:
AVCaptureVideoPreviewLayer* lay = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.sess];
UIView *view = [self videoPreviewView];
CALayer *viewLayer = [view layer];
[viewLayer setMasksToBounds:YES];
CGRect bounds = [view bounds];
[lay setFrame:bounds];
if ([lay respondsToSelector:@selector(connection)])
{
if ([lay.connection isVideoOrientationSupported])
{
[lay.connection setVideoOrientation:AVCaptureVideoOrientationPortrait];
}
}
[lay setVideoGravity:AVLayerVideoGravityResizeAspectFill];
[viewLayer insertSublayer:lay below:[[viewLayer sublayers] objectAtIndex:0]];
self.previewLayer = lay;
Run Code Online (Sandbox Code Playgroud)
fou*_*dry 10
以下是基于我对您的问题的理解的部分答案(与您的其他答案不同).
您已将应用锁定为纵向方向.因此,无论手机的方向如何,状态栏始终位于手机的纵向顶部.这会成功锁定您的界面,包括AVCapture界面.但是您还希望锁定来自摄像机的原始图像馈送,以使图像范围始终与状态栏平行.
理想情况下,这需要连续进行 - 因此,如果摄像机处于45度角,则图像将反向旋转45度.否则,大多数时候,图像将无法正确对齐(另一种方法是,它始终是脱节的,直到你90degree方向开关的更新,这将转体图像90度).
为此,您需要使用Core Motion和加速度计.您希望将手机的Y轴角度设置为真垂直并相应地旋转图像.有关几何细节,请参见此处
使用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;
}];
}
}
Run Code Online (Sandbox Code Playgroud)
一个
b
C
![]()
电话持有(一)肖像; (b)旋转〜30度; (c)景观
.
你可能会发现这有点跳跃,设备运动和视图之间有一点滞后.您可以使用updateInterval,并深入了解其他Core Motion技巧以抑制移动.(我没有把手机的情况完全颠倒过来,如果你把相机面朝下或面朝上,结果是未定义的, 修改了更新的代码/使用atan2).
现在方向相当正确,但您的图像不适合您的视图.由于原始摄像机输入的格式由其传感器阵列的物理尺寸确定,因此您无法做很多事情.解决方法是缩放图像,以便在所有角度都有足够多的图像数据,以便裁剪图像以适合所需的纵向格式.
无论是在界面生成器:
或者在代码中:
- (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};
}
Run Code Online (Sandbox Code Playgroud)
如果你这样做的代码,resizeCameraView如果您从您的通话它应该工作viewDidLoad.确保这self.videoPreviewView是您对正确视图的IBOutlet引用.
现在,当您拍摄照片时,您将从相机的阵列中捕获整个"原始"图像数据,这些数据将采用横向格式.它将与方向标志一起保存以显示旋转.但您可能想要的是保存屏幕上显示的照片.这意味着在保存照片之前,您必须旋转并裁剪照片以匹配屏幕视图,并删除它的方向元数据.这是你要解决的问题("部分答案"的另一部分):我怀疑你可能会认为这整个方法无法满足你的需求(我认为你真正喜欢的是相机传感器那个硬件 - 防止设备旋转以保持地平线稳定).
更新
更改startAccelerometerUpdates为从而获得角度,atan2而不是acos更平滑,并考虑到所有方向而不是摆弄
更新2
从您的评论中,您的旋转预览图层似乎卡住了吗?我无法复制您的错误,它必须是您的代码或设置中的其他位置.
因此,您可以使用干净的代码进行检查,我已将我的解决方案添加到Apple的AVCam项目中,因此您可以对此进行检查.这是做什么的:
在AVCamViewController.m中
#import <CoreMotion/CoreMotion.h> startAccelerometerUpdates方法 resizeCameraView方法(将这两种方法都粘贴在类文件的顶部附近,否则你可能会感到困惑,@implementation该文件中有多个s) [self resizeCameraView];to viewDidLoad(它可以是方法的第一行) @property (strong, nonatomic) CMMotionManager* coreMotionManager在startAccelerometerUpdates改变这一行:
self.previewLayer.transform = rotate;
Run Code Online (Sandbox Code Playgroud)
至:
self.captureVideoPreviewLayer.transform = rotate;
Run Code Online (Sandbox Code Playgroud)
此外,在对象列表中AVCamViewController.xib,将videoPreview视图移动到ToolBar上方(否则当你放大它时,你会覆盖控件)
确保禁用旋转 - 对于iOS <6.0,已经是如此,但对于6.0+,您需要在目标摘要中选择仅支持方向的肖像.
我认为这是我对AVCam所做的更改的完整列表,并且旋转/方向都非常有效.我建议你尝试做同样的事情.如果你能让它顺利运行,你知道你的代码中还有其他一些小问题.如果您仍然发现您的轮换,我很想知道您的硬件和软件环境,例如您正在测试的设备.
我正在编译XCode 4.6/OSX10.8.2,并测试:
- iPhone4S / iOS5.1
- iPhone3G / iOS6.1
- iPad mini / iOS6.1
Run Code Online (Sandbox Code Playgroud)
所有结果都是平滑而准确的.
| 归档时间: |
|
| 查看次数: |
3032 次 |
| 最近记录: |