禁用不是人像AVFoundation其他任何方向拍摄的图像(Disable taking image

2019-08-16 20:00发布

我使用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;

Answer 1:

这是基于我对你的问题(从你有其他的答案不同)的了解了部分答案。

您已锁定为纵向的应用程序。 因此,状态栏始终在手机的顶部肖像无论手机的方向。 这成功地锁定您的接口,包括您的AVCapture接口。 但你也想锁定从相机的原始图像饲料,使图像地平线总是与状态栏平行。

这将非常需要连续进行-所以,如果你有摄像头在45度角的图像会适得其反旋转45度。 否则,大多数时候,图像将无法正确对齐(另一种方法是,它始终是脱节的,直到你90degree方向开关的更新,这将转体图像90度)。

要做到这一点,你需要使用核心运动和加速度计。 你想拿到手机的Y轴为真垂直的角度,并相应地旋转图像。 看到这里的几何细节:

iPhone方向-如何找出哪个方向是向上?

使用核心运动,触发从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;

         }];
    }
}

一个 b C

举行(一)肖像电话; (b)中旋转30度〜; (三)景观

您可能会发现这是一个有点神经质,而且还有几分设备的移动和视图之间的滞后。 你可以用updateInterval玩,并与其他核心运动挂羊头卖狗肉,以抑制运动更深得到。 ( 我还没有处理的手机确切地说是倒挂的情况下,如果你按住相机面朝下或面朝上,其结果是不确定的 固定更新的代码/使用atan2 )。

现在的方向是正确合理的,但你的形象不适合你的看法。 没有很多可以做这为原料摄像头输入的格式由物理尺寸,它的传感器阵列固定。 解决办法是让你在各个角度足够的多余的图像数据,使您可以裁剪图像,以适应你想要的肖像格式来缩放图像。

无论是在界面生成器:

  • 设定previewLayer的视图正方形围绕它的上海华,具有宽度和高度等于该对角线上的可视图像的区域(SQRT(宽度2 +高度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中引用正确的观点。

现在,当你拍照,你会捕捉整个从相机阵列“原始”的图像数据,这将是横向格式的。 它将被保存与屏幕旋转的方向标志。 但你可能想要的是将照片保存为屏幕上看到的。 这意味着,你将不得不旋转,裁剪照片保存前以符合您的屏幕上查看和删除它的方向元数据。 这对你的工作了(即“部分答案”的其他部分):我怀疑你可能会觉得这整个的做法并没有得到你想要的东西(我想你很想被摄像机传感器硬件对设备的旋转-rotates保持稳定的地平线)。

更新
改变startAccelerometerUpdates从中获取角度atan2代替acos ,顺畅,考虑到各个方向的不摆弄

更新2
从您的意见,似乎你的旋转预览层卡住? 我不能复制你的错误,那一定是在你的代码或设置其他一些地方。

所以,你可以用干净的代码检查,我增加了我的解决方案为苹果的AVCam项目 ,这样你就可以检查它对抗。 这里是做什么的:

  • 加上核心运动框架AVCam。

在AVCamViewController.m

  • #import <CoreMotion/CoreMotion.h>
  • 加我startAccelerometerUpdates方法
  • 加我resizeCameraView方法(坚持这两种方法附近的类文件的顶部,或者你可能会感到困惑,也有不止一个@implementation在那只文件)
  • 添加一行: [self resizeCameraView];viewDidLoad (它可以是该方法的第一行)
  • 添加属性
    @property (strong, nonatomic) CMMotionManager* coreMotionManager
    在@interface(它并不需要是一个财产,但我的方法假定它的存在,所以如果你不加它,你将不得不修改我的方法来代替)。

startAccelerometerUpdates改变这一行:

    self.previewLayer.transform = rotate;  

至:

    self.captureVideoPreviewLayer.transform = rotate;

同样,在对象列表AVCamViewController.xib ,移动工具栏(否则,当你放大你覆盖控件)以上的videoPreview查看

一定要禁用转 - 适用于iOS <6.0,这已经是事实,但为6.0+,你需要在目标总结支撑取向只选择肖像。

我认为这是我对AVCam所做的更改的完整列表,旋转/定向所有工作得很好。 我建议你尝试这样做。 如果你能得到这个工作的顺利开展,你知道有你的代码中的一些其他故障的地方。 如果你仍然觉得你的旋转坚持,我会好奇地想知道更多关于你的硬件和软件环境,如哪些设备正在测试你的。

我在编译4.6的XCode / OSX10.8.2和测试上:

- iPhone4S  /  iOS5.1  
- iPhone3G  /  iOS6.1  
- iPad mini /  iOS6.1 

所有的结果都是平稳和准确。



Answer 2:

我猜你需要用这个方法来限制摄像机旋转。

AVCaptureConnection *videoConnection = [CameraVC connectionWithMediaType:AVMediaTypeVideo fromConnections:[imageCaptureOutput connections]];
if ([videoConnection isVideoOrientationSupported])
{
    [videoConnection setVideoOrientation:[UIDevice currentDevice].orientation];
}

假设您的预览层定义为属性,可以使用

[self.previewLayer setOrientation:[[UIDevice currentDevice] orientation]];

你的情况,你可以取代[的UIDevice currentDevice]取向]由UIInterfaceOrientationPortrait

编辑

尝试添加预览层当你真正需要它。 例

preview = [[self videoPreviewWithFrame:CGRectMake(0, 0, 320, 480)] retain];
[self.view addSubview:preview];

该videoPreviewWithFrame功能。

- (UIView *) videoPreviewWithFrame:(CGRect) frame 
{
  AVCaptureVideoPreviewLayer *tempPreviewLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:[self captureSession]];
  [tempPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
  tempPreviewLayer.frame = frame;

  UIView* tempView = [[UIView alloc] init];
  [tempView.layer addSublayer:tempPreviewLayer];
  tempView.frame = frame;

  [tempPreviewLayer autorelease];
  [tempView autorelease];
  return tempView;
}


Answer 3:

假设你previewlayer被添加到一个视图控制器视图。 在执行此操作viewDidLoad

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];

并定义选择为:

- (void)orientationChanged:(NSNotification*)notification {
    UIInterfaceOrientation interfaceOrientation = [UIApplication sharedApplication].statusBarOrientation;
    if ([self.previewlayer respondsToSelector:@selector(orientation)]) {
        //for iOS5
        if (interfaceOrientation != UIInterfaceOrientationPortrait) {
            self.previewlayer.orientation = (AVCaptureVideoOrientation)UIInterfaceOrientationPortrait;
        }
    } else {
        //for iOS6
        if (interfaceOrientation != UIInterfaceOrientationPortrait) {
            self.previewlayer.connection.videoOrientation = (AVCaptureVideoOrientation)UIInterfaceOrientationPortrait;
        }
    }
}

注意:tempPreviewLayer在属性self.previewlayer

这将预览层强制纵向位置当设备方向变化。

编辑

您还可以在乌拉圭回合“的的viewController的shouldAutoRotate`方法添加此

    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
    {
        // Return YES for supported orientations
        if ([self.previewlayer respondsToSelector:@selector(orientation)]) {
            if (interfaceOrientation != UIInterfaceOrientationPortrait) {
                self.previewlayer.orientation = (AVCaptureVideoOrientation)UIInterfaceOrientationPortrait;
            }
        } else {
            if (interfaceOrientation != UIInterfaceOrientationPortrait) {
                self.previewlayer.connection.videoOrientation = (AVCaptureVideoOrientation)UIInterfaceOrientationPortrait;
            }
        }

        return (interfaceOrientation == UIInterfaceOrientationPortrait);
    }

为iOS6的乘坐过这两个检查。

-(NSUInteger)supportedInterfaceOrientations {
    //UIInterfaceOrientation interfaceOrientation = [UIApplication sharedApplication].statusBarOrientation;
    //return (
    //interfaceOrientation == UIInterfaceOrientationLandscapeLeft |
    //interfaceOrientation == UIInterfaceOrientationLandscapeRight);
    return UIInterfaceOrientationMaskLandscape;//(UIInterfaceOrientationLandscapeLeft | UIInterfaceOrientationLandscapeRight);
}

- (BOOL)shouldAutorotate {
    return YES;
}

return在这两种方法中apend,我给通知的代码..和,看看它,当你roate设备调用。



文章来源: Disable taking images in any orientation other than Portrait AVFoundation