从 AVCaptureSession 捕获的 iPhone 图像比例

Posted

技术标签:

【中文标题】从 AVCaptureSession 捕获的 iPhone 图像比例【英文标题】:iPhone image ratio captured from AVCaptureSession 【发布时间】:2012-01-10 08:15:49 【问题描述】:

我正在使用某人的源代码通过 AVCaptureSession 捕获图像。但是,我发现 CaptureSessionManager 的 previewLayer 比最终捕获的图像要好。

我发现结果图像的比例始终为 720x1280=9:16。现在我想将生成的图像裁剪为比例为 320:480 的 UIImage,这样它只会捕获 previewLayer 中可见的部分。任何的想法?非常感谢。

*** 中的相关问题(还没有好的答案): Q1, Q2

源代码:

- (id)init 
if ((self = [super init])) 
    [self setCaptureSession:[[[AVCaptureSession alloc] init] autorelease]];

return self;


- (void)addVideoPreviewLayer 
[self setPreviewLayer:[[[AVCaptureVideoPreviewLayer alloc] initWithSession:[self captureSession]] autorelease]];
[[self previewLayer] setVideoGravity:AVLayerVideoGravityResizeAspectFill];



- (void)addVideoInput 
AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];   
if (videoDevice) 
    NSError *error;


    if ([videoDevice isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus] && [videoDevice lockForConfiguration:&error]) 
        [videoDevice setFocusMode:AVCaptureFocusModeContinuousAutoFocus];
        [videoDevice unlockForConfiguration];
            

    AVCaptureDeviceInput *videoIn = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
    if (!error) 
        if ([[self captureSession] canAddInput:videoIn])
            [[self captureSession] addInput:videoIn];
        else
            NSLog(@"Couldn't add video input");     
    
    else
        NSLog(@"Couldn't create video input");

else
    NSLog(@"Couldn't create video capture device");


- (void)addStillImageOutput 

  [self setStillImageOutput:[[[AVCaptureStillImageOutput alloc] init] autorelease]];
  NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG,AVVideoCodecKey,nil];
  [[self stillImageOutput] setOutputSettings:outputSettings];

  AVCaptureConnection *videoConnection = nil;
  for (AVCaptureConnection *connection in [[self stillImageOutput] connections]) 
    for (AVCaptureInputPort *port in [connection inputPorts]) 
      if ([[port mediaType] isEqual:AVMediaTypeVideo] ) 
        videoConnection = connection;
        break;
      
    
    if (videoConnection)  
      break; 
    
  

  [[self captureSession] addOutput:[self stillImageOutput]];


- (void)captureStillImage
  
AVCaptureConnection *videoConnection = nil;
for (AVCaptureConnection *connection in [[self stillImageOutput] connections]) 
    for (AVCaptureInputPort *port in [connection inputPorts]) 
        if ([[port mediaType] isEqual:AVMediaTypeVideo]) 
            videoConnection = connection;
            break;
        
    
    if (videoConnection)  
  break; 



NSLog(@"about to request a capture from: %@", [self stillImageOutput]);
[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:videoConnection 
                                                   completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error)  
                                                     CFDictionaryRef exifAttachments = CMGetAttachment(imageSampleBuffer, kCGImagePropertyExifDictionary, NULL);
                                                     if (exifAttachments) 
                                                       NSLog(@"attachements: %@", exifAttachments);
                                                      else  
                                                       NSLog(@"no attachments");
                                                     
                                                     NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];    
                                                     UIImage *image = [[UIImage alloc] initWithData:imageData];
                                                     [self setStillImage:image];
                                                     [image release];
                                                     [[NSNotificationCenter defaultCenter] postNotificationName:kImageCapturedSuccessfully object:nil];
                                                   ];



在进行更多研究和测试后进行编辑: AVCaptureSession 的属性“sessionPreset”有以下几个常量,我没有逐一检查,但注意到大多数比例是 9:16 或 3:4,

NSString *const AVCaptureSessionPresetPhoto; NSString *const AVCaptureSessionPresetHigh; NSString *const AVCaptureSessionPresetMedium; NSString *const AVCaptureSessionPresetLow; NSString *const AVCaptureSessionPreset352x288; NSString *const AVCaptureSessionPreset640x480; NSString *const AVCaptureSessionPresetiFrame960x540; NSString *const AVCaptureSessionPreset1280x720; NSString *const AVCaptureSessionPresetiFrame1280x720;

在我的项目中,我有全屏预览(帧大小为 320x480) 还有:[[self previewLayer] setVideoGravity:AVLayerVideoGravityResizeAspectFill];

我是这样做的:拍摄尺寸为 9:16 的照片并将其裁剪为 320:480,正好是预览层的可见部分。看起来很完美。

调整大小和裁剪以替换旧代码的代码是

NSData *imageData = [AVCaptureStillImageOutput  jpegStillImageNSDataRepresentation:imageSampleBuffer];
 UIImage *image = [UIImage imageWithData:imageData]; 
UIImage *scaledimage=[ImageHelper scaleAndRotateImage:image];
 //going to crop the image 9:16 to 2:3;with Width fixed 
float width=scaledimage.size.width; 
float height=scaledimage.size.height; 
float top_adjust=(height-width*3/2.0)/2.0;  
[self setStillImage:[scaledimage croppedImage:rectToCrop]];

【问题讨论】:

为什么不使用 4:3-sessionPreset,这样就不必裁剪和使用整个摄像头传感器? 【参考方案1】:

iPhone 的摄像头本来就是 ​​4:3。您获得的 16:9 图像已经从 4:3 裁剪。将那些 16:9 的图像再次裁剪为 4:3 并不是您想要的。而是通过设置self.captureSession.sessionPreset = AVCaptureSessionPresetPhoto(在向会话添加任何输入/输出之前)从 iPhone 的相机中获取原生 4:3 图像。

【讨论】:

多米尼克,感谢您的回复。 iPhone Camera App底部有一个工具栏,预览比例为(480-44):320~=4:3=1.3333,在相册App中打开,貌似aspecttofill 480:320=1.50,所以实际上图片是失真的已经对了?但由于 1.333 与 1.50 差别不大,所以对用户来说看起来并不那么明显 是的,相册应用程序最初会动态裁剪图片(填充方面,无失真)以填充整个屏幕。但是通过捏合手势,您可以看到整个 4:3 画面。 确保测试会话是否支持 AVCaptureSessionPresetPhoto: if ([captureSession canSetSessionPreset: AVCaptureSessionPresetPhoto]) [captureSession setSessionPreset: AVCaptureSessionPresetPhoto]; 您好,我的问题是相反的。我们如何从相机以 16:9 的比例捕捉图像?有什么方法可以捕捉到这个(16:9)口粮的图像吗?

以上是关于从 AVCaptureSession 捕获的 iPhone 图像比例的主要内容,如果未能解决你的问题,请参考以下文章

如何正确释放 AVCaptureSession

AVCaptureSession 捕获图像横向模式

如何在 Swift 中使用 AVCaptureSession 捕获图片?

如何记录使用 AVCaptureSession 捕获的第一个和最后一个电影帧的确切时间?

从同一个 AVCaptureSession 拍摄视频和照片时应用程序崩溃?

从 Swift 中的 AVCaptureSession 获取输出以发送到服务器