You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS自定义YOLOv8模型仅横屏可检测,竖屏失效问题求助

解决iOS竖屏模式下YOLOv8 Core ML模型检测失效问题

问题根源

核心矛盾是设备方向、相机捕获图像方向、模型训练时的图像方向三者不匹配:一方面传递给Core ML模型的图像不符合训练预期,导致检测失效;另一方面UI图层的固定旋转逻辑仅适配横屏,引发检测框、标签显示错位。

分步解决方案

1. 修正EXIF方向映射(核心:让模型拿到正确方向的图像)

假设你的YOLOv8模型是基于竖屏图像训练的,替换exifOrientationFromDeviceOrientation方法,确保传递给Vision框架的图像方向与训练时一致:

public func exifOrientationFromDeviceOrientation() -> CGImagePropertyOrientation {
    let orientation = UIDevice.current.orientation
    switch orientation {
    case .portrait:
        return .right // 相机捕获的横屏图像转90度顺时针,匹配竖屏训练样本
    case .portraitUpsideDown:
        return .left // 转270度顺时针
    case .landscapeLeft:
        return .upMirrored // 横屏Home键右侧,对应训练时的横屏镜像图像
    case .landscapeRight:
        return .down // 横屏Home键左侧,对应训练时的横屏图像
    case .faceUp, .faceDown, .unknown:
        // 设备平放时 fallback 到竖屏方向
        return .right
    }
}

若模型是基于横屏图像训练的,需反向调整映射关系。

2. 动态调整检测图层几何变换(解决UI显示错位)

原方法固定旋转90度仅适配横屏,改为根据设备方向动态计算旋转角度:

func updateLayerGeometry() {
    let bounds = rootLayer.bounds
    var scale: CGFloat
    var rotationAngle: CGFloat = 0.0
    
    // 根据设备方向确定旋转角度
    let orientation = UIDevice.current.orientation
    switch orientation {
    case .portrait, .portraitUpsideDown:
        rotationAngle = .pi / 2.0
    case .landscapeLeft, .landscapeRight:
        rotationAngle = 0.0
    default:
        rotationAngle = .pi / 2.0
    }
    
    // 计算等比例缩放系数
    let xScale: CGFloat = bounds.size.width / bufferSize.height
    let yScale: CGFloat = bounds.size.height / bufferSize.width
    scale = fmax(xScale, yScale)
    if scale.isInfinite {
        scale = 1.0
    }
    
    CATransaction.begin()
    CATransaction.setValue(kCFBooleanTrue, forKey: kCATransactionDisableActions)
    
    // 组合旋转、缩放、镜像变换
    var transform = CGAffineTransform(rotationAngle: rotationAngle)
    transform = transform.scaledBy(x: scale, y: -scale)
    detectionOverlay.setAffineTransform(transform)
    
    detectionOverlay.position = CGPoint(x: bounds.midX, y: bounds.midY)
    CATransaction.commit()
}

3. 修正文本图层旋转(解决标签垂直显示问题)

根据设备方向动态调整文本图层的尺寸与旋转:

func createTextSubLayerInBounds(_ bounds: CGRect, identifier: String, confidence: VNConfidence) -> CATextLayer {
    let textLayer = CATextLayer()
    textLayer.name = "Object Label"
    let formattedString = NSMutableAttributedString(string: String(format: "\(identifier)\nConfidence:  %.2f", confidence))
    let largeFont = UIFont(name: "Helvetica", size: 10.0)!
    formattedString.addAttributes([NSAttributedString.Key.font: largeFont], range: NSRange(location: 0, length: identifier.count))
    textLayer.string = formattedString
    
    // 根据设备方向适配文本图层
    let orientation = UIDevice.current.orientation
    if orientation.isPortrait {
        textLayer.bounds = CGRect(x: 0, y: 0, width: bounds.size.height - 10, height: bounds.size.width - 10)
        textLayer.setAffineTransform(CGAffineTransform(rotationAngle: .pi / 2.0).scaledBy(x: 1.0, y: -1.0))
    } else {
        textLayer.bounds = CGRect(x: 0, y: 0, width: bounds.size.width - 10, height: bounds.size.height - 10)
        textLayer.setAffineTransform(CGAffineTransform.identity)
    }
    
    textLayer.position = CGPoint(x: bounds.midX, y: bounds.midY)
    textLayer.shadowOpacity = 0.7
    textLayer.shadowOffset = CGSize(width: 2, height: 2)
    textLayer.foregroundColor = CGColor(colorSpace: CGColorSpaceCreateDeviceRGB(), components: [0.0, 0.0, 0.0, 1.0])
    textLayer.contentsScale = UIScreen.main.scale
    return textLayer
}

4. 监听设备方向变化,实时更新图层

在viewDidLoad中添加方向监听,确保旋转时图层同步更新:

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(deviceOrientationChanged), name: UIDevice.orientationDidChangeNotification, object: nil)
    UIDevice.current.beginGeneratingDeviceOrientationNotifications()
}

@objc func deviceOrientationChanged() {
    updateLayerGeometry()
}

deinit {
    NotificationCenter.default.removeObserver(self)
    UIDevice.current.endGeneratingDeviceOrientationNotifications()
}

额外验证步骤

  1. 确认YOLOv8训练时的图像方向,若为横屏需反向调整EXIF映射与图层逻辑
  2. 打印exifOrientation值,验证不同设备方向对应正确的CGImagePropertyOrientation
  3. 检查bufferSize是否与相机预览分辨率一致

内容的提问来源于stack exchange,提问作者sks

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 16:07:33