Swift4中调用CGRect的scaled方法报错,求解决方案
解决Swift 4中CGRect无scaled成员的问题
这个错误很常见——在Swift 4对应的iOS版本(iOS 11/12)里,CGRect确实没有内置的scaled(to:)方法,这个方法是iOS 13及以后才加入的系统API,所以你在Swift 4里调用自然会报错。而且还要注意:Vision框架返回的boundingBox是归一化坐标系(原点在图像左下角,数值范围0-1),和UIKit的视图坐标系(原点在左上角)不匹配,就算有scaled方法,直接用也会导致人脸框位置不对。
下面给你两种可行的解决方法:
方法一:手动完成坐标转换(推荐)
直接通过仿射变换同时完成缩放和坐标系翻转,这是处理Vision人脸框坐标的标准方式:
func detectLandmarks(on image: CIImage) { try? faceLandmarksDetectionRequest.perform([faceLandmarks], on: image) if let landmarksResults = faceLandmarks.results as? [VNFaceObservation] { for observation in landmarksResults { DispatchQueue.main.async { let boundingBox = observation.boundingBox // 直接用当前检测结果的boundingBox,而非inputFaceObservations let imageSize = image.extent.size // 第一步:将归一化坐标缩放到视图尺寸 let scale = CGAffineTransform(scaleX: self.view.bounds.width / imageSize.width, y: self.view.bounds.height / imageSize.height) // 第二步:翻转Y轴,适配UIKit坐标系 let flip = CGAffineTransform(scaleX: 1, y: -1) .translatedBy(x: 0, y: -self.view.bounds.height) // 组合变换得到最终的人脸框 let faceBoundingBox = boundingBox.applying(scale).applying(flip) // 这里就可以用faceBoundingBox做绘制等操作了 } } } }
注意:我调整了获取boundingBox的方式,你之前用inputFaceObservations?.first可能不是当前检测到的最新结果,直接用循环里的observation.boundingBox才是正确的。
方法二:自定义CGRect的scaled扩展
如果你确实想复用类似scaled(to:)的语法,可以自己给CGRect写一个扩展,但记得之后还要处理坐标系翻转:
extension CGRect { func scaled(to targetSize: CGSize) -> CGRect { return CGRect( x: origin.x * targetSize.width, y: origin.y * targetSize.height, width: size.width * targetSize.width, height: size.height * targetSize.height ) } }
使用时仍需添加翻转步骤:
let scaledBox = boundingBox.scaled(to: self.view.bounds.size) let flipTransform = CGAffineTransform(scaleX: 1, y: -1).translatedBy(x: 0, y: -self.view.bounds.height) let faceBoundingBox = scaledBox.applying(flipTransform)
内容的提问来源于stack exchange,提问作者Haochen Wang
相关产品推荐
相关产品推荐

