这段代码定义了一个静态函数 poseOverlays
,用于根据多个姿势标志(landmarks)生成姿势覆盖层(PoseOverlay)。该函数接收多个参数以便对姿势标志进行处理,并将其转换为适合于指定显示视图的点和线。下面是对每个部分的详细解释:
函数签名
static func poseOverlays(
fromMultiplePoseLandmarks landmarks: [[NormalizedLandmark]],
inferredOnImageOfSize originalImageSize: CGSize,
ovelayViewSize: CGSize,
imageContentMode: UIView.ContentMode,
andOrientation orientation: UIImage.Orientation) -> [PoseOverlay]
参数:
landmarks
: 一个二维数组,每个元素包含一组标准化的骨架坐标(NormalizedLandmark
),表示一个人的姿势。originalImageSize
: 图像的原始尺寸,以便在该尺寸上进行绘制。ovelayViewSize
: 绘制到目标视图上的大小。imageContentMode
: 用于指示如何调整图像以适应显示区域的模式,例如.scaleAspectFit
或.scaleAspectFill
。orientation
: 当前设备方向,用于调整骨架坐标。
返回值: 返回一个
[PoseOverlay]
的数组,其中每个元素都是一个包含点和线信息的对象,用于表示绘制的姿势。
变量初始化
var poseOverlays: [PoseOverlay] = []
- 初始化一个空数组,用来存储最终生成的所有姿势覆盖层。
检查输入有效性
guard !landmarks.isEmpty else {
return []
}
- 如果传入的
landmarks
数组为空,直接返回空数组,避免不必要的计算。
计算偏移量和缩放因子
let offsetsAndScaleFactor = OverlayView.offsetsAndScaleFactor(
forImageOfSize: originalImageSize,
tobeDrawnInViewOfSize: ovelayViewSize,
withContentMode: imageContentMode)
- 调用辅助函数来计算图像从原始大小到目标视图大小所需的偏移量和缩放因子。这些值在后续步骤中用于正确定位和缩放关键点。
遍历每组骨架坐标并处理方向
for poseLandmarks in landmarks {
var transformedPoseLandmarks: [CGPoint]!
switch orientation {
case .left:
transformedPoseLandmarks = poseLandmarks.map({CGPoint(x: CGFloat($0.y), y: 1 - CGFloat($0.x))})
case .right:
transformedPoseLandmarks = poseLandmarks.map({CGPoint(x: 1 - CGFloat($0.y), y: CGFloat($0.x))})
default:
transformedPoseLandmarks = poseLandmarks.map({CGPoint(x: CGFloat($0.x), y: CGFloat($0.y))})
}
}
- 对每组骨架标志进行遍历,根据设备方向转换坐标:
- 如果设备处于左侧 (
.left
):交换 x 和 y 值,并对 x 值进行反转。 - 如果设备处于右侧 (
.right
):同样交换 x 和 y 值,但对 y 值反转。 - 默认情况下,保持坐标不变。
- 如果设备处于左侧 (
将标准化坐标转换为实际屏幕坐标
let dots: [CGPoint] = transformedPoseLandmarks.map({ CGPoint(x: CGFloat($0.x) * originalImageSize.width * offsetsAndScaleFactor.scaleFactor + offsetsAndScaleFactor.xOffset,
y: CGFloat($0.y) * originalImageSize.height * offsetsAndScaleFactor.scaleFactor + offsetsAndScaleFactor.yOffset)})
- 使用映射将变换后的标准化点转换为具体屏幕坐标。这里考虑了缩放因子和偏移量,以确保点能够准确地渲染在目标视图中。
创建连接线条并构建 PoseOverlay 对象
let lines: [Line] = PoseLandmarker.poseLandmarks.map({ connection in
let start = dots[Int(connection.start)]
let end = dots[Int(connection.end)]
return Line(from: start, to: end)
})
poseOverlays.append(PoseOverlay(dots: dots, lines: lines))
- 根据定义好的连接规则 (
connection.start
,connection.end
) 创建相应的线条对象,将开始和结束点对应到之前计算出的屏幕点上。然后,将这些点与线条组合成一个新的PoseOverlay
对象,并添加到结果数组中。
返回最终结果
return poseOverlays
- 返回经过处理后的所有姿势覆盖层,这些覆盖层可以用来在用户界面上绘制识别到的人体姿势。
整体而言,这段代码负责将从某种检测服务获得的一系列骨架关键点经过坐标变换、位置调整及绘制前处理后,转换成可用于 UI 渲染的数据结构,使得可以在应用中直观展示人体的位置与动作。
内容由零声教学AI助手提供,问题来源于学员提问