36

我一直在努力让 AVFoundation 相机以正确的方向(即设备方向)捕捉图片,但我无法让它工作。

我看过教程,看过 WWDC 演示文稿并下载了 WWDC 示例程序,但即使这样也没有。

我的应用程序的代码是...

AVCaptureConnection *videoConnection = [CameraVC connectionWithMediaType:AVMediaTypeVideo fromConnections:[imageCaptureOutput connections]];
if ([videoConnection isVideoOrientationSupported])
{
    [videoConnection setVideoOrientation:[UIApplication sharedApplication].statusBarOrientation];
}

[imageCaptureOutput captureStillImageAsynchronouslyFromConnection:videoConnection
                                                completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error)
{
    if (imageDataSampleBuffer != NULL)
    {
        //NSLog(@"%d", screenOrientation);

        //CMSetAttachment(imageDataSampleBuffer, kCGImagePropertyOrientation, [NSString stringWithFormat:@"%d", screenOrientation], 0);

        NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
        UIImage *image = [[UIImage alloc] initWithData:imageData];

        [self processImage:image];
    }
}];

(processImage 使用与 WWDC 代码相同的 writeImage... 方法)

来自 WWDC 应用程序的代码是......

AVCaptureConnection *videoConnection = [AVCamDemoCaptureManager connectionWithMediaType:AVMediaTypeVideo fromConnections:[[self stillImageOutput] connections]];
        if ([videoConnection isVideoOrientationSupported]) {
            [videoConnection setVideoOrientation:AVCaptureVideoOrientationPortrait];
        }

[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:videoConnection
                                                             completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
                                                                 if (imageDataSampleBuffer != NULL) {
                                                                     NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
                                                                     UIImage *image = [[UIImage alloc] initWithData:imageData];                                                                 
                                                                     ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
                                                                     [library writeImageToSavedPhotosAlbum:[image CGImage]
                                                                                               orientation:(ALAssetOrientation)[image imageOrientation]
                                                                                           completionBlock:^(NSURL *assetURL, NSError *error){
                                                                                               if (error) {
                                                                                                   id delegate = [self delegate];
                                                                                                   if ([delegate respondsToSelector:@selector(captureStillImageFailedWithError:)]) {
                                                                                                       [delegate captureStillImageFailedWithError:error];
                                                                                                   }                                                                                               
                                                                                               }
                                                                                           }];
                                                                     [library release];
                                                                     [image release];
                                                                 } else if (error) {
                                                                     id delegate = [self delegate];
                                                                     if ([delegate respondsToSelector:@selector(captureStillImageFailedWithError:)]) {
                                                                         [delegate captureStillImageFailedWithError:error];
                                                                     }
                                                                 }
                                                             }];

在他们的代码开始时,他们将 AVOrientation 设置为 Portrait,这看起来很奇怪,但我试图让它检测设备的当前方向并使用它。

如您所见,我已将 [UIApplication sharedApplication]statusBarOrientation 放入尝试获取此信息,但它仍然仅将照片保存为纵向。

任何人都可以就我需要做的事情提供任何帮助或建议吗?

谢谢!

奥利弗

4

12 回答 12

46

好吧,这让我永远水力压裂,但我做到了!

我正在寻找的代码是

[UIDevice currentDevice].orientation;

这是这样的

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

而且效果很好:D

呜呜呜!

于 2010-09-07T22:16:23.100 回答
14

这不是更干净一点吗?

    AVCaptureVideoOrientation newOrientation;
    switch ([[UIDevice currentDevice] orientation]) {
    case UIDeviceOrientationPortrait:
        newOrientation = AVCaptureVideoOrientationPortrait;
        break;
    case UIDeviceOrientationPortraitUpsideDown:
        newOrientation = AVCaptureVideoOrientationPortraitUpsideDown;
        break;
    case UIDeviceOrientationLandscapeLeft:
        newOrientation = AVCaptureVideoOrientationLandscapeRight;
        break;
    case UIDeviceOrientationLandscapeRight:
        newOrientation = AVCaptureVideoOrientationLandscapeLeft;
        break;
    default:
        newOrientation = AVCaptureVideoOrientationPortrait;
    }
    [stillConnection setVideoOrientation: newOrientation];
于 2013-09-19T15:54:13.313 回答
11

以下来自 AVCam,我也添加了它:

- (void)deviceOrientationDidChange{

    UIDeviceOrientation deviceOrientation = [[UIDevice currentDevice] orientation];

    AVCaptureVideoOrientation newOrientation;

    if (deviceOrientation == UIDeviceOrientationPortrait){
        NSLog(@"deviceOrientationDidChange - Portrait");
        newOrientation = AVCaptureVideoOrientationPortrait;
    }
    else if (deviceOrientation == UIDeviceOrientationPortraitUpsideDown){
        NSLog(@"deviceOrientationDidChange - UpsideDown");
        newOrientation = AVCaptureVideoOrientationPortraitUpsideDown;
    }

    // AVCapture and UIDevice have opposite meanings for landscape left and right (AVCapture orientation is the same as UIInterfaceOrientation)
    else if (deviceOrientation == UIDeviceOrientationLandscapeLeft){
        NSLog(@"deviceOrientationDidChange - LandscapeLeft");
        newOrientation = AVCaptureVideoOrientationLandscapeRight;
    }
    else if (deviceOrientation == UIDeviceOrientationLandscapeRight){
        NSLog(@"deviceOrientationDidChange - LandscapeRight");
        newOrientation = AVCaptureVideoOrientationLandscapeLeft;
    }

    else if (deviceOrientation == UIDeviceOrientationUnknown){
        NSLog(@"deviceOrientationDidChange - Unknown ");
        newOrientation = AVCaptureVideoOrientationPortrait;
    }

    else{
        NSLog(@"deviceOrientationDidChange - Face Up or Down");
        newOrientation = AVCaptureVideoOrientationPortrait;
    }

    [self setOrientation:newOrientation];
}

并确保将其添加到您的 init 方法中:

NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[notificationCenter addObserver:self
    selector:@selector(deviceOrientationDidChange) 
    name:UIDeviceOrientationDidChangeNotification object:nil];
[self setOrientation:AVCaptureVideoOrientationPortrait];
于 2011-06-13T20:35:14.263 回答
4

有两件事需要注意

a) 正如 Brian King 所写 - LandscapeRight 和 LandscapeLeft 在枚举中交换。请参阅 AVCamCaptureManager 示例:

// AVCapture and UIDevice have opposite meanings for landscape left and right (AVCapture orientation is the same as UIInterfaceOrientation)
else if (deviceOrientation == UIDeviceOrientationLandscapeLeft)
    orientation = AVCaptureVideoOrientationLandscapeRight;
else if (deviceOrientation == UIDeviceOrientationLandscapeRight)
    orientation = AVCaptureVideoOrientationLandscapeLeft;

b) 还有一些规定UIDeviceOrientationFaceUpUIDeviceOrientationFaceDown如果您尝试设置为视频方向,您的视频将无法录制。打电话时请确保不要使用它们[UIDevice currentDevice].orientation

于 2011-04-20T15:11:04.750 回答
3

如果您使用的是 AVCaptureVideoPreviewLayer,您可以在视图控制器中执行以下操作。

(假设您有一个名为“previewLayer”的 AVCaptureVideoPreviewLayer 实例)

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
   [self.previewLayer setOrientation:[[UIDevice currentDevice] orientation]];
}
于 2012-02-14T21:34:44.113 回答
3

在开始捕获会话后以及每当设备旋转时更新预览层中的方向。

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    coordinator.animate(alongsideTransition: { [weak self] context in
        if let connection = self?.previewLayer?.connection, connection.isVideoOrientationSupported {
            if let orientation = AVCaptureVideoOrientation(orientation: UIDevice.current.orientation) {
                connection.videoOrientation = orientation
            }
        }
    }, completion: nil)
    super.viewWillTransition(to: size, with: coordinator)
}

extension AVCaptureVideoOrientation {
    init?(orientation: UIDeviceOrientation) {
        switch orientation {
        case .landscapeRight: self = .landscapeLeft
        case .landscapeLeft: self = .landscapeRight
        case .portrait: self = .portrait
        case .portraitUpsideDown: self = .portraitUpsideDown
        default: return nil
        }
    }
}
于 2018-12-21T09:15:25.337 回答
2

我正在用 Swift 编写这段代码,以防有人需要。

步骤 1:生成方向通知(在您的viewDidLoad

    UIDevice.currentDevice().beginGeneratingDeviceOrientationNotifications()
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("deviceOrientationDidChange:"), name: UIDeviceOrientationDidChangeNotification, object: nil)

第二步:拍照。在这里,我们将交换 的方向videoConnection。在 AVFoundation 中,方向有微小的变化,尤其是横向方向。所以我们将交换它。例如,我们将从LandscapeRightto更改为LandscapeLeft,反之亦然

  func takePicture() {
if let videoConnection = stillImageOutput!.connectionWithMediaType(AVMediaTypeVideo) {

    var newOrientation: AVCaptureVideoOrientation?
    switch (UIDevice.currentDevice().orientation) {
    case .Portrait:
        newOrientation = .Portrait
        break
    case .PortraitUpsideDown:
        newOrientation = .PortraitUpsideDown
        break
    case .LandscapeLeft:
        newOrientation = .LandscapeRight
        break
    case .LandscapeRight:
        newOrientation = .LandscapeLeft
        break
    default :
        newOrientation = .Portrait
        break

    }
    videoConnection.videoOrientation = newOrientation!


  stillImageOutput!.captureStillImageAsynchronouslyFromConnection(videoConnection) {
    (imageDataSampleBuffer, error) -> Void in

    let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer)

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {

      dispatch_async(dispatch_get_main_queue()) {

        let image = UIImage(data: imageData!)!
        let portraitImage = image.fixOrientation()


      }
    }


  }
}

  }

注意:请注意横向方向的新方向值。它恰恰相反。(这是罪魁祸首::UHHHH)

第 3 步:修复方向(UIImage 扩展)

extension UIImage {

func fixOrientation() -> UIImage {

    if imageOrientation == UIImageOrientation.Up {
        return self
    }

    var transform: CGAffineTransform = CGAffineTransformIdentity

    switch imageOrientation {
    case UIImageOrientation.Down, UIImageOrientation.DownMirrored:
        transform = CGAffineTransformTranslate(transform, size.width, size.height)
        transform = CGAffineTransformRotate(transform, CGFloat(M_PI))
        break
    case UIImageOrientation.Left, UIImageOrientation.LeftMirrored:
        transform = CGAffineTransformTranslate(transform, size.width, 0)
        transform = CGAffineTransformRotate(transform, CGFloat(M_PI_2))
        break
    case UIImageOrientation.Right, UIImageOrientation.RightMirrored:
        transform = CGAffineTransformTranslate(transform, 0, size.height)
        transform = CGAffineTransformRotate(transform, CGFloat(-M_PI_2))
        break
    case UIImageOrientation.Up, UIImageOrientation.UpMirrored:
        break
    }

    switch imageOrientation {
    case UIImageOrientation.UpMirrored, UIImageOrientation.DownMirrored:
        CGAffineTransformTranslate(transform, size.width, 0)
        CGAffineTransformScale(transform, -1, 1)
        break
    case UIImageOrientation.LeftMirrored, UIImageOrientation.RightMirrored:
        CGAffineTransformTranslate(transform, size.height, 0)
        CGAffineTransformScale(transform, -1, 1)
    case UIImageOrientation.Up, UIImageOrientation.Down, UIImageOrientation.Left, UIImageOrientation.Right:
        break
    }

    let ctx: CGContextRef = CGBitmapContextCreate(nil, Int(size.width), Int(size.height), CGImageGetBitsPerComponent(CGImage), 0, CGImageGetColorSpace(CGImage), CGImageAlphaInfo.PremultipliedLast.rawValue)!

    CGContextConcatCTM(ctx, transform)

    switch imageOrientation {
    case UIImageOrientation.Left, UIImageOrientation.LeftMirrored, UIImageOrientation.Right, UIImageOrientation.RightMirrored:
        CGContextDrawImage(ctx, CGRectMake(0, 0, size.height, size.width), CGImage)
        break
    default:
        CGContextDrawImage(ctx, CGRectMake(0, 0, size.width, size.height), CGImage)
        break
    }

    let cgImage: CGImageRef = CGBitmapContextCreateImage(ctx)!

    return UIImage(CGImage: cgImage)
}


   }
于 2016-05-24T07:48:49.240 回答
1

这使用视图控制器的方向方法。这对我有用,希望对你有用。

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];

    AVCaptureConnection *videoConnection = self.prevLayer.connection;
    [videoConnection setVideoOrientation:(AVCaptureVideoOrientation)toInterfaceOrientation];
}
于 2014-03-12T12:35:32.553 回答
1

在 Swift 中你应该这样做:

    videoOutput = AVCaptureVideoDataOutput()
    videoOutput!.setSampleBufferDelegate(self, queue: dispatch_queue_create("sample buffer delegate", DISPATCH_QUEUE_SERIAL))

    if captureSession!.canAddOutput(self.videoOutput) {
        captureSession!.addOutput(self.videoOutput)
    }

    videoOutput!.connectionWithMediaType(AVMediaTypeVideo).videoOrientation = AVCaptureVideoOrientation.PortraitUpsideDown

它非常适合我!

于 2015-11-27T18:46:03.740 回答
1

斯威夫特 4 和斯威夫特 5。

开始了:

private var requests = [VNRequest]()
let exifOrientation = exifOrientationFromDeviceOrientation()
let imageRequestHandler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, orientation: exifOrientation, options: [:])
do {
  try imageRequestHandler.perform(self.requests)
} catch {
  print(error)
}

public func exifOrientationFromDeviceOrientation() -> CGImagePropertyOrientation {
    let curDeviceOrientation = UIDevice.current.orientation
    let exifOrientation: CGImagePropertyOrientation

    switch curDeviceOrientation {
    case UIDeviceOrientation.portraitUpsideDown:  // Device oriented vertically, home button on the top
        exifOrientation = .upMirrored
    case UIDeviceOrientation.landscapeLeft:       // Device oriented horizontally, home button on the right
        exifOrientation = .left
    case UIDeviceOrientation.landscapeRight:      // Device oriented horizontally, home button on the left
        exifOrientation = .right
    case UIDeviceOrientation.portrait:            // Device oriented vertically, home button on the bottom
        exifOrientation = .up
    default:
        exifOrientation = .up
    }
    return exifOrientation
}
于 2019-11-18T05:48:28.423 回答
0

您还可以创建一个中间 CIImage,并获取属性字典

NSDictionary *propDict = [aCIImage properties];
NSString *orientString = [propDict objectForKey:kCGImagePropertyOrientation];

并相应地转换:)

我喜欢在 iOS5 中访问所有这些图像元数据是多么容易!

于 2012-01-17T15:20:53.383 回答
-1

如何与 AVCaptureFileOutput 一起使用?

- (void)detectVideoOrientation:(AVCaptureFileOutput *)captureOutput {
    for(int i = 0; i < [[captureOutput connections] count]; i++) {
        AVCaptureConnection *captureConnection = [[captureOutput connections] objectAtIndex:i];
        if([captureConnection isVideoOrientationSupported]) {
            [captureConnection setVideoOrientation:[[UIDevice currentDevice] orientation]];
        }
    }
}
于 2010-09-13T10:12:52.900 回答