我正在尝试使用以下方法从当前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度)。知道为什么吗?
答案 0 :(得分:1)
首先,我应该说这绝对是令人不快的错误。
一个问题是,当您将Portrait
图像转换为ARFrame包含的图像到CIImage或CGImage时,它将失去其方向并将其逆时针旋转180度。此问题仅影响Portrait
个图像。 Landscape
个根本不受影响。
发生这种情况是因为Portrait
图像在转换阶段没有有关其方向的信息,因此,即使将肖像图像转换为CIImage或CGImage,也仍然保持肖像模式。
要解决此问题,您应该将“标准”肖像的 width
/ height
与“非标准”肖像的 {{1} } / width
,如果这些值不同,则将图像旋转至 180度(或应用方向情况.portraitUpsideDown)。
希望这会有所帮助。
答案 1 :(得分:0)
坐标系
我们需要非常清楚我们在哪个坐标系中工作。
我们知道 UIKit 的左上角有 (0,0)
,右上角有 (1,1)
,但 CoreImage 不是这样:
由于 Core Image 的坐标系与 UIKit 不匹配...(参见 here)
或 Vision(包括 CoreML 识别):
<块引用>Vision 使用从 0.0 到 1.0 的标准化坐标空间 左原点。 (见here)
然而,displayTransform
使用 UIKit 方向:
从归一化图像坐标转换的变换矩阵 捕获的图像到归一化的图像坐标,说明 指定的参数。归一化图像坐标范围从 图像左上角的 (0,0) 到下角的 (1,1) 右上角。 (见here)
因此,如果您将 CVPixelBuffer
加载到 CIImage
中,然后尝试应用
displayTransform
矩阵,它将被翻转(如您所见)。
但是,它也会弄乱图像。
显示转换的作用
显示变换似乎主要用于 Metal 或其他倾向于匹配核心图像方向的较低级别的绘图程序。 变换会缩放图像并移动它,使其在指定的边界内“填充”。
如果您要在 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 方向上)转换为图像视图中的坐标
与显示的图像对齐(由于纵横比填充而移动和缩放)。