2

我正在尝试ARFrame使用以下方法从当前获取图像:

if let imageBuffer = sceneView.session.currentFrame?.capturedImage {
    let orientation = UIApplication.shared.statusBarOrientation
    let viewportSize = sceneView.bounds.size
    let transformation = sceneView.session.currentFrame?.displayTransform(for: orientation, viewportSize: viewportSize)

    let ciImage = CIImage(cvPixelBuffer: imageBuffer).transformed(by: transformation)
}    



对于风景来说,效果很好。对于肖像,我以错误的角度获得图像(旋转 180 度)。知道为什么吗?

输出:

输出

预期的:

预期的

4

2 回答 2

1

起初我应该说这绝对是一个令人不快的错误

一个问题是,当您将PortraitARFrame 包含的图像转换为 CIImage 或 CGImage 时,它​​会失去方向并将其逆时针旋转 180 度。此问题仅影响Portrait图像。Landscape那些根本不受影响。

发生这种情况是因为Portrait图像在转换阶段没有关于其方向的信息,因此,即使转换为 CIImage 或 CGImage,纵向图像仍处于纵向模式。

要解决此问题,您应该将“标准”横向 width/height“非标准”纵向 width/进行比较height,如果这些值不同,请将图像旋转180 度 CW(或应用方向案例.portraitUpsideDown)。

希望这可以帮助。

于 2019-02-27T16:10:13.517 回答
1

坐标系

我们需要非常清楚我们在哪个坐标系中工作。我们知道 UIKit(0,0)在左上角和(1,1)右上角,但 CoreImage 不是这样:

由于 Core Image 的坐标系与 UIKit 不匹配...(见这里

或 Vision(包括 CoreML 识别):

Vision 使用从 0.0 到 1.0 的归一化坐标空间,原点位于左下方。(见这里

但是,displayTransform使用 UIKit 方向:

一个变换矩阵,从捕获的图像中的归一化图像坐标转换为考虑指定参数的归一化图像坐标。归一化的图像坐标范围从图像左上角的 (0,0) 到右下角的 (1,1)。(见这里

因此,如果您将 a 加载CVPixelBuffer到 aCIImage中,然后尝试应用displayTransform矩阵,它将被翻转(如您所见)。但是,它也弄乱了图像。

什么显示变换

显示变换似乎主要用于金属或其他倾向于匹配核心图像方向的较低级别的绘图例程。转换缩放图像并移动它,使其在指定范围内“填充”。

如果您要在 a 中显示图像,UIImageView那么它将被反转,因为它们的方向不同。但此外,图像视图会为您进行方面填充转换,因此没有理由移动或缩放,因此根本没有理由使用displayTransform。只需将图像旋转到正确的方向。

// apply an orientation. You can easily make a function
// which converts the screen orientation to this parameter

let rotated = CIImage(cvPixelBuffer: frame.capturedImage).oriented(...)
imageView.image = UIImage(ciImage: rotated)

如果您想在图像上覆盖内容,例如通过向 中添加子视图UIImageView,那么displayTransform可能会有所帮助。它将图像坐标(在 UIKit 方向)转换为图像视图中的坐标,该坐标与显示的图像对齐(由于方面填充而移动和缩放)。

于 2021-04-13T23:16:16.333 回答