AVFoundation 照片大小和旋转

Posted

技术标签:

【中文标题】AVFoundation 照片大小和旋转【英文标题】:AVFoundation photo size and rotation 【发布时间】:2014-01-11 11:13:09 【问题描述】:

我正经历着噩梦般的时光,试图将使用 AVFoundation captureStillImageAsynchronouslyFromConnection 拍摄的照片校正为屏幕上显示的大小和方向。

我用这段代码显示AVCaptureVideoPreviewLayer,以确保它在所有旋转中显示正确的方式:

previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.captureSession];
[previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
previewLayer.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height);
if ([[previewLayer connection] isVideoOrientationSupported])

    [[previewLayer connection] setVideoOrientation:(AVCaptureVideoOrientation)[UIApplication sharedApplication].statusBarOrientation];

[self.view.layer insertSublayer:previewLayer atIndex:0];

现在,当我有一个返回的图像时,它需要裁剪,因为它比显示的要大得多。 我知道有很多 UIImage 裁剪示例,但我似乎遇到的第一个障碍是找到正确的 CGRect 来使用。当我简单地裁剪到 self.view.frame 时,图像被裁剪到错误的位置。

预览使用AVLayerVideoGravityResizeAspectFill,我的UIImageView也设置为AspectFill

那么我怎样才能从预览层获得AVFoundation 在屏幕上显示的正确帧?

编辑----

这是我面临的问题的一个示例。使用 iPad Mini 的前置摄像头,摄像头使用分辨率 720x1280,但显示屏为 768x0124。视图显示了这一点(参见图片顶部的墙板:

然后当我拍摄图像并显示它时,它看起来像这样:

显然相机显示在视图的中心,但裁剪后的图像是从照片的顶部(看不到)部分拍摄的。

【问题讨论】:

【参考方案1】:

我现在正在做一个类似的项目,如果你还没有弄清楚的话,我想我可能会提供帮助。

我似乎遇到的第一个障碍是找到要使用的正确 CGRect。当我简单地裁剪到 self.view.frame 时,图像被裁剪在错误的位置。

假设您的图片为 720x1280,并且您希望将图片裁剪为显示器的矩形,即尺寸为 768x1024 的 CGRect。你不能只传递一个大小为 768x1024 的矩形。首先,您的图像不是 768 像素宽。其次,您需要指定该矩形相对于图像的位置(即通过指定矩形的原点)。在您的示例中,self.view.frame 是一个原点为 (0, 0) 的 CGRect。这就是为什么它总是从图像的顶部而不是从中心裁剪。

计算裁剪矩形有点棘手,因为您有几个不同的坐标系。

您已经获得了视图控制器的视图,它具有... ...一个视频预览层作为子层,它正在显示一个方面填充的图像,但是... ...AVCaptureOutput 返回一个UIImage,它不仅具有与视频预览不同的宽度/高度,而且还具有不同的纵横比。

因此,由于您的预览层显示的是居中且裁剪后的预览图像(即方面填充),因此您基本上想要找到的是 CGRect

显示比例与self.view.bounds相同 具有与UIImage 的较小尺寸相同的较小尺寸(即方面适合) 以UIImage为中心

所以是这样的:

// Determine the width:height ratio of the crop rect, based on self.bounds
CGFloat widthToHeightRatio = self.bounds.size.width / self.bounds.size.height;
CGRect cropRect;
// Set the crop rect's smaller dimension to match the image's smaller dimension, and
// scale its other dimension according to the width:height ratio.
if (image.size.width < image.size.height) 
    cropRect.size.width = image.size.width;
    cropRect.size.height = cropRect.size.width / widthToHeightRatio;
 else 
    cropRect.size.width = image.size.height * widthToHeightRatio;
    cropRect.size.height = image.size.height;

// Center the rect in the longer dimension
if (cropRect.size.width < cropRect.size.height) 
    cropRect.origin.x = 0;
    cropRect.origin.y = (image.size.height - cropRect.size.height) / 2.0;
 else 
    cropRect.origin.x = (image.size.width - cropRect.size.width) / 2.0;
    cropRect.origin.y = 0;

最后,回到图像为 720x1280 的原始示例,并且您希望将图像裁剪为 768x1024 的显示矩形,您最终将得到一个大小为 720x960 的 CGRect,其x 的原点 = 0,y = 1280-960/2 = 160。

【讨论】:

Richard,我刚刚花了 2 天时间尝试解决同样的问题,同时拍摄一张预览层占据屏幕顶部 50% 的照片,然后裁剪图像的确切部分在预览中可见。在浏览了 SO 上的每个裁剪线程之后,您的线程是唯一一个可以完美运行的线程。谢谢。 有一件事,由于某种原因,我的“cropRect.origin.y”和“cropRect.origin.x”都得到0值,但奇怪的是,如果我用NSLog它们打印一个值714 所以我不得不手动将该数字输入到最终的 CGRectMake 中。除此之外,您的代码运行良好。 酷!乐意效劳。那段代码是我为了演示该技术而临时编写的,所以如果你得到一些古怪的结果,我并不感到惊讶。很高兴你设法绕过它! 它与除以 2 有关。我可以将它提供给 NSLog 正确的值,但实际方法不能正确除以 2。我是 Objective-c 和一般编程的新手,但这可能只是一个简单的修复。不管怎样,我不是在开玩笑。我花了 2 天时间试图弄清楚这一点,并不断收到诸如“裁剪图像”之类的回复。人们只是不明白,所以再次感谢您提供此代码。

以上是关于AVFoundation 照片大小和旋转的主要内容,如果未能解决你的问题,请参考以下文章

保存旋转的图片(swift3)

如何根据设备方向制作横向或纵向照片[重复]

如何在 iphone 中使用 avFoundation 像 Instagram 应用一样拍摄方形照片?

使用AVFoundation完成照片拍摄存储相册, 开启关闭闪光灯, 切换摄像头

AVFoundation 将第一帧添加到视频

使用 AVFoundation 裁剪视频