mcpField
A
axiom-vision-diag

axiom-vision-diag

github.com/charleswiltgen开发1.2k178 次安装今天更新
代码仓库

关于 axiom-vision-diag

面向使用 Apple Vision 框架的开发者的故障排查指南,按环境、置信度、线程、坐标和 API 可用性定位检测、识别及性能问题,并提供诊断步骤和修复模式。

主要功能

  1. 01诊断 Vision 检测问题
  2. 02检查置信度和运行线程
  3. 03排查坐标转换错误
  4. 04处理 API 可用性差异
  5. 05优化实时处理性能

适用场景

  1. 01调查手部或人体姿态未识别
  2. 02修复界面叠加位置偏差
  3. 03排查文本或条码识别失败
  4. 04降低实时图像处理卡顿

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/charleswiltgen/axiom --skill axiom-vision-diag

安装后在 Claude Code 中输入/axiom-vision-diag确认已加载。

详细介绍

Vision 框架诊断

系统地排查 Vision 框架问题:检测不到主体、缺少关键点、置信度低、性能问题、坐标不匹配、文本识别失败、条形码检测问题以及文档扫描问题。

概述

核心原则:Vision 无法正常工作时,问题通常出在:

  1. 环境(光照、遮挡、画面边缘)——40%
  2. 置信度阈值(忽略低置信度数据)——30%
  3. 线程(阻塞主线程导致界面冻结)——15%
  4. 坐标(混淆左下角和左上角原点)——10%
  5. API 可用性(在较旧设备上使用 iOS 17+ API)——5%

调试代码之前,务必先检查环境和置信度。

危险信号

表明存在 Vision 特定问题的症状:

症状可能原因
完全检测不到主体画面边缘、光照不足、主体太小
手部关键点间歇性地为 nil手靠近边缘、与相机平行、手套或遮挡
身体姿势跳过若干帧人物弯腰、倒立、穿着飘动的衣物
处理期间界面冻结在主线程上运行 Vision
覆盖内容位置错误坐标转换(左下角与左上角)
在较旧设备上崩溃使用 iOS 17+ API,但未检查 @available
人物分割漏掉人物场景中有 >4 个人(实例蒙版数量限制)
相机画面的 FPS 低maximumHandCount 过高,且没有丢弃帧
完全识别不到文本图像模糊、字体风格化、识别级别错误
文本误读(字符错误)未启用语言校正,缺少自定义词语
未检测到条形码条码类型错误、码太小、眩光或反光
DataScanner 显示空白屏幕相机访问被拒绝、设备不受支持
未检测到文档边缘对比度低、非矩形、眩光
实时扫描太慢处理每一帧、区域过大

必须先执行的步骤

调查代码之前,先运行以下诊断:

步骤 1:使用诊断代码验证检测
let request = VNGenerateForegroundInstanceMaskRequest()  // Or hand/body pose
let handler = VNImageRequestHandler(cgImage: testImage)

do {
    try handler.perform([request])

    if let results = request.results {
        print("✅ Request succeeded")
        print("Result count: \(results.count)")

        if let observation = results.first as? VNInstanceMaskObservation {
            print("All instances: \(observation.allInstances)")
            print("Instance count: \(observation.allInstances.count)")
        }
    } else {
        print("⚠️ Request succeeded but no results")
    }
} catch {
    print("❌ Request failed: \(error)")
}

预期输出:

  • ✅ 请求成功,实例数量 > 0 → 检测正常
  • ⚠️ 请求成功,实例数量 = 0 → 未检测到任何内容(参见决策树)
  • ❌ 请求失败 → API 可用性问题
步骤 2:检查置信度分数
// For hand/body pose
if let observation = request.results?.first as? VNHumanHandPoseObservation {
    let allPoints = try observation.recognizedPoints(.all)

    for (key, point) in allPoints {
        print("\(key): confidence \(point.confidence)")

        if point.confidence < 0.3 {
            print("  ⚠️ LOW CONFIDENCE - unreliable")
        }
    }
}

预期输出:

  • 大多数关键点的置信度 > 0.5 → 检测良好
  • 许多关键点的置信度 < 0.3 → 光照不足、存在遮挡或位于画面边缘
步骤 3:验证线程
print("🧵 Thread: \(Thread.current)")

if Thread.isMainThread {
    print("❌ Running on MAIN THREAD - will block UI!")
} else {
    print("✅ Running on background thread")
}

预期输出:

  • ✅ 后台线程 → 正确
  • ❌ 主线程 → 移至 DispatchQueue.global()

决策树

Vision not working as expected?
│
├─ No results returned?
│  ├─ Check Step 1 output
│  │  ├─ "Request failed" → See Pattern 1a (API availability)
│  │  ├─ "No results" → See Pattern 1b (nothing detected)
│  │  └─ Results but count = 0 → See Pattern 1c (edge of frame)
│
├─ Landmarks have nil/low confidence?
│  ├─ Hand pose → See Pattern 2 (hand detection issues)
│  ├─ Body pose → See Pattern 3 (body detection issues)
│  └─ Face detection → See Pattern 4 (face detection issues)
│
├─ UI freezing/slow?
│  ├─ Check Step 3 (threading)
│  │  ├─ Main thread → See Pattern 5a (move to background)
│  │  └─ Background thread → See Pattern 5b (performance tuning)
│
├─ Overlays in wrong position?
│  └─ See Pattern 6 (coordinate conversion)
│
├─ Person segmentation missing people?
│  └─ See Pattern 7 (crowded scenes)
│
├─ VisionKit not working?
│  └─ See Pattern 8 (VisionKit specific)
│
├─ Text recognition issues?
│  ├─ No text detected → See Pattern 9a (image quality)
│  ├─ Wrong characters → See Pattern 9b (language/correction)
│  └─ Too slow → See Pattern 9c (recognition level)
│
├─ Barcode detection issues?
│  ├─ Barcode not detected → See Pattern 10a (symbology/size)
│  └─ Wrong payload → See Pattern 10b (barcode quality)
│
├─ DataScannerViewController issues?
│  ├─ Blank screen → See Pattern 11a (availability check)
│  └─ Items not detected → See Pattern 11b (data types)
│
└─ Document scanning issues?
   ├─ Edges not detected → See Pattern 12a (contrast/shape)
   └─ Perspective wrong → See Pattern 12b (corner points)

诊断模式

模式 1a:请求失败(API 可用性)

症状:try handler.perform([request]) 抛出错误

常见错误:

"VNGenerateForegroundInstanceMaskRequest is only available on iOS 17.0 or newer"
"VNDetectHumanBodyPose3DRequest is only available on iOS 17.0 or newer"

根本原因:在较旧的部署目标上使用 iOS 17+ API

修复方法:

if #available(iOS 17.0, *) {
    let request = VNGenerateForegroundInstanceMaskRequest()
    // ...
} else {
    // Fallback for iOS 14-16
    let request = VNGeneratePersonSegmentationRequest()
    // ...
}

预防措施:实现之前,先在 axiom-vision-ref 中检查 API 可用性

修复耗时:10 分钟

模式 1b:无结果(未检测到任何内容)

症状:request.results == nil 或 results.isEmpty

诊断:

// 1. Save debug image to Photos
UIImageWriteToSavedPhotosAlbum(debugImage, nil, nil, nil)

// 2. Inspect visually
// - Is subject too small? (< 10% of image)
// - Is subject blurry?
// - Poor contrast with background?

常见原因:

  • 主体太小(调整大小或裁剪得更近)
  • 主体太模糊(增强光照、稳定相机)
  • 对比度低(主体与背景颜色相同)

修复方法:

// Crop image to focus on region of interest
let croppedImage = cropImage(sourceImage, to: regionOfInterest)
let handler = VNImageRequestHandler(cgImage: croppedImage)

修复耗时:30 分钟

模式 1c:画面边缘问题

症状:主体在画面中移动时,检测结果时有时无

根本原因:主体接触图像边缘时发生部分遮挡

诊断:

// Check if subject is near edges
if let observation = results.first as? VNInstanceMaskObservation {
    let mask = try observation.createScaledMask(
        for: observation.allInstances,
        croppedToInstancesContent: true
    )

    let bounds = calculateMaskBounds(mask)

    if bounds.minX < 0.1 || bounds.maxX > 0.9 ||
       bounds.minY < 0.1 || bounds.maxY > 0.9 {
        print("⚠️ Subject too close to edge")
    }
}

修复方法:

// Add padding to capture area
let paddedRect = captureRect.insetBy(dx: -20, dy: -20)

// OR guide user with on-screen overlay
overlayView.addSubview(guideBox)  // Visual boundary

修复耗时:20 分钟

模式 2:手部姿势问题

症状:VNDetectHumanHandPoseRequest 返回 nil 或置信度较低的关键点

诊断:

if let observation = request.results?.first as? VNHumanHandPoseObservation {
    let thumbTip = try? observation.recognizedPoint(.thumbTip)
    let wrist = try? observation.recognizedPoint(.wrist)

    print("Thumb confidence: \(thumbTip?.confidence ?? 0)")
    print("Wrist confidence: \(wrist?.confidence ?? 0)")

    // Check hand orientation
    if let thumb = thumbTip, let wristPoint = wrist {
        let angle = atan2(
            thumb.location.y - wristPoint.location.y,
            thumb.location.x - wristPoint.location.x
        )
        print("Hand angle: \(angle * 180 / .pi) degrees")

        if abs(angle) > 80 && abs(angle) < 100 {
            print("⚠️ Hand parallel to camera (hard to detect)")
        }
    }
}

常见原因:

原因置信度模式修复方法
手靠近边缘指尖置信度较低调整取景
手与摄像头平行所有关键点置信度较低提示用户转动手部
手套/遮挡手指置信度较低,手腕置信度较高脱掉手套或调整光线
将脚检测为手检测到意外的手添加 chirality 检查或忽略

修复手部与摄像头平行的问题:

// Detect and warn user
if avgConfidence < 0.4 {
    showWarning("Rotate your hand toward the camera")
}

修复时间:45 分钟

模式 3:身体姿势问题

症状:VNDetectHumanBodyPoseRequest 跳过帧或返回置信度较低的结果

诊断:

if let observation = request.results?.first as? VNHumanBodyPoseObservation {
    let nose = try? observation.recognizedPoint(.nose)
    let root = try? observation.recognizedPoint(.root)

    if let nosePoint = nose, let rootPoint = root {
        let bodyAngle = atan2(
            nosePoint.location.y - rootPoint.location.y,
            nosePoint.location.x - rootPoint.location.x
        )

        let angleFromVertical = abs(bodyAngle - .pi / 2)

        if angleFromVertical > .pi / 4 {
            print("⚠️ Person bent over or upside down")
        }
    }
}

常见原因:

原因解决方案
人物弯腰提示用户站直
倒立(手倒立)改用 ARKit(更适合动态姿势)
飘逸的衣物增加对比度或穿着更贴身的衣物
多人重叠使用人物实例分割

修复时间:1 小时

模式 4:人脸检测问题

症状:VNDetectFaceRectanglesRequest 漏检人脸或返回错误的数量

诊断:

if let faces = request.results as? [VNFaceObservation] {
    print("Detected \(faces.count) faces")

    for face in faces {
        print("Face bounds: \(face.boundingBox)")
        print("Confidence: \(face.confidence)")

        if face.boundingBox.width < 0.1 {
            print("⚠️ Face too small")
        }
    }
}

常见原因:

  • 人脸小于图像的 10%(裁剪得更近)
  • 侧脸视角(改用人脸关键点请求)
  • 光线不足(增加曝光)

修复时间:30 分钟

模式 5a:UI 卡顿(主线程)

症状:执行 Vision 请求时应用卡顿

诊断(上面的步骤 3 可确认是否在主线程)

修复方法:

// BEFORE (wrong)
let request = VNGenerateForegroundInstanceMaskRequest()
try handler.perform([request])  // Blocks UI

// AFTER (correct)
DispatchQueue.global(qos: .userInitiated).async {
    let request = VNGenerateForegroundInstanceMaskRequest()
    try? handler.perform([request])

    DispatchQueue.main.async {
        // Update UI
    }
}

修复时间:15 分钟

模式 5b:性能问题(后台线程)

症状:已在后台线程运行,但仍然缓慢/丢帧

诊断:

let start = CFAbsoluteTimeGetCurrent()

try handler.perform([request])

let elapsed = CFAbsoluteTimeGetCurrent() - start
print("Request took \(elapsed * 1000)ms")

if elapsed > 0.2 {  // 200ms = too slow for real-time
    print("⚠️ Request too slow for real-time processing")
}

常见原因及修复方法:

原因修复方法节省时间
maximumHandCount = 10设置为实际所需数量(例如 2)50-70%
处理每一帧跳过部分帧(每 3 帧处理一次)66%
全分辨率图像缩小至 1280x72040-60%
每帧执行多个请求批处理或交替执行请求30-50%

实时摄像头的修复方法:

// Skip frames
frameCount += 1
guard frameCount % 3 == 0 else { return }

// OR downscale
let scaledImage = resizeImage(sourceImage, to: CGSize(width: 1280, height: 720))

// OR set lower hand count
request.maximumHandCount = 2  // Instead of default

修复时间:1 小时

模式 6:坐标转换

症状:UI 覆盖层显示在错误的位置

诊断:

// Vision point (lower-left origin, normalized)
let visionPoint = recognizedPoint.location
print("Vision point: \(visionPoint)")  // e.g., (0.5, 0.8)

// Convert to UIKit
let uiX = visionPoint.x * imageWidth
let uiY = (1 - visionPoint.y) * imageHeight  // FLIP Y
print("UIKit point: (\(uiX), \(uiY))")

// Verify overlay
overlayView.center = CGPoint(x: uiX, y: uiY)

常见错误:

// ❌ WRONG (no Y flip)
let uiPoint = CGPoint(
    x: axiom-visionPoint.x * width,
    y: axiom-visionPoint.y * height
)

// ❌ WRONG (forgot to scale from normalized)
let uiPoint = CGPoint(
    x: axiom-visionPoint.x,
    y: 1 - visionPoint.y
)

// ✅ CORRECT
let uiPoint = CGPoint(
    x: axiom-visionPoint.x * width,
    y: (1 - visionPoint.y) * height
)

修复时间:20 分钟

模式 7:场景拥挤(超过 4 人)

症状:VNGeneratePersonInstanceMaskRequest 漏检人物或将多个人物合并

诊断:

// Count faces
let faceRequest = VNDetectFaceRectanglesRequest()
try handler.perform([faceRequest])

let faceCount = faceRequest.results?.count ?? 0
print("Detected \(faceCount) faces")

// Person instance segmentation
let personRequest = VNGeneratePersonInstanceMaskRequest()
try handler.perform([personRequest])

let personCount = (personRequest.results?.first as? VNInstanceMaskObservation)?.allInstances.count ?? 0
print("Detected \(personCount) people")

if faceCount > 4 && personCount <= 4 {
    print("⚠️ Crowded scene - some people combined or missing")
}

修复方法:

if faceCount > 4 {
    // Fallback: Use single mask for all people
    let singleMaskRequest = VNGeneratePersonSegmentationRequest()
    try handler.perform([singleMaskRequest])

    // OR guide user
    showWarning("Please reduce number of people in frame (max 4)")
}

修复时间:30 分钟

模式 8:VisionKit 特有问题

症状:ImageAnalysisInteraction 未显示主体抠图 UI

诊断:

// 1. Check interaction types
print("Interaction types: \(interaction.preferredInteractionTypes)")

// 2. Check if analysis is set
print("Analysis: \(interaction.analysis != nil ? "set" : "nil")")

// 3. Check if view supports interaction
if let view = interaction.view {
    print("View: \(view)")
} else {
    print("❌ View not set")
}

常见原因:

症状原因修复方法
未显示 UI未设置 analysis调用 analyzer.analyze() 并设置结果
已显示 UI,但未抠出主体交互类型错误设置 .imageSubject 或 .automatic
交互时崩溃交互前视图已移除将视图保留在内存中

修复方法:

// Ensure analysis is set
let analyzer = ImageAnalyzer()
let analysis = try await analyzer.analyze(image, configuration: config)

interaction.analysis = analysis  // Required!
interaction.preferredInteractionTypes = .imageSubject

修复时间:20 分钟

模式 9a:未检测到文本(图像质量问题)

症状:VNRecognizeTextRequest 未返回结果或返回空字符串

诊断:

let request = VNRecognizeTextRequest()
request.recognitionLevel = .accurate

try handler.perform([request])

if request.results?.isEmpty ?? true {
    print("❌ No text detected")

    // Check image quality
    print("Image size: \(image.size)")
    print("Minimum text height: \(request.minimumTextHeight)")
}

for obs in request.results as? [VNRecognizedTextObservation] ?? [] {
    let top = obs.topCandidates(3)
    for candidate in top {
        print("'\(candidate.string)' confidence: \(candidate.confidence)")
    }
}

常见原因:

原因症状修复方法
图像模糊无结果改善光线,稳定摄像头
文本太小无结果降低 minimumTextHeight 或裁剪得更近
艺术字体识别错误或无结果尝试 .accurate 识别级别
对比度低结果不完整改善光线,提高图像对比度
文本旋转使用 .fast 时无结果使用 .accurate(可处理旋转)

小文本的修复方法:

// Lower minimum text height (default ignores very small text)
request.minimumTextHeight = 0.02  // 2% of image height

修复时间:30 分钟

模式 9b:字符错误(语言校正)

症状:检测到了文本,但字符有误(例如,“C001” → “COOL”)

诊断:

// Check all candidates, not just first
for observation in results {
    let candidates = observation.topCandidates(5)
    for (i, candidate) in candidates.enumerated() {
        print("Candidate \(i): '\(candidate.string)' (\(candidate.confidence))")
    }
}

常见原因:

输入类型问题修复方法
序列号语言校正会“修正”它们禁用 usesLanguageCorrection
技术代码被误读为单词添加到 customWords
非英语文本ML 模型错误设置正确的 recognitionLanguages
门牌号风格化字符 → 误读检查所有候选项,而不只是排名第一的

代码/序列号的修复方法:

let request = VNRecognizeTextRequest()
request.usesLanguageCorrection = false  // Don't "fix" codes

// Post-process with domain knowledge
func correctSerialNumber(_ text: String) -> String {
    text.replacingOccurrences(of: "O", with: "0")
        .replacingOccurrences(of: "l", with: "1")
        .replacingOccurrences(of: "S", with: "5")
}

修复耗时:30 min

模式 9c:文本识别太慢

症状:文本识别耗时 >500ms,实时摄像头会丢帧

诊断:

let start = CFAbsoluteTimeGetCurrent()
try handler.perform([request])
let elapsed = CFAbsoluteTimeGetCurrent() - start

print("Recognition took \(elapsed * 1000)ms")
print("Recognition level: \(request.recognitionLevel == .fast ? "fast" : "accurate")")
print("Language correction: \(request.usesLanguageCorrection)")

常见原因及修复方法:

原因修复方法提速幅度
实时识别使用 .accurate切换到 .fast3-5x
启用了语言校正对代码禁用语言校正20-30%
处理完整图像使用 regionOfInterest2-4x
处理每一帧跳过帧50-70%

实时识别的修复方法:

request.recognitionLevel = .fast
request.usesLanguageCorrection = false
request.regionOfInterest = CGRect(x: 0.1, y: 0.3, width: 0.8, height: 0.4)

// Skip frames
frameCount += 1
guard frameCount % 3 == 0 else { return }

修复耗时:30 min

模式 10a:未检测到条形码(码制/尺寸)

症状:VNDetectBarcodesRequest 未返回任何结果

诊断:

let request = VNDetectBarcodesRequest()
// Don't specify symbologies to detect all types
try handler.perform([request])

if let results = request.results as? [VNBarcodeObservation] {
    print("Found \(results.count) barcodes")
    for barcode in results {
        print("Type: \(barcode.symbology)")
        print("Payload: \(barcode.payloadStringValue ?? "nil")")
        print("Bounds: \(barcode.boundingBox)")
    }
} else {
    print("❌ No barcodes detected")
}

常见原因:

原因症状修复方法
码制错误未检测到不要筛选,或添加正确的类型
条形码太小未检测到将摄像头移近,裁剪图像
眩光/反光未检测到调整角度,改善光照
条形码损坏检测不完整/未检测到清洁条形码,改善图像质量
使用修订版 1只能识别一个代码要识别多个代码,请使用修订版 2+

小型条形码的修复方法:

// Crop to barcode region for better detection
let croppedHandler = VNImageRequestHandler(
    cgImage: croppedImage,
    options: [:]
)

修复耗时:20 min

模式 10b:条形码载荷错误

症状:检测到条形码,但 payloadStringValue 错误或为 nil

诊断:

if let barcode = results.first {
    print("String payload: \(barcode.payloadStringValue ?? "nil")")
    print("Raw payload: \(barcode.payloadData ?? Data())")
    print("Symbology: \(barcode.symbology)")
    print("Confidence: Implicit (always 1.0 for barcodes)")
}

常见原因:

原因修复方法
二进制条形码(非字符串)改用 payloadData
代码损坏重新扫描或清洁条形码
假设的码制错误检查实际的 symbology 值

修复耗时:15 min

模式 11a:DataScanner 空白屏幕

症状:展示 DataScannerViewController 时显示黑屏/空白屏

诊断:

// Check support first
print("isSupported: \(DataScannerViewController.isSupported)")
print("isAvailable: \(DataScannerViewController.isAvailable)")

// Check camera permission
let status = AVCaptureDevice.authorizationStatus(for: .video)
print("Camera access: \(status.rawValue)")

常见原因:

症状原因修复方法
isSupported = false设备缺少摄像头/芯片展示前先检查
isAvailable = false家长控制或访问被拒请求摄像头权限
黑屏摄像头正被其他应用使用确保独占访问
展示时崩溃缺少权限配置添加摄像头使用说明

修复方法:

guard DataScannerViewController.isSupported else {
    showError("Scanning not supported on this device")
    return
}

guard DataScannerViewController.isAvailable else {
    // Request camera access
    AVCaptureDevice.requestAccess(for: .video) { granted in
        // Retry after access granted
    }
    return
}

修复耗时:15 min

模式 11b:DataScanner 未检测到项目

症状:DataScanner 显示摄像头画面,但无法识别项目

诊断:

// Check recognized data types
print("Data types: \(scanner.recognizedDataTypes)")

// Add delegate to see what's happening
func dataScanner(_ scanner: DataScannerViewController,
                 didAdd items: [RecognizedItem],
                 allItems: [RecognizedItem]) {
    print("Added \(items.count) items, total: \(allItems.count)")
    for item in items {
        switch item {
        case .text(let text): print("Text: \(text.transcript)")
        case .barcode(let barcode): print("Barcode: \(barcode.payloadStringValue ?? "")")
        @unknown default: break
        }
    }
}

常见原因:

原因修复方法
数据类型错误添加正确的 .barcode(symbologies:) 或 .text()
文本内容类型筛选器移除筛选器或使用正确的类型
摄像头太近/太远调整距离
光照不足改善光照

修复耗时:20 min

模式 12a:未检测到文档边缘

症状:VNDetectDocumentSegmentationRequest 未返回任何结果

诊断:

let request = VNDetectDocumentSegmentationRequest()
try handler.perform([request])

if let observation = request.results?.first {
    print("Document found at: \(observation.boundingBox)")
    print("Corners: TL=\(observation.topLeft), TR=\(observation.topRight)")
} else {
    print("❌ No document detected")
}

常见原因:

原因修复方法
对比度低使用对比鲜明的背景
非矩形文档ML 需要矩形文档
眩光/反光调整光照角度
文档占满画面需要露出一些背景

修复方法:使用 VNDocumentCameraViewController,通过实时反馈提供引导式用户体验。

修复耗时:15 min

模式 12b:透视校正错误

症状:文档已提取,但发生了扭曲

诊断:

// Verify corner order
print("TopLeft: \(observation.topLeft)")
print("TopRight: \(observation.topRight)")
print("BottomLeft: \(observation.bottomLeft)")
print("BottomRight: \(observation.bottomRight)")

// Check if corners are in expected positions
// TopLeft should have larger Y than BottomLeft (Vision uses lower-left origin)

常见原因:

原因修复方法
角点顺序错误Vision 使用从左上角开始的逆时针顺序
坐标系将归一化坐标转换为像素坐标
筛选参数错误检查 CIPerspectiveCorrection 参数

修复方法:

// Scale normalized to image coordinates
func scaled(_ point: CGPoint, to size: CGSize) -> CGPoint {
    CGPoint(x: point.x * size.width, y: point.y * size.height)
}

修复时间:20 分钟

生产环境危机场景

情况:App Store 审核因“点击分析按钮时应用卡死”而被拒

分诊(5 分钟):

  1. 确认 Vision 是否在主线程上运行 → 模式 5a
  2. 在较旧的设备(iPhone 12)上验证 → 卡死
  3. 检查性能分析:主线程耗时 800ms

修复(15 分钟):

@IBAction func analyzeTapped(_ sender: UIButton) {
    showLoadingIndicator()

    DispatchQueue.global(qos: .userInitiated).async { [weak self] in
        let request = VNGenerateForegroundInstanceMaskRequest()
        // ... perform request

        DispatchQueue.main.async {
            self?.hideLoadingIndicator()
            self?.updateUI(with: results)
        }
    }
}

向 PM 说明: “App Store 审核被拒,原因是 Vision 在主线程上处理。已通过移至后台队列修复(行业标准做法)。在 iPhone 12 上测试确认修复有效。可以安全地重新提交。”

快速参考表

症状可能原因首要检查项模式预计时间
无结果未检测到任何内容第 1 步输出1b/1c30 分钟
检测不稳定位于画面边缘主体位置1c20 分钟
手部缺少特征点置信度低第 2 步(置信度)245 分钟
跳过身体姿势人物弯腰身体角度31 小时
UI 卡顿主线程第 3 步(线程处理)5a15 分钟
处理缓慢性能调优请求耗时5b1 小时
覆盖层位置错误坐标打印点坐标620 分钟
缺少人物(>4)场景拥挤人脸数量730 分钟
VisionKit 没有 UI未设置分析交互状态820 分钟
未检测到文本图像质量结果数量9a30 分钟
字符错误语言设置候选项列表9b30 分钟
文本识别缓慢识别级别耗时9c30 分钟
未检测到条形码符号类型/尺寸结果转储10a20 分钟
条形码内容错误已损坏/二进制数据内容数据10b15 分钟
DataScanner 内容空白可用性isSupported/isAvailable11a15 分钟
DataScanner 没有项目数据类型recognizedDataTypes11b20 分钟
缺少文档边缘对比度/形状检查结果12a15 分钟
透视错误角点顺序角点位置12b20 分钟

资源

WWDC:2019-234、2021-10041、2022-10024、2022-10025、2025-272、2023-10176、2020-10653

文档:/vision、/vision/vnrecognizetextrequest、/visionkit

技能:axiom-vision、axiom-vision-ref

评论

支持 Markdown