关于 vision-framework
面向 Apple 平台开发者的 Vision 技能,介绍使用设备端计算机视觉处理图像和视频。涵盖现代异步请求、旧版 API 回退,以及 VisionKit 和 Core ML 集成。
主要功能
- 01识别文本、面部和条码
- 02读取结构化文档内容
- 03生成分割遮罩并跟踪对象
- 04检测人体、手部和动物姿态
- 05通过 Vision 运行 Core ML 模型
- 06使用 VisionKit 实时扫描文本和条码
适用场景
- 01从图片中提取文字或条码内容
- 02扫描并解析文档布局
- 03为视频帧中的对象持续跟踪
- 04生成用于图像效果的人像遮罩
- 05在相机画面中扫描文字或条码
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ dpearson2699/ swift-ios-skills --skill vision-framework安装后在 Claude Code 中输入/vision-framework确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
evals/evals.jsonreferences/vision-requests.mdvisionkit-scanner.md详细介绍
Vision Framework
使用设备端计算机视觉在图像和视频中检测文本、人脸、条码、物体和人体姿势。优先使用现代 iOS 18+ 请求 API,仅在部署目标有要求时才加载旧版参考内容。
完整代码模式请参阅 references/vision-requests.md,DataScannerViewController 集成方式请参阅 references/visionkit-scanner.md。
目录
- 两代 API
- 请求模式(现代 API)
- 文本识别(OCR)
- 人脸检测
- 条码检测
- 文档扫描(iOS 26+)
- 图像分割
- 物体跟踪
- 其他请求类型
- Core ML 集成
- VisionKit:DataScannerViewController
- 常见错误
- 审查清单
- 参考资料
两代 API
Vision 有两个截然不同的 API 层。新代码优先使用现代 API:
Swift 原生请求类型,以及 try await request.perform(on:)。将 VN*、
VNImageRequestHandler、VNSequenceRequestHandler、完成处理程序和
旧版 CGRect 辅助函数保留在明确标注的旧版回退代码段或文件中。
| 方面 | 现代版(iOS 18+) | 旧版 |
|---|---|---|
| 模式 | let result = try await request.perform(on: image) | VNImageRequestHandler + 完成处理程序 |
| 请求类型 | Swift 类型——结构体和类(RecognizeTextRequest、DetectFaceRectanglesRequest) | ObjC 类(VNRecognizeTextRequest、VNDetectFaceRectanglesRequest) |
| 并发 | 原生 async/await | 完成处理程序或同步 perform |
| 观察结果 | 类型化返回值 | 将 results 从 [Any] 转换为所需类型 |
| 可用性 | iOS 18+ / macOS 15+ | iOS 11+ |
现代 API 使用 ImageProcessingRequest 协议。每种请求类型都有一个
perform(on:orientation:) 方法,可接受 CGImage、CIImage、
CVPixelBuffer、CMSampleBuffer、Data 或 URL。大多数请求都是
结构体;GeneratePersonSegmentationRequest、TrackObjectRequest、
TrackRectangleRequest 和 DetectTrajectoriesRequest 等有状态请求
则是 final 类。
请求模式(现代 API)
所有现代 Vision 请求都遵循相同模式:创建请求、调用
perform(on:),然后处理类型化结果。
import Vision
func recognizeText(in image: CGImage) async throws -> [String] {
var request = RecognizeTextRequest()
request.recognitionLevel = .accurate
request.recognitionLanguages = [Locale.Language(identifier: "en-US")]
let observations = try await request.perform(on: image)
return observations.compactMap { observation in
observation.topCandidates(1).first?.string
}
}
旧版模式(iOS 18 之前)
对于部署目标低于 iOS 18 的项目,请使用对应的 VNRequest 和 VNImageRequestHandler 或 VNSequenceRequestHandler。加载 references/vision-requests.md,查看完整的旧版请求和处理程序模式。
文本识别(OCR)
现代版:RecognizeTextRequest(iOS 18+)
var request = RecognizeTextRequest()
request.recognitionLevel = .accurate // .fast for real-time
request.recognitionLanguages = [
Locale.Language(identifier: "en-US"),
Locale.Language(identifier: "fr-FR"),
]
request.usesLanguageCorrection = true
request.customWords = ["SwiftUI", "Xcode"] // domain-specific terms
let observations = try await request.perform(on: cgImage)
for observation in observations {
guard let candidate = observation.topCandidates(1).first else { continue }
let text = candidate.string
let confidence = candidate.confidence // 0.0 ... 1.0
let bounds = observation.boundingBox // NormalizedRect
}
旧版:VNRecognizeTextRequest
旧版请求使用字符串形式的语言标识符,并采用参考资料中的处理程序模式;两代 API 均支持准确和快速识别级别。
人脸检测
检测人脸矩形、面部特征点(眼睛、鼻子、嘴巴)和拍摄质量。
// Modern API
let faceRequest = DetectFaceRectanglesRequest()
let faces = try await faceRequest.perform(on: cgImage)
for face in faces {
let boundingBox = face.boundingBox // NormalizedRect
let roll = face.roll // Measurement<UnitAngle>
let yaw = face.yaw // Measurement<UnitAngle>
}
// Landmarks (eyes, nose, mouth contours)
var landmarkRequest = DetectFaceLandmarksRequest()
let landmarkFaces = try await landmarkRequest.perform(on: cgImage)
for face in landmarkFaces {
let landmarks = face.landmarks
let leftEye = landmarks?.leftEye.points
let nose = landmarks?.nose.points
}
坐标系
Vision 使用原点位于左下角的归一化坐标系。 显示前请转换为 UIKit 坐标系(原点位于左上角):
import Vision
func imageRectForDisplay(_ rect: NormalizedRect, imageSize: CGSize) -> CGRect {
rect.toImageCoordinates(imageSize, origin: .upperLeft)
}
条码检测
检测一维和二维条码,包括 QR 码。
var request = DetectBarcodesRequest()
let symbologies: [BarcodeSymbology] = [.qr, .ean13, .code128, .pdf417]
request.symbologies = symbologies
let barcodes = try await request.perform(on: cgImage)
for barcode in barcodes {
let payload = barcode.payloadString // decoded content
let symbology = barcode.symbology // .qr, .ean13, etc.
let bounds = barcode.boundingBox // NormalizedRect
}
先为局部值添加类型注解,再分别赋值给请求属性。
文档扫描(iOS 26+)
RecognizeDocumentsRequest 可进行结构化文档读取,提供超越基础 OCR 的版面理解能力。它会返回 DocumentObservation 对象,其中包含嵌套的 Container 结构,用于表示段落、表格、列表和条形码。目前,Vision 会为每张图像返回一个文档观察结果。
var request = RecognizeDocumentsRequest()
let documents = try await request.perform(on: cgImage)
for observation in documents {
let container = observation.document
// Full text content
let fullText = container.text
// Structured access to paragraphs
for paragraph in container.paragraphs {
let paragraphText = paragraph.text
}
// Tables and lists
for table in container.tables { /* structured table data */ }
for list in container.lists { /* structured list data */ }
// Embedded barcodes detected within the document
for barcode in container.barcodes { /* barcode data */ }
// Document title if detected
if let title = container.title { print(title) }
}
若要进行更简单的文档相机扫描,请使用 VisionKit 的
VNDocumentCameraViewController,它提供全屏相机界面,支持自动捕获、透视校正和多页扫描。
图像分割
现代方式:GeneratePersonSegmentationRequest(iOS 18+)
var request = GeneratePersonSegmentationRequest()
request.qualityLevel = .accurate // .balanced, .fast
let mask = try await request.perform(on: cgImage)
// mask is a PixelBufferObservation with a pixelBuffer property
let maskBuffer = mask.pixelBuffer
// Apply mask using Core Image: CIFilter.blendWithMask()
旧版方式:VNGeneratePersonSegmentationRequest
对于较早的目标平台,VNGeneratePersonSegmentationRequest 通过第一个像素缓冲区观察结果公开其遮罩;使用参考文档中的处理程序和遮罩合成方案。
质量级别:
.accurate—— 质量最高、速度最慢(约 1 秒),全分辨率.balanced—— 质量较好、速度适中(约 100 毫秒),960x540.fast—— 质量最低、速度最快(约 10 毫秒),256x144,适用于实时场景
实例分割(iOS 18+)
为每个人分别生成遮罩,以便应用个体效果。
// Modern API (iOS 18+)
let request = GeneratePersonInstanceMaskRequest()
let observation = try await request.perform(on: cgImage)
let indices = observation.allInstances
for index in indices {
let mask = try observation.generateMask(for: IndexSet(integer: index))
// mask is a CVPixelBuffer with only this person visible
}
// Legacy API (iOS 17+)
let request = VNGeneratePersonInstanceMaskRequest()
let handler = VNImageRequestHandler(cgImage: cgImage)
try handler.perform([request])
guard let result = request.results?.first else { return }
let indices = result.allInstances
for index in indices {
let instanceMask = try result.generateMaskedImage(
ofInstances: IndexSet(integer: index),
from: handler,
croppedToInstancesExtent: false
)
}
有关遮罩合成和 Core Image 滤镜集成模式,请参阅 references/vision-requests.md。
对象跟踪
现代方式:TrackObjectRequest(iOS 18+)
TrackObjectRequest 是一种有状态请求,可在连续帧之间维持跟踪上下文。
// Initialize with a detected object's bounding box
let initialObservation = DetectedObjectObservation(boundingBox: detectedBox)
let request = TrackObjectRequest(detectedObject: initialObservation)
for pixelBuffer in framePixelBuffers {
let results = try await request.perform(on: pixelBuffer)
if let tracked = results.first {
let updatedBounds = tracked.boundingBox // NormalizedRect
}
}
现代的 TrackObjectRequest 没有 trackingLevel 或 qualityLevel。
旧版方式:VNTrackObjectRequest
对于较早的目标平台,请使用 VNTrackObjectRequest,并保留一个 VNSequenceRequestHandler,再将每次结果作为下一次输入观察结果。参考文档包含完整循环。
其他请求类型
Vision 还提供了其他请求,详见 references/vision-requests.md:
| 请求 | 用途 |
|---|---|
ClassifyImageRequest | 对场景内容进行分类(户外、食物、动物等) |
GenerateAttentionBasedSaliencyImageRequest | 返回单个 SaliencyImageObservation,表示观看者注意力集中的位置 |
GenerateObjectnessBasedSaliencyImageRequest | 返回单个 SaliencyImageObservation,表示类似对象的区域 |
GenerateForegroundInstanceMaskRequest | 前景对象分割(不限于人物) |
DetectRectanglesRequest | 检测矩形形状(文档、卡片、屏幕) |
DetectHorizonRequest | 检测地平线角度,以自动校平照片 |
DetectHumanBodyPoseRequest | 检测身体关节(肩部、肘部、膝部) |
DetectHumanBodyPose3DRequest | 估算 3D 人体姿势 |
DetectHumanHandPoseRequest | 检测手部关节和手指位置 |
DetectAnimalBodyPoseRequest | 检测动物身体关节位置 |
DetectFaceCaptureQualityRequest | 对人脸拍摄质量进行评分(0–1),用于选择照片 |
TrackRectangleRequest | 跟踪视频帧中的矩形对象 |
TrackOpticalFlowRequest | 计算视频帧之间的光流 |
DetectTrajectoriesRequest | 检测视频中的对象轨迹 |
以上所有现代请求类型均适用于 iOS 18+ / macOS 15+。
Core ML 集成
通过 Vision 运行自定义 Core ML 模型,自动完成图像预处理。
Vision 使用 CoreMLRequest 或 VNCoreMLRequest 运行已准备好的模型;
模型转换、性能分析、打包和生命周期决策请交由 coreml 处理。
import CoreML
import Vision
// Modern API (iOS 18+): CoreMLRequest takes a CoreMLModelContainer.
let model = try MLModel(contentsOf: modelURL)
let container = try CoreMLModelContainer(model: model, featureProvider: nil)
let request = CoreMLRequest(model: container)
let results = try await request.perform(on: cgImage)
// Classification model
if let classification = results.first as? ClassificationObservation {
let label = classification.identifier
let confidence = classification.confidence
}
CoreMLModelContainer 是 Vision 面向 iOS 18+ 的公开容器,供 CoreMLRequest 使用:加载 MLModel,使用 CoreMLModelContainer(model:featureProvider:) 将其封装,然后将该容器传递给 CoreMLRequest(model:)。查看通过 Vision 使用 Core ML 时的结果映射:分类器会生成 ClassificationObservation,图像输出会生成 PixelBufferObservation,通用预测器会生成 CoreMLFeatureValueObservation。
// Legacy API
let vnModel = try VNCoreMLModel(for: model)
let request = VNCoreMLRequest(model: vnModel) { request, error in
guard let results = request.results as? [VNClassificationObservation] else { return }
let topResult = results.first
}
let handler = VNImageRequestHandler(cgImage: cgImage)
try handler.perform([request])
VisionKit:DataScannerViewController
DataScannerViewController 提供实时摄像头扫描器,可扫描文本和条形码;请参阅 references/visionkit-scanner.md。VisionKit 使用 VNBarcodeSymbology;现代的 DetectBarcodesRequest 使用 BarcodeSymbology。
快速入门
import AVFoundation
import Vision
import VisionKit
@MainActor
func presentScanner() async {
// Add NSCameraUsageDescription before requesting camera access.
guard await AVCaptureDevice.requestAccess(for: .video) else { return }
guard DataScannerViewController.isSupported,
DataScannerViewController.isAvailable else { return }
let scannerSymbologies: [VNBarcodeSymbology] = [.qr, .ean13]
let scanner = DataScannerViewController(
recognizedDataTypes: [
.text(languages: ["en"]),
.barcode(symbologies: scannerSymbologies)
],
qualityLevel: .balanced,
recognizesMultipleItems: true,
isHighFrameRateTrackingEnabled: true,
isHighlightingEnabled: true
)
scanner.delegate = self
present(scanner, animated: true) {
// Start scanning after presentation, on the main actor.
try? scanner.startScanning()
}
}
SwiftUI 集成
将 DataScannerViewController 封装在 UIViewControllerRepresentable 中,并在 updateUIViewController 中使用 Task { @MainActor in try? controller.startScanning() } 启动扫描;请参阅 references/visionkit-scanner.md。
常见错误
不要: 在新的 iOS 18+ 项目中使用旧版 VNImageRequestHandler API。
应该: 使用现代 Swift 原生请求,通过 perform(on:) 和 async/await 执行。
原因: 现代 API 提供类型安全性、更好的 Swift 并发支持,以及更简洁的错误处理。
不要: 绘制边界框前忘记转换归一化坐标。
应该: 对现代观测结果使用 NormalizedRect.toImageCoordinates(_:origin:),或对旧版 CGRect 观测结果使用 VNImageRectForNormalizedRect(_:_:_:)。
原因: Vision 使用左下角为原点的归一化坐标(0...1);UIKit 使用左上角为原点的点坐标。
不要: 在主线程上运行 Vision 请求。 应该: 在后台线程上执行请求,或从分离任务中使用 async/await。 原因: 图像分析会大量占用 CPU/GPU,在主执行器上运行会阻塞 UI。
不要: 对实时摄像头画面使用 .accurate 识别级别。
应该: 实时视频使用 .fast,静态图像或离线处理使用 .accurate。
原因: 准确识别对于 30fps 视频来说太慢;快速识别则以牺牲质量换取速度。
不要: 认为所有 Vision 观测结果都具有相同属性。 应该: 在编写共享辅助函数前,检查每种观测类型的边界框、置信度、负载、蒙版或角度字段。 原因: 现代 Vision 返回强类型观测结果,不同请求的结果结构也各不相同。
不要: 为每一帧视频重新创建有状态跟踪请求。
应该: 保留同一个现代 TrackObjectRequest 实例,或将 VNSequenceRequestHandler 与旧版跟踪请求配合使用。
原因: 跟踪依赖连续帧之间的时序上下文。
不要: 只需要 QR 码时仍请求所有条形码符号类型。 应该: 在请求中仅指定所需的符号类型。 原因: 符号类型越少,检测越快,误报也越少。
不要: 假定所有设备都支持 DataScannerViewController。
应该: 展示前检查 isSupported(硬件支持情况)和 isAvailable(用户权限)。
原因: 此功能需要 A12+ 芯片;isAvailable 还会检查摄像头访问授权。
检查清单
- 使用现代 Vision API(iOS 18+),除非目标部署版本较旧
- Vision 请求在主线程之外运行(async/await 或后台队列)
- 在 UI 中显示前转换归一化坐标
- 应用置信度阈值,过滤低质量观测结果
- 识别级别符合使用场景(视频使用
.fast,静态图像使用.accurate) - 已知输入语言时,为文本识别设置语言提示
- 条形码符号类型仅限所需类型
- 展示前检查
DataScannerViewController是否可用 - 在 Info.plist 中为 VisionKit 配置摄像头使用说明(
NSCameraUsageDescription) - 展示前请求 VisionKit 摄像头访问权限,并在展示后开始扫描
- 人物分割质量级别符合使用场景
- 在视频帧之间保留有状态跟踪请求或
VNSequenceRequestHandler - 错误处理涵盖请求失败和结果为空的情况
References
- Vision request patterns: references/vision-requests.md
- VisionKit scanner integration: references/visionkit-scanner.md
- Apple docs: Vision | VisionKit | RecognizeTextRequest | DataScannerViewController | CoreMLRequest | CoreMLModelContainer