axiom-vision-diag
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseVision Framework Diagnostics
Vision Framework 诊断指南
Systematic troubleshooting for Vision framework issues: subjects not detected, missing landmarks, low confidence, performance problems, coordinate mismatches, text recognition failures, barcode detection issues, and document scanning problems.
针对Vision框架问题的系统性故障排查:未检测到主体、缺失关键点、置信度低、性能问题、坐标不匹配、文本识别失败、条形码检测问题以及文档扫描问题。
Overview
概述
Core Principle: When Vision doesn't work, the problem is usually:
- Environment (lighting, occlusion, edge of frame) - 40%
- Confidence threshold (ignoring low confidence data) - 30%
- Threading (blocking main thread causes frozen UI) - 15%
- Coordinates (mixing lower-left and top-left origins) - 10%
- API availability (using iOS 17+ APIs on older devices) - 5%
Always check environment and confidence BEFORE debugging code.
核心原则:当Vision无法正常工作时,问题通常源于以下方面:
- 环境因素(光线、遮挡、主体在画面边缘)- 占比40%
- 置信度阈值(忽略低置信度数据)- 占比30%
- 线程处理(主线程被阻塞导致UI冻结)- 占比15%
- 坐标系统(混淆左下和左上原点)- 占比10%
- API兼容性(在旧设备上使用iOS 17+的API)- 占比5%
在调试代码之前,务必先检查环境和置信度。
Red Flags
异常信号
Symptoms that indicate Vision-specific issues:
| Symptom | Likely Cause |
|---|---|
| Subject not detected at all | Edge of frame, poor lighting, very small subject |
| Hand landmarks intermittently nil | Hand near edge, parallel to camera, glove/occlusion |
| Body pose skipped frames | Person bent over, upside down, flowing clothing |
| UI freezes during processing | Running Vision on main thread |
| Overlays in wrong position | Coordinate conversion (lower-left vs top-left) |
| Crash on older devices | Using iOS 17+ APIs without |
| Person segmentation misses people | >4 people in scene (instance mask limit) |
| Low FPS in camera feed | |
| Text not recognized at all | Blurry image, stylized font, wrong recognition level |
| Text misread (wrong characters) | Language correction disabled, missing custom words |
| Barcode not detected | Wrong symbology, code too small, glare/reflection |
| DataScanner shows blank screen | Camera access denied, device not supported |
| Document edges not detected | Low contrast, non-rectangular, glare |
| Real-time scanning too slow | Processing every frame, region too large |
表明存在Vision特定问题的症状:
| 症状 | 可能原因 |
|---|---|
| 完全未检测到主体 | 主体在画面边缘、光线不佳、主体过小 |
| 手部关键点间歇性为空 | 手靠近画面边缘、与摄像头平行、戴手套/被遮挡 |
| 人体姿态跳过帧 | 人物弯腰、倒立、穿着宽松衣物 |
| 处理过程中UI冻结 | 在主线程运行Vision任务 |
| 覆盖层位置错误 | 坐标转换问题(左下 vs 左上原点) |
| 在旧设备上崩溃 | 使用iOS 17+ API未做 |
| 人物分割遗漏人物 | 场景中超过4人(实例掩码限制) |
| 摄像头画面帧率低 | |
| 完全未识别到文本 | 图像模糊、字体风格特殊、识别级别设置错误 |
| 文本识别错误(字符错误) | 语言校正已禁用、缺少自定义词汇 |
| 未检测到条形码 | 符号体系错误、条码过小、反光/眩光 |
| DataScanner显示黑屏 | 摄像头权限被拒绝、设备不支持 |
| 未检测到文档边缘 | 对比度低、非矩形文档、反光 |
| 实时扫描过慢 | 处理每一帧、扫描区域过大 |
Mandatory First Steps
必做的初步步骤
Before investigating code, run these diagnostics:
在排查代码之前,先执行以下诊断步骤:
Step 1: Verify Detection with Diagnostic Code
步骤1:使用诊断代码验证检测功能
swift
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)")
}Expected output:
- ✅ Request succeeded, instance count > 0 → Detection working
- ⚠️ Request succeeded, instance count = 0 → Nothing detected (see Decision Tree)
- ❌ Request failed → API availability issue
swift
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)")
}预期输出:
- ✅ Request succeeded, instance count > 0 → 检测功能正常
- ⚠️ Request succeeded, instance count = 0 → 未检测到任何内容(查看决策树)
- ❌ Request failed → API兼容性问题
Step 2: Check Confidence Scores
步骤2:检查置信度分数
swift
// 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")
}
}
}Expected output:
- Most landmarks > 0.5 confidence → Good detection
- Many landmarks < 0.3 → Poor lighting, occlusion, or edge of frame
swift
// 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 → 光线不佳、被遮挡或主体在画面边缘
Step 3: Verify Threading
步骤3:验证线程处理
swift
print("🧵 Thread: \(Thread.current)")
if Thread.isMainThread {
print("❌ Running on MAIN THREAD - will block UI!")
} else {
print("✅ Running on background thread")
}Expected output:
- ✅ Background thread → Correct
- ❌ Main thread → Move to
DispatchQueue.global()
swift
print("🧵 Thread: \(Thread.current)")
if Thread.isMainThread {
print("❌ Running on MAIN THREAD - will block UI!")
} else {
print("✅ Running on background thread")
}预期输出:
- ✅ Background thread → 处理正确
- ❌ Main thread → 迁移至
DispatchQueue.global()
Decision Tree
决策树
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)Vision未按预期工作?
│
├─ 未返回任何结果?
│ ├─ 查看步骤1的输出
│ │ ├─ "Request failed" → 查看模式1a(API兼容性)
│ │ ├─ "No results" → 查看模式1b(未检测到任何内容)
│ │ └─ 有结果但数量为0 → 查看模式1c(主体在画面边缘)
│
├─ 关键点为空/置信度低?
│ ├─ 手部姿态 → 查看模式2(手部检测问题)
│ ├─ 人体姿态 → 查看模式3(人体检测问题)
│ └─ 面部检测 → 查看模式4(面部检测问题)
│
├─ UI冻结/响应缓慢?
│ ├─ 检查步骤3(线程处理)
│ │ ├─ 主线程 → 查看模式5a(迁移至后台线程)
│ │ └─ 后台线程 → 查看模式5b(性能调优)
│
├─ 覆盖层位置错误?
│ └─ 查看模式6(坐标转换)
│
├─ 人物分割遗漏人物?
│ └─ 查看模式7(拥挤场景)
│
├─ VisionKit无法工作?
│ └─ 查看模式8(VisionKit特定问题)
│
├─ 文本识别问题?
│ ├─ 未检测到文本 → 查看模式9a(图像质量)
│ ├─ 字符识别错误 → 查看模式9b(语言/校正设置)
│ └─ 识别过慢 → 查看模式9c(识别级别)
│
├─ 条形码检测问题?
│ ├─ 未检测到条形码 → 查看模式10a(符号体系/尺寸)
│ └─ 载荷内容错误 → 查看模式10b(条码质量)
│
├─ DataScannerViewController问题?
│ ├─ 黑屏 → 查看模式11a(兼容性检查)
│ └─ 未检测到物品 → 查看模式11b(数据类型)
│
└─ 文档扫描问题?
├─ 未检测到边缘 → 查看模式12a(对比度/形状)
└─ 透视效果错误 → 查看模式12b(角点位置)Diagnostic Patterns
诊断模式
Pattern 1a: Request Failed (API Availability)
模式1a:请求失败(API兼容性)
Symptom: throws error
try handler.perform([request])Common errors:
"VNGenerateForegroundInstanceMaskRequest is only available on iOS 17.0 or newer"
"VNDetectHumanBodyPose3DRequest is only available on iOS 17.0 or newer"Root cause: Using iOS 17+ APIs on older deployment target
Fix:
swift
if #available(iOS 17.0, *) {
let request = VNGenerateForegroundInstanceMaskRequest()
// ...
} else {
// Fallback for iOS 14-16
let request = VNGeneratePersonSegmentationRequest()
// ...
}Prevention: Check API availability in before implementing
axiom-vision-refTime to fix: 10 min
症状:抛出错误
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
修复方案:
swift
if #available(iOS 17.0, *) {
let request = VNGenerateForegroundInstanceMaskRequest()
// ...
} else {
// Fallback for iOS 14-16
let request = VNGeneratePersonSegmentationRequest()
// ...
}预防措施:在实现前,先在中检查API兼容性
axiom-vision-ref修复时间:10分钟
Pattern 1b: No Results (Nothing Detected)
模式1b:无结果返回(未检测到任何内容)
Symptom: or
request.results == nilresults.isEmptyDiagnostic:
swift
// 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?Common causes:
- Subject too small (resize or crop closer)
- Subject too blurry (increase lighting, stabilize camera)
- Low contrast (subject same color as background)
Fix:
swift
// Crop image to focus on region of interest
let croppedImage = cropImage(sourceImage, to: regionOfInterest)
let handler = VNImageRequestHandler(cgImage: croppedImage)Time to fix: 30 min
症状: 或
request.results == nilresults.isEmpty诊断方法:
swift
// 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?常见原因:
- 主体过小(小于画面的10%)→ 调整大小或裁剪放大
- 主体模糊 → 增加光线、稳定摄像头
- 对比度低(主体与背景颜色相近)
修复方案:
swift
// Crop image to focus on region of interest
let croppedImage = cropImage(sourceImage, to: regionOfInterest)
let handler = VNImageRequestHandler(cgImage: croppedImage)修复时间:30分钟
Pattern 1c: Edge of Frame Issues
模式1c:画面边缘问题
Symptom: Subject detected intermittently as object moves across frame
Root cause: Partial occlusion when subject touches image edges
Diagnostic:
swift
// 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")
}
}Fix:
swift
// Add padding to capture area
let paddedRect = captureRect.insetBy(dx: -20, dy: -20)
// OR guide user with on-screen overlay
overlayView.addSubview(guideBox) // Visual boundaryTime to fix: 20 min
症状:主体在画面中移动时,检测结果间歇性出现
根本原因:主体接触画面边缘时被部分遮挡
诊断方法:
swift
// 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")
}
}修复方案:
swift
// 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分钟
Pattern 2: Hand Pose Issues
模式2:手部姿态检测问题
Symptom: returns nil or low confidence landmarks
VNDetectHumanHandPoseRequestDiagnostic:
swift
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)")
}
}
}Common causes:
| Cause | Confidence Pattern | Fix |
|---|---|---|
| Hand near edge | Tips have low confidence | Adjust framing |
| Hand parallel to camera | All landmarks low | Prompt user to rotate hand |
| Gloves/occlusion | Fingers low, wrist high | Remove gloves or change lighting |
| Feet detected as hands | Unexpected hand detected | Add |
Fix for parallel hand:
swift
// Detect and warn user
if avgConfidence < 0.4 {
showWarning("Rotate your hand toward the camera")
}Time to fix: 45 min
症状:返回空值或低置信度关键点
VNDetectHumanHandPoseRequest诊断方法:
swift
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)")
}
}
}常见原因:
| 原因 | 置信度模式 | 修复方案 |
|---|---|---|
| 手靠近画面边缘 | 指尖置信度低 | 调整取景范围 |
| 手与摄像头平行 | 所有关键点置信度低 | 提示用户旋转手部 |
| 戴手套/被遮挡 | 手指置信度低、手腕置信度高 | 摘下手套或调整光线 |
| 脚被识别为手 | 检测到意外的手部 | 添加 |
平行手部的修复方案:
swift
// Detect and warn user
if avgConfidence < 0.4 {
showWarning("Rotate your hand toward the camera")
}修复时间:45分钟
Pattern 3: Body Pose Issues
模式3:人体姿态检测问题
Symptom: skips frames or returns low confidence
VNDetectHumanBodyPoseRequestDiagnostic:
swift
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")
}
}
}Common causes:
| Cause | Solution |
|---|---|
| Person bent over | Prompt user to stand upright |
| Upside down (handstand) | Use ARKit instead (better for dynamic poses) |
| Flowing clothing | Increase contrast or use tighter clothing |
| Multiple people overlapping | Use person instance segmentation |
Time to fix: 1 hour
症状:跳过帧或返回低置信度结果
VNDetectHumanBodyPoseRequest诊断方法:
swift
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")
}
}
}常见原因:
| 原因 | 解决方案 |
|---|---|
| 人物弯腰 | 提示用户站直 |
| 倒立(手倒立) | 使用ARKKit替代(更适合动态姿态) |
| 穿着宽松衣物 | 增加对比度或穿着紧身衣物 |
| 多人重叠 | 使用人物实例分割功能 |
修复时间:1小时
Pattern 4: Face Detection Issues
模式4:面部检测问题
Symptom: misses faces or returns wrong count
VNDetectFaceRectanglesRequestDiagnostic:
swift
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")
}
}
}Common causes:
- Face < 10% of image (crop closer)
- Profile view (use face landmarks request instead)
- Poor lighting (increase exposure)
Time to fix: 30 min
症状:遗漏面部或返回错误的数量
VNDetectFaceRectanglesRequest诊断方法:
swift
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分钟
Pattern 5a: UI Freezing (Main Thread)
模式5a:UI冻结(主线程问题)
Symptom: App freezes when performing Vision request
Diagnostic (Step 3 above confirms main thread)
Fix:
swift
// 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
}
}Time to fix: 15 min
症状:执行Vision请求时应用冻结
诊断结果(步骤3已确认在主线程运行)
修复方案:
swift
// 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分钟
Pattern 5b: Performance Issues (Background Thread)
模式5b:性能问题(后台线程)
Symptom: Already on background thread but still slow / dropping frames
Diagnostic:
swift
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")
}Common causes & fixes:
| Cause | Fix | Time Saved |
|---|---|---|
| Set to actual need (e.g., 2) | 50-70% |
| Processing every frame | Skip frames (process every 3rd) | 66% |
| Full-res images | Downscale to 1280x720 | 40-60% |
| Multiple requests per frame | Batch or alternate requests | 30-50% |
Fix for real-time camera:
swift
// 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 defaultTime to fix: 1 hour
症状:已在后台线程运行,但仍缓慢/丢帧
诊断方法:
swift
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")
}常见原因及修复方案:
| 原因 | 修复方案 | 时间节省比例 |
|---|---|---|
| 设置为实际需求(例如2) | 50-70% |
| 处理每一帧 | 跳过部分帧(每3帧处理1帧) | 66% |
| 全分辨率图像 | 缩小至1280x720 | 40-60% |
| 每帧执行多个请求 | 批量处理或交替执行请求 | 30-50% |
实时摄像头的修复方案:
swift
// 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小时
Pattern 6: Coordinate Conversion
模式6:坐标转换问题
Symptom: UI overlays appear in wrong position
Diagnostic:
swift
// 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)Common mistakes:
swift
// ❌ 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
)Time to fix: 20 min
症状:UI覆盖层位置错误
诊断方法:
swift
// 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)常见错误:
swift
// ❌ 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分钟
Pattern 7: Crowded Scenes (>4 People)
模式7:拥挤场景(超过4人)
Symptom: misses people or combines them
VNGeneratePersonInstanceMaskRequestDiagnostic:
swift
// 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")
}Fix:
swift
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)")
}Time to fix: 30 min
症状:遗漏人物或合并人物
VNGeneratePersonInstanceMaskRequest诊断方法:
swift
// 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")
}修复方案:
swift
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分钟
Pattern 8: VisionKit Specific Issues
模式8:VisionKit特定问题
Symptom: not showing subject lifting UI
ImageAnalysisInteractionDiagnostic:
swift
// 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")
}Common causes:
| Symptom | Cause | Fix |
|---|---|---|
| No UI appears | | Call |
| UI appears but no subject lifting | Wrong interaction type | Set |
| Crash on interaction | View removed before interaction | Keep view in memory |
Fix:
swift
// Ensure analysis is set
let analyzer = ImageAnalyzer()
let analysis = try await analyzer.analyze(image, configuration: config)
interaction.analysis = analysis // Required!
interaction.preferredInteractionTypes = .imageSubjectTime to fix: 20 min
症状:未显示主体悬浮UI
ImageAnalysisInteraction诊断方法:
swift
// 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显示 | | 调用 |
| UI显示但无主体悬浮 | 交互类型错误 | 设置为 |
| 交互时崩溃 | 交互前视图已被移除 | 保持视图在内存中 |
修复方案:
swift
// Ensure analysis is set
let analyzer = ImageAnalyzer()
let analysis = try await analyzer.analyze(image, configuration: config)
interaction.analysis = analysis // Required!
interaction.preferredInteractionTypes = .imageSubject修复时间:20分钟
Pattern 9a: Text Not Detected (Image Quality)
模式9a:未检测到文本(图像质量问题)
Symptom: returns no results or empty strings
VNRecognizeTextRequestDiagnostic:
swift
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)")
}
}Common causes:
| Cause | Symptom | Fix |
|---|---|---|
| Blurry image | No results | Improve lighting, stabilize camera |
| Text too small | No results | Lower |
| Stylized font | Misread or no results | Try |
| Low contrast | Partial results | Improve lighting, increase image contrast |
| Rotated text | No results with | Use |
Fix for small text:
swift
// Lower minimum text height (default ignores very small text)
request.minimumTextHeight = 0.02 // 2% of image heightTime to fix: 30 min
症状:无结果返回或返回空字符串
VNRecognizeTextRequest诊断方法:
swift
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)")
}
}常见原因:
| 原因 | 症状 | 修复方案 |
|---|---|---|
| 图像模糊 | 无结果 | 改善光线、稳定摄像头 |
| 文本过小 | 无结果 | 降低 |
| 字体风格特殊 | 识别错误或无结果 | 尝试使用 |
| 对比度低 | 部分结果 | 改善光线、提高图像对比度 |
| 文本旋转 | 使用 | 使用 |
小文本的修复方案:
swift
// Lower minimum text height (default ignores very small text)
request.minimumTextHeight = 0.02 // 2% of image height修复时间:30分钟
Pattern 9b: Wrong Characters (Language/Correction)
模式9b:字符识别错误(语言/设置问题)
Symptom: Text is detected but characters are wrong (e.g., "C001" → "COOL")
Diagnostic:
swift
// 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))")
}
}Common causes:
| Input Type | Problem | Fix |
|---|---|---|
| Serial numbers | Language correction "fixes" them | Disable |
| Technical codes | Misread as words | Add to |
| Non-English | Wrong ML model | Set correct |
| House numbers | Stylized → misread | Check all candidates, not just top |
Fix for codes/serial numbers:
swift
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")
}Time to fix: 30 min
症状:文本已检测到但字符错误(例如"C001" → "COOL")
诊断方法:
swift
// 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))")
}
}常见原因:
| 输入类型 | 问题 | 修复方案 |
|---|---|---|
| 序列号 | 语言校正"修正"了序列号 | 禁用 |
| 技术代码 | 被误识别为普通词汇 | 添加到 |
| 非英文文本 | ML模型错误 | 设置正确的 |
| 门牌号 | 风格特殊导致识别错误 | 检查所有候选结果,而非仅第一个 |
代码/序列号的修复方案:
swift
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分钟
Pattern 9c: Text Recognition Too Slow
模式9c:文本识别过慢
Symptom: Text recognition takes >500ms, real-time camera drops frames
Diagnostic:
swift
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)")Common causes & fixes:
| Cause | Fix | Speedup |
|---|---|---|
Using | Switch to | 3-5x |
| Language correction enabled | Disable for codes | 20-30% |
| Full image processing | Use | 2-4x |
| Processing every frame | Skip frames | 50-70% |
Fix for real-time:
swift
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 }Time to fix: 30 min
症状:文本识别耗时超过500ms,实时摄像头丢帧
诊断方法:
swift
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)")常见原因及修复方案:
| 原因 | 修复方案 | 提速比例 |
|---|---|---|
实时场景使用 | 切换为 | 3-5倍 |
| 已启用语言校正 | 针对代码类文本禁用 | 20-30% |
| 处理全图像 | 使用 | 2-4倍 |
| 处理每一帧 | 跳过部分帧 | 50-70% |
实时场景的修复方案:
swift
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分钟
Pattern 10a: Barcode Not Detected (Symbology/Size)
模式10a:未检测到条形码(符号体系/尺寸问题)
Symptom: returns no results
VNDetectBarcodesRequestDiagnostic:
swift
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")
}Common causes:
| Cause | Symptom | Fix |
|---|---|---|
| Wrong symbology | Not detected | Don't filter, or add correct type |
| Barcode too small | Not detected | Move camera closer, crop image |
| Glare/reflection | Not detected | Change angle, improve lighting |
| Damaged barcode | Partial/no detection | Clean barcode, improve image |
| Using revision 1 | Only one code | Use revision 2+ for multiple |
Fix for small barcodes:
swift
// Crop to barcode region for better detection
let croppedHandler = VNImageRequestHandler(
cgImage: croppedImage,
options: [:]
)Time to fix: 20 min
症状:无结果返回
VNDetectBarcodesRequest诊断方法:
swift
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+以支持多个条码 |
小条码的修复方案:
swift
// Crop to barcode region for better detection
let croppedHandler = VNImageRequestHandler(
cgImage: croppedImage,
options: [:]
)修复时间:20分钟
Pattern 10b: Wrong Barcode Payload
模式10b:条形码载荷内容错误
Symptom: Barcode detected but is wrong or nil
payloadStringValueDiagnostic:
swift
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)")
}Common causes:
| Cause | Fix |
|---|---|
| Binary barcode (not string) | Use |
| Damaged code | Re-scan or clean barcode |
| Wrong symbology assumed | Check actual |
Time to fix: 15 min
症状:已检测到条形码但错误或为空
payloadStringValue诊断方法:
swift
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)")
}常见原因:
| 原因 | 修复方案 |
|---|---|
| 二进制条码(非字符串类型) | 使用 |
| 条码损坏 | 重新扫描或清洁条码 |
| 假设的符号体系错误 | 检查实际的 |
修复时间:15分钟
Pattern 11a: DataScanner Blank Screen
模式11a:DataScanner黑屏
Symptom: shows black/blank when presented
DataScannerViewControllerDiagnostic:
swift
// 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)")Common causes:
| Symptom | Cause | Fix |
|---|---|---|
| Device lacks camera/chip | Check before presenting |
| Parental controls or access denied | Request camera permission |
| Black screen | Camera in use by another app | Ensure exclusive access |
| Crash on present | Missing entitlements | Add camera usage description |
Fix:
swift
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
}Time to fix: 15 min
症状:展示时显示黑屏/空白
DataScannerViewController诊断方法:
swift
// 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)")常见原因:
| 症状 | 原因 | 修复方案 |
|---|---|---|
| 设备缺少摄像头/芯片 | 展示前先检查 |
| 家长控制或权限被拒绝 | 请求摄像头权限 |
| 黑屏 | 摄像头被其他应用占用 | 确保独占访问权限 |
| 展示时崩溃 | 缺少权限描述 | 添加摄像头使用描述 |
修复方案:
swift
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分钟
Pattern 11b: DataScanner Items Not Detected
模式11b:DataScanner未检测到物品
Symptom: DataScanner shows camera but doesn't recognize items
Diagnostic:
swift
// 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
}
}
}Common causes:
| Cause | Fix |
|---|---|
| Wrong data types | Add correct |
| Text content type filter | Remove filter or use correct type |
| Camera too close/far | Adjust distance |
| Poor lighting | Improve lighting |
Time to fix: 20 min
症状:DataScanner显示摄像头画面但未识别到物品
诊断方法:
swift
// 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
}
}
}常见原因:
| 原因 | 修复方案 |
|---|---|
| 数据类型错误 | 添加正确的 |
| 文本内容类型过滤 | 移除过滤器或使用正确的类型 |
| 摄像头过近/过远 | 调整距离 |
| 光线不佳 | 改善光线 |
修复时间:20分钟
Pattern 12a: Document Edges Not Detected
模式12a:未检测到文档边缘
Symptom: returns no results
VNDetectDocumentSegmentationRequestDiagnostic:
swift
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")
}Common causes:
| Cause | Fix |
|---|---|
| Low contrast | Use contrasting background |
| Non-rectangular | ML expects rectangular documents |
| Glare/reflection | Change lighting angle |
| Document fills frame | Need some background visible |
Fix: Use VNDocumentCameraViewController for guided user experience with live feedback.
Time to fix: 15 min
症状:无结果返回
VNDetectDocumentSegmentationRequest诊断方法:
swift
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分钟
Pattern 12b: Perspective Correction Wrong
模式12b:透视校正错误
Symptom: Document extracted but distorted
Diagnostic:
swift
// 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)Common causes:
| Cause | Fix |
|---|---|
| Corner order wrong | Vision uses counterclockwise from top-left |
| Coordinate system | Convert normalized to pixel coordinates |
| Filter parameters wrong | Check CIPerspectiveCorrection parameters |
Fix:
swift
// Scale normalized to image coordinates
func scaled(_ point: CGPoint, to size: CGSize) -> CGPoint {
CGPoint(x: point.x * size.width, y: point.y * size.height)
}Time to fix: 20 min
症状:提取的文档存在变形
诊断方法:
swift
// 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参数 |
修复方案:
swift
// 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分钟
Production Crisis Scenario
生产环境紧急场景
Situation: App Store review rejected for "app freezes when tapping analyze button"
Triage (5 min):
- Confirm Vision running on main thread → Pattern 5a
- Verify on older device (iPhone 12) → Freezes
- Check profiling: 800ms on main thread
Fix (15 min):
swift
@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)
}
}
}Communicate to PM:
"App Store rejection due to Vision processing on main thread. Fixed by moving to background queue (industry standard). Testing on iPhone 12 confirms fix. Safe to resubmit."
场景:App Store审核因"点击分析按钮时应用冻结"被拒绝
快速排查(5分钟):
- 确认Vision在主线程运行 → 模式5a
- 在旧设备(iPhone 12)上验证 → 确实冻结
- 性能分析:主线程耗时800ms
修复方案(15分钟):
swift
@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)
}
}
}向产品经理汇报:
"App Store审核被拒原因是Vision处理任务在主线程运行。已通过迁移至后台队列修复(行业标准做法)。在iPhone 12上测试确认修复有效,可重新提交审核。"
Quick Reference Table
快速参考表
| Symptom | Likely Cause | First Check | Pattern | Est. Time |
|---|---|---|---|---|
| No results | Nothing detected | Step 1 output | 1b/1c | 30 min |
| Intermittent detection | Edge of frame | Subject position | 1c | 20 min |
| Hand missing landmarks | Low confidence | Step 2 (confidence) | 2 | 45 min |
| Body pose skipped | Person bent over | Body angle | 3 | 1 hour |
| UI freezes | Main thread | Step 3 (threading) | 5a | 15 min |
| Slow processing | Performance tuning | Request timing | 5b | 1 hour |
| Wrong overlay position | Coordinates | Print points | 6 | 20 min |
| Missing people (>4) | Crowded scene | Face count | 7 | 30 min |
| VisionKit no UI | Analysis not set | Interaction state | 8 | 20 min |
| Text not detected | Image quality | Results count | 9a | 30 min |
| Wrong characters | Language settings | Candidates list | 9b | 30 min |
| Text recognition slow | Recognition level | Timing | 9c | 30 min |
| Barcode not detected | Symbology/size | Results dump | 10a | 20 min |
| Wrong barcode payload | Damaged/binary | Payload data | 10b | 15 min |
| DataScanner blank | Availability | isSupported/isAvailable | 11a | 15 min |
| DataScanner no items | Data types | recognizedDataTypes | 11b | 20 min |
| Document edges missing | Contrast/shape | Results check | 12a | 15 min |
| Perspective wrong | Corner order | Corner positions | 12b | 20 min |
| 症状 | 可能原因 | 首要检查项 | 对应模式 | 预计修复时间 |
|---|---|---|---|---|
| 无结果返回 | 未检测到任何内容 | 步骤1输出 | 1b/1c | 30分钟 |
| 检测结果间歇性出现 | 主体在画面边缘 | 主体位置 | 1c | 20分钟 |
| 手部关键点缺失 | 置信度低 | 步骤2(置信度) | 2 | 45分钟 |
| 人体姿态帧被跳过 | 人物弯腰 | 人体角度 | 3 | 1小时 |
| UI冻结 | 主线程运行 | 步骤3(线程处理) | 5a | 15分钟 |
| 处理过慢 | 性能调优 | 请求耗时 | 5b | 1小时 |
| 覆盖层位置错误 | 坐标问题 | 打印坐标点 | 6 | 20分钟 |
| 遗漏人物(超过4人) | 拥挤场景 | 面部数量 | 7 | 30分钟 |
| VisionKit无UI显示 | Analysis未设置 | 交互状态 | 8 | 20分钟 |
| 未检测到文本 | 图像质量 | 结果数量 | 9a | 30分钟 |
| 字符识别错误 | 语言设置 | 候选结果列表 | 9b | 30分钟 |
| 文本识别过慢 | 识别级别 | 耗时统计 | 9c | 30分钟 |
| 未检测到条形码 | 符号体系/尺寸 | 结果详情 | 10a | 20分钟 |
| 条形码载荷错误 | 损坏/二进制 | 载荷数据 | 10b | 15分钟 |
| DataScanner黑屏 | 兼容性 | isSupported/isAvailable | 11a | 15分钟 |
| DataScanner未检测到物品 | 数据类型 | recognizedDataTypes | 11b | 20分钟 |
| 未检测到文档边缘 | 对比度/形状 | 结果检查 | 12a | 15分钟 |
| 透视效果错误 | 角点顺序 | 角点位置 | 12b | 20分钟 |
Resources
参考资源
WWDC: 2019-234, 2021-10041, 2022-10024, 2022-10025, 2025-272, 2023-10176, 2020-10653
Docs: /vision, /vision/vnrecognizetextrequest, /visionkit
Skills: axiom-vision, axiom-vision-ref
WWDC:2019-234, 2021-10041, 2022-10024, 2022-10025, 2025-272, 2023-10176, 2020-10653
文档:/vision, /vision/vnrecognizetextrequest, /visionkit
技能:axiom-vision, axiom-vision-ref