关于 axiom-vision-ref
面向 iOS 开发者的 Vision 框架 API 参考,涵盖图像分割、姿态与人脸检测、OCR、条码识别和文档扫描。内容包括请求处理器选择、API 用法及视频序列中的状态处理。
主要功能
- 01前景与人物分割 API
- 02手部和身体姿态检测
- 03人脸分析与文本识别
- 04条码检测和文档扫描
- 05图像与序列请求处理器说明
适用场景
- 01从图像提取前景主体
- 02为手势或健身应用追踪姿态
- 03在图像中识别文字或条码
- 04构建实时扫描与文档识别功能
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ charleswiltgen/ axiom --skill axiom-vision-ref安装后在 Claude Code 中输入/axiom-vision-ref确认已加载。
详细介绍
Vision 框架 API 参考
Vision 框架计算机视觉综合参考:主体分割、手部/身体姿势检测、人物检测、人脸分析、文本识别(OCR)、条码检测和文档扫描。
何时使用此参考
- 使用 VisionKit 或 Vision 实现主体提取
- 检测手部/身体姿势,用于手势识别或健身应用
- 分割人物,将其从背景中分离或分离多个个体
- 人脸检测和特征点,用于 AR 效果或身份验证
- 组合使用 Vision API,解决复杂的计算机视觉问题
- 查询特定 API 签名和参数含义
- 使用 VNRecognizeTextRequest 在图像中识别文本(OCR)
- 使用 VNDetectBarcodesRequest 检测条码和二维码
- 使用 DataScannerViewController 构建实时扫描器
- 使用 VNDocumentCameraViewController 扫描文档
- 使用 RecognizeDocumentsRequest 提取结构化文档数据(iOS 26+)
相关技能:决策树和模式请参阅 axiom-vision,故障排查请参阅 axiom-vision-diag
Vision 框架概览
Vision 为静态图像和视频提供计算机视觉算法:
核心工作流:
- 创建请求(例如,
VNDetectHumanHandPoseRequest()) - 使用图像创建处理器(
VNImageRequestHandler(cgImage: image)) - 执行请求(
try handler.perform([request])) - 从
request.results访问观察结果
坐标系:左下角为原点,坐标归一化至 0.0-1.0
性能:在后台队列运行——资源占用较高;若在主线程运行,会阻塞 UI
请求处理器
Vision 为不同场景提供两种请求处理器。
VNImageRequestHandler
分析单张图像。使用图像初始化,对其执行请求,然后丢弃处理器。
let handler = VNImageRequestHandler(cgImage: image)
try handler.perform([request1, request2]) // Multiple requests, one image
可使用以下类型初始化:CGImage、CIImage、CVPixelBuffer、Data 或 URL
规则:每张图像使用一个处理器。不支持将同一处理器用于不同图像。
VNSequenceRequestHandler
分析一系列帧(视频、相机画面)。先进行空初始化,再将每一帧传递给 perform()。会维护帧间状态,以实现时间平滑处理。
let sequenceHandler = VNSequenceRequestHandler()
// In your camera/video frame callback:
func processFrame(_ pixelBuffer: CVPixelBuffer) throws {
try sequenceHandler.perform([request], on: pixelBuffer)
}
规则:创建一次,并在多帧间重复使用。处理器会在调用之间跟踪状态。
如何选择
| 使用场景 | 处理器 |
|---|---|
| 单张照片或屏幕截图 | VNImageRequestHandler |
| 视频流或相机帧 | VNSequenceRequestHandler |
| 时间平滑处理(姿势、分割) | VNSequenceRequestHandler |
| 对 CVPixelBuffer 进行一次性分析 | VNImageRequestHandler |
适合使用序列处理的请求
通过 VNSequenceRequestHandler 运行时,这些请求会使用帧间状态:
VNDetectHumanBodyPoseRequest— 更平滑地跟踪关节VNDetectHumanHandPoseRequest— 更平滑地跟踪特征点VNGeneratePersonSegmentationRequest— 时间上更一致的蒙版VNGeneratePersonInstanceMaskRequest— 在多帧间保持人物身份稳定VNDetectDocumentSegmentationRequest— 稳定的文档边缘- 任何
VNStatefulRequest子类 — 专为序列设计
常见错误
为每个视频帧新建一个 VNImageRequestHandler 会丢弃时间上下文。姿势特征点会抖动,分割蒙版会闪烁,也无法获得序列处理带来的平滑效果。
// Wrong — loses temporal context every frame
func processFrame(_ buffer: CVPixelBuffer) throws {
let handler = VNImageRequestHandler(cvPixelBuffer: buffer)
try handler.perform([poseRequest])
}
// Right — maintains inter-frame state
let sequenceHandler = VNSequenceRequestHandler()
func processFrame(_ buffer: CVPixelBuffer) throws {
try sequenceHandler.perform([poseRequest], on: buffer)
}
主体分割 API
VNGenerateForegroundInstanceMaskRequest
可用性:iOS 17+、macOS 14+、tvOS 17+、visionOS 1+
生成前景对象(人物、宠物、建筑、食物、鞋子等)的类别无关实例蒙版。
基本用法
let request = VNGenerateForegroundInstanceMaskRequest()
let handler = VNImageRequestHandler(cgImage: image)
try handler.perform([request])
guard let observation = request.results?.first as? VNInstanceMaskObservation else {
return
}
InstanceMaskObservation
allInstances:包含所有前景实例索引的 IndexSet(不包括背景 0)
instanceMask:包含 UInt8 标签的 CVPixelBuffer(0 = 背景,1+ = 实例索引)
instanceAtPoint(_:):返回归一化坐标点处的实例索引
let point = CGPoint(x: 0.5, y: 0.5) // Center of image
let instance = observation.instanceAtPoint(point)
if instance == 0 {
print("Background tapped")
} else {
print("Instance \(instance) tapped")
}
生成蒙版
createScaledMask(for:croppedToInstancesContent:)
参数:
for:要包含的实例的IndexSetcroppedToInstancesContent:false= 输出与输入分辨率一致(用于合成)true= 紧密裁剪所选实例周围的区域
返回值:单通道浮点型 CVPixelBuffer(软分割蒙版)
// All instances, full resolution
let mask = try observation.createScaledMask(
for: observation.allInstances,
croppedToInstancesContent: false
)
// Single instance, cropped
let instances = IndexSet(integer: 1)
let croppedMask = try observation.createScaledMask(
for: instances,
croppedToInstancesContent: true
)
实例蒙版命中测试
访问原始像素缓冲区,将点击坐标映射到实例标签:
let instanceMask = observation.instanceMask
CVPixelBufferLockBaseAddress(instanceMask, .readOnly)
defer { CVPixelBufferUnlockBaseAddress(instanceMask, .readOnly) }
let baseAddress = CVPixelBufferGetBaseAddress(instanceMask)
let width = CVPixelBufferGetWidth(instanceMask)
let bytesPerRow = CVPixelBufferGetBytesPerRow(instanceMask)
// Convert normalized tap to pixel coordinates
let pixelPoint = VNImagePointForNormalizedPoint(
CGPoint(x: normalizedX, y: normalizedY),
width: imageWidth,
height: imageHeight
)
// Calculate byte offset
let offset = Int(pixelPoint.y) * bytesPerRow + Int(pixelPoint.x)
// Read instance label
let label = UnsafeRawPointer(baseAddress!).load(
fromByteOffset: offset,
as: UInt8.self
)
let instances = label == 0 ? observation.allInstances : IndexSet(integer: Int(label))
VisionKit 主体提取
ImageAnalysisInteraction(iOS)
可用性:iOS 16+、iPadOS 16+
为视图添加类似系统的主体提取 UI:
let interaction = ImageAnalysisInteraction()
interaction.preferredInteractionTypes = .imageSubject // Or .automatic
imageView.addInteraction(interaction)
交互类型:
.automatic:主体提取 + 实况文本 + 数据检测器.imageSubject:仅主体提取(无交互式文本)
ImageAnalysisOverlayView(macOS)
可用性:macOS 13+
let overlayView = ImageAnalysisOverlayView()
overlayView.preferredInteractionTypes = .imageSubject
nsView.addSubview(overlayView)
编程式访问
ImageAnalyzer
let analyzer = ImageAnalyzer()
let configuration = ImageAnalyzer.Configuration([.text, .visualLookUp])
let analysis = try await analyzer.analyze(image, configuration: configuration)
ImageAnalysis
subjects:[Subject] - 图像中的所有主体
highlightedSubjects:Set<Subject> - 当前高亮的主体(用户长按后)
subject(at:):异步查询标准化坐标点处的主体(如果没有则返回 nil)
// Get all subjects
let subjects = analysis.subjects
// Look up subject at tap
if let subject = try await analysis.subject(at: tapPoint) {
// Process subject
}
// Change highlight state
analysis.highlightedSubjects = Set([subjects[0], subjects[1]])
Subject 结构体
image:UIImage/NSImage - 提取出的透明主体
bounds:CGRect - 主体在图像坐标系中的边界
// Single subject image
let subjectImage = subject.image
// Composite multiple subjects
let compositeImage = try await analysis.image(for: [subject1, subject2])
进程外运行:VisionKit 分析在进程外执行(具有性能优势,但图像尺寸受限)
人体分割 API
VNGeneratePersonSegmentationRequest
可用性:iOS 15+、macOS 12+
返回包含图像中所有人物的单个蒙版:
let request = VNGeneratePersonSegmentationRequest()
// Configure quality level if needed
try handler.perform([request])
guard let observation = request.results?.first as? VNPixelBufferObservation else {
return
}
let personMask = observation.pixelBuffer // CVPixelBuffer
VNGeneratePersonInstanceMaskRequest
可用性:iOS 17+、macOS 14+
返回最多 4 个人物的独立蒙版:
let request = VNGeneratePersonInstanceMaskRequest()
try handler.perform([request])
guard let observation = request.results?.first as? VNInstanceMaskObservation else {
return
}
// Same InstanceMaskObservation API as foreground instance masks
let allPeople = observation.allInstances // Up to 4 people (1-4)
// Get mask for person 1
let person1Mask = try observation.createScaledMask(
for: IndexSet(integer: 1),
croppedToInstancesContent: false
)
限制:
- 最多分割 4 个人物
- 人物超过 4 个时:可能漏掉人物或将他们合并(通常是背景中的人物)
- 如果需要处理拥挤场景,请使用
VNDetectFaceRectanglesRequest统计人脸数量
手部姿势检测
VNDetectHumanHandPoseRequest
可用性:iOS 14+、macOS 11+
检测每只手的21 个关键点:
let request = VNDetectHumanHandPoseRequest()
request.maximumHandCount = 2 // Default: 2, increase if needed
let handler = VNImageRequestHandler(cgImage: image)
try handler.perform([request])
for observation in request.results as? [VNHumanHandPoseObservation] ?? [] {
// Process each hand
}
性能说明:maximumHandCount 会影响延迟。仅计算数量不超过上限的手部姿势。请将其设为可接受的最低值。
手部关键点(21 个点)
手腕:1 个关键点
拇指(4 个关键点):
.thumbTip.thumbIP(指间关节).thumbMP(掌指关节).thumbCMC(腕掌关节)
手指(每根 4 个关键点):
- 指尖(
.indexTip、.middleTip、.ringTip、.littleTip) - DIP(远端指间关节)
- PIP(近端指间关节)
- MCP(掌指关节)
分组键
访问关键点组:
| 分组键 | 点数 |
|---|---|
.all | 全部 21 个关键点 |
.thumb | 4 个拇指关节点 |
.indexFinger | 4 个食指关节点 |
.middleFinger | 4 个中指关节点 |
.ringFinger | 4 个无名指关节点 |
.littleFinger | 4 个小指关节点 |
// Get all points
let allPoints = try observation.recognizedPoints(.all)
// Get index finger points only
let indexPoints = try observation.recognizedPoints(.indexFinger)
// Get specific point
let thumbTip = try observation.recognizedPoint(.thumbTip)
let indexTip = try observation.recognizedPoint(.indexTip)
// Check confidence
guard thumbTip.confidence > 0.5 else { return }
// Access location (normalized coordinates, lower-left origin)
let location = thumbTip.location // CGPoint
手势识别示例(捏合)
let thumbTip = try observation.recognizedPoint(.thumbTip)
let indexTip = try observation.recognizedPoint(.indexTip)
guard thumbTip.confidence > 0.5, indexTip.confidence > 0.5 else {
return
}
let distance = hypot(
thumbTip.location.x - indexTip.location.x,
thumbTip.location.y - indexTip.location.y
)
let isPinching = distance < 0.05 // Normalized threshold
手性(左右手)
let chirality = observation.chirality // .left or .right or .unknown
身体姿势检测
VNDetectHumanBodyPoseRequest(2D)
可用性:iOS 14+、macOS 11+
检测18 个身体关键点(2D 标准化坐标):
let request = VNDetectHumanBodyPoseRequest()
try handler.perform([request])
for observation in request.results as? [VNHumanBodyPoseObservation] ?? [] {
// Process each person
}
身体关键点(18 个点)
面部(5 个关键点):
.nose、.leftEye、.rightEye、.leftEar、.rightEar
手臂(6 个关键点):
- 左侧:
.leftShoulder、.leftElbow、.leftWrist - 右侧:
.rightShoulder、.rightElbow、.rightWrist
躯干(7 个关键点):
.neck(双肩之间).leftShoulder、.rightShoulder(也包含在手臂组中).leftHip、.rightHip.root(双髋之间)
腿部(6 个关键点):
- 左侧:
.leftHip、.leftKnee、.leftAnkle - 右侧:
.rightHip、.rightKnee、.rightAnkle
注意:肩部和髋部会出现在多个分组中
Group Keys(身体)
| Group Key | Points |
|---|---|
.all | 全部 18 个关键点 |
.face | 5 个面部关键点 |
.leftArm | 肩部、肘部、手腕 |
.rightArm | 肩部、肘部、手腕 |
.torso | 颈部、肩部、髋部、根节点 |
.leftLeg | 髋部、膝部、脚踝 |
.rightLeg | 髋部、膝部、脚踝 |
// Get all body points
let allPoints = try observation.recognizedPoints(.all)
// Get left arm only
let leftArmPoints = try observation.recognizedPoints(.leftArm)
// Get specific joint
let leftWrist = try observation.recognizedPoint(.leftWrist)
VNDetectHumanBodyPose3DRequest(3D)
可用性:iOS 17+、macOS 14+
返回以米为单位的 3D 骨架,包含 17 个关节(真实世界坐标):
let request = VNDetectHumanBodyPose3DRequest()
try handler.perform([request])
guard let observation = request.results?.first as? VNHumanBodyPose3DObservation else {
return
}
// Get 3D joint position
let leftWrist = try observation.recognizedPoint(.leftWrist)
let position = leftWrist.position // simd_float4x4 matrix
let localPosition = leftWrist.localPosition // Relative to parent joint
3D 身体关键点(17 个点):与 2D 相同,但不包含耳朵(15 个,而 2D 有 18 个关键点)
3D 观测属性
bodyHeight:估算身高,单位为米
- 有深度数据:测量身高
- 无深度数据:参考身高(1.8m)
heightEstimation:.measured 或 .reference
cameraOriginMatrix:相机相对于主体的位置/方向,类型为 simd_float4x4
pointInImage(_:):将 3D 关节投影回 2D 图像坐标
let wrist2D = try observation.pointInImage(leftWrist)
3D 点类
VNPoint3D:基类,包含 simd_float4x4 位置矩阵
VNRecognizedPoint3D:增加标识符(关节名称)
VNHumanBodyRecognizedPoint3D:增加 localPosition 和 parentJoint
// Position relative to skeleton root (center of hip)
let modelPosition = leftWrist.position
// Position relative to parent joint (left elbow)
let relativePosition = leftWrist.localPosition
深度输入
Vision 接受与图像一同传入的深度数据:
// From AVDepthData
let handler = VNImageRequestHandler(
cvPixelBuffer: imageBuffer,
depthData: depthData,
orientation: orientation
)
// From file (automatic depth extraction)
let handler = VNImageRequestHandler(url: imageURL) // Depth auto-fetched
深度格式:视差或深度(可通过 AVFoundation 互换)
LiDAR:在实时采集会话中使用,可准确测量尺度/距离
人脸检测与关键点
VNDetectFaceRectanglesRequest
可用性:iOS 11+
检测人脸边界框:
let request = VNDetectFaceRectanglesRequest()
try handler.perform([request])
for observation in request.results as? [VNFaceObservation] ?? [] {
let faceBounds = observation.boundingBox // Normalized rect
}
VNDetectFaceLandmarksRequest
可用性:iOS 11+
检测人脸及详细关键点:
let request = VNDetectFaceLandmarksRequest()
try handler.perform([request])
for observation in request.results as? [VNFaceObservation] ?? [] {
if let landmarks = observation.landmarks {
let leftEye = landmarks.leftEye
let nose = landmarks.nose
let leftPupil = landmarks.leftPupil // Revision 2+
}
}
版本:
- 版本 1:基本关键点
- 版本 2:检测倒置的人脸
- 版本 3+:瞳孔位置
人体检测
VNDetectHumanRectanglesRequest
可用性:iOS 13+
检测人体边界框(躯干检测):
let request = VNDetectHumanRectanglesRequest()
try handler.perform([request])
for observation in request.results as? [VNHumanObservation] ?? [] {
let humanBounds = observation.boundingBox // Normalized rect
}
使用场景:只需要定位时,速度比姿势检测更快
CoreImage 集成
CIBlendWithMask 滤镜
使用 Vision 蒙版将主体合成到新背景上:
// 1. Get mask from Vision
let observation = request.results?.first as? VNInstanceMaskObservation
let visionMask = try observation.createScaledMask(
for: observation.allInstances,
croppedToInstancesContent: false
)
// 2. Convert to CIImage
let maskImage = CIImage(cvPixelBuffer: visionMask)
// 3. Apply filter
let filter = CIFilter(name: "CIBlendWithMask")!
filter.setValue(sourceImage, forKey: kCIInputImageKey)
filter.setValue(maskImage, forKey: kCIInputMaskImageKey)
filter.setValue(newBackground, forKey: kCIInputBackgroundImageKey)
let output = filter.outputImage // Composited result
参数:
- 输入图像:要应用蒙版的原始图像
- 蒙版图像:Vision 的软分割蒙版
- 背景图像:新背景(或用于透明效果的空图像)
HDR 保留:CoreImage 会保留输入图像的高动态范围(Vision/VisionKit 输出为 SDR)
文本识别 API
VNRecognizeTextRequest
可用性:iOS 13+、macOS 10.15+
识别图像中的文本,可配置准确度/速度的权衡。
基本用法
let request = VNRecognizeTextRequest()
request.recognitionLevel = .accurate // Or .fast
request.recognitionLanguages = ["en-US", "de-DE"] // Order matters
request.usesLanguageCorrection = true
let handler = VNImageRequestHandler(cgImage: image)
try handler.perform([request])
for observation in request.results as? [VNRecognizedTextObservation] ?? [] {
// Get top candidates
let candidates = observation.topCandidates(3)
let bestText = candidates.first?.string ?? ""
}
识别级别
| Level | 性能 | 准确度 | 适用场景 |
|---|---|---|---|
.fast | 实时 | 良好 | 相机画面、大号文本、标志 |
.accurate | 较慢 | 极佳 | 文档、收据、手写文本 |
快速路径:逐字符识别(神经网络 → 字符检测)
准确路径:整行 ML 识别(神经网络 → 行/单词识别)
属性
| Property | Type | Description |
|---|---|---|
recognitionLevel | VNRequestTextRecognitionLevel | .fast 或 .accurate |
recognitionLanguages | [String] | BCP 47 语言代码,顺序即优先级 |
usesLanguageCorrection | Bool | 使用语言模型进行纠错 |
customWords | [String] | 特定领域词汇 |
automaticallyDetectsLanguage | Bool | 自动检测语言(iOS 16+) |
minimumTextHeight | Float | 最小文本高度,占图像高度的比例(0-1) |
revision | Int | API 版本(影响支持的语言) |
语言支持
// Check supported languages for current settings
let languages = try VNRecognizeTextRequest.supportedRecognitionLanguages(
for: .accurate,
revision: VNRecognizeTextRequestRevision3
)
语言纠错:可提高准确度,但需要处理时间。识别代码/序列号时应停用。
自定义词汇:添加特定领域词汇,以提升识别效果(医学术语、产品代码)。
VNRecognizedTextObservation
boundingBox:包含已识别文本的归一化矩形
topCandidates(_:):按置信度顺序返回 [VNRecognizedText]
VNRecognizedText
| 属性 | 类型 | 描述 |
|---|---|---|
string | String | 已识别的文本 |
confidence | VNConfidence | 0.0-1.0 |
boundingBox(for:) | VNRectangleObservation? | 子字符串范围对应的框 |
// Get bounding box for substring
let text = candidate.string
if let range = text.range(of: "invoice") {
let box = try candidate.boundingBox(for: range)
}
条码检测 API
VNDetectBarcodesRequest
可用性:iOS 11+、macOS 10.13+
检测并解码条码和二维码。
基本用法
let request = VNDetectBarcodesRequest()
request.symbologies = [.qr, .ean13, .code128] // Specific codes
let handler = VNImageRequestHandler(cgImage: image)
try handler.perform([request])
for barcode in request.results as? [VNBarcodeObservation] ?? [] {
let payload = barcode.payloadStringValue
let type = barcode.symbology
let bounds = barcode.boundingBox
}
编码类型
一维条码:
.codabar(iOS 15+).code39、.code39Checksum、.code39FullASCII、.code39FullASCIIChecksum.code93、.code93i.code128.ean8、.ean13.gs1DataBar、.gs1DataBarExpanded、.gs1DataBarLimited(iOS 15+).i2of5、.i2of5Checksum.itf14.upce
二维编码:
.aztec.dataMatrix.microPDF417(iOS 15+).microQR(iOS 15+).pdf417.qr
性能:指定的编码类型越少,检测速度越快
版本
| 版本 | iOS | 功能 |
|---|---|---|
| 1 | 11+ | 基本检测,一次检测一个编码 |
| 2 | 15+ | Codabar、GS1、MicroPDF、MicroQR,改进 ROI |
| 3 | 16+ | 基于 ML,支持多个编码,改进边界框 |
VNBarcodeObservation
| 属性 | 类型 | 描述 |
|---|---|---|
payloadStringValue | String? | 解码后的内容 |
symbology | VNBarcodeSymbology | 条码类型 |
boundingBox | CGRect | 归一化边界 |
topLeft/topRight/bottomLeft/bottomRight | CGPoint | 角点 |
VisionKit 扫描器 API
DataScannerViewController
可用性:iOS 16+
基于摄像头的实时扫描器,内置文本和条码扫描界面。
检查可用性
// Hardware support
DataScannerViewController.isSupported
// Runtime availability (camera access, parental controls)
DataScannerViewController.isAvailable
配置
import VisionKit
let dataTypes: Set<DataScannerViewController.RecognizedDataType> = [
.barcode(symbologies: [.qr, .ean13]),
.text(textContentType: .URL), // Or nil for all text
// .text(languages: ["ja"]) // Filter by language
]
let scanner = DataScannerViewController(
recognizedDataTypes: dataTypes,
qualityLevel: .balanced, // .fast, .balanced, .accurate
recognizesMultipleItems: true,
isHighFrameRateTrackingEnabled: true,
isPinchToZoomEnabled: true,
isGuidanceEnabled: true,
isHighlightingEnabled: true
)
scanner.delegate = self
present(scanner, animated: true) {
try? scanner.startScanning()
}
RecognizedDataType
| 类型 | 描述 |
|---|---|
.barcode(symbologies:) | 指定条码类型 |
.text() | 所有文本 |
.text(languages:) | 按语言筛选文本 |
.text(textContentType:) | 按类型筛选文本(URL、电话、电子邮件) |
委托协议
protocol DataScannerViewControllerDelegate {
func dataScanner(_ dataScanner: DataScannerViewController,
didTapOn item: RecognizedItem)
func dataScanner(_ dataScanner: DataScannerViewController,
didAdd addedItems: [RecognizedItem],
allItems: [RecognizedItem])
func dataScanner(_ dataScanner: DataScannerViewController,
didUpdate updatedItems: [RecognizedItem],
allItems: [RecognizedItem])
func dataScanner(_ dataScanner: DataScannerViewController,
didRemove removedItems: [RecognizedItem],
allItems: [RecognizedItem])
func dataScanner(_ dataScanner: DataScannerViewController,
becameUnavailableWithError error: DataScannerViewController.ScanningUnavailable)
}
RecognizedItem
enum RecognizedItem {
case text(RecognizedItem.Text)
case barcode(RecognizedItem.Barcode)
var id: UUID { get }
var bounds: RecognizedItem.Bounds { get }
}
// Text item
struct Text {
let transcript: String
}
// Barcode item
struct Barcode {
let payloadStringValue: String?
let observation: VNBarcodeObservation
}
异步流
// Alternative to delegate
for await items in scanner.recognizedItems {
// Current recognized items
}
自定义高亮
// Add custom views over recognized items
scanner.overlayContainerView.addSubview(customHighlight)
// Capture still photo
let photo = try await scanner.capturePhoto()
VNDocumentCameraViewController
可用性:iOS 13+
文档扫描,支持自动边缘检测、透视校正和光线调整。
基本用法
import VisionKit
let camera = VNDocumentCameraViewController()
camera.delegate = self
present(camera, animated: true)
委托协议
protocol VNDocumentCameraViewControllerDelegate {
func documentCameraViewController(_ controller: VNDocumentCameraViewController,
didFinishWith scan: VNDocumentCameraScan)
func documentCameraViewControllerDidCancel(_ controller: VNDocumentCameraViewController)
func documentCameraViewController(_ controller: VNDocumentCameraViewController,
didFailWithError error: Error)
}
VNDocumentCameraScan
| 属性 | 类型 | 描述 |
|---|---|---|
pageCount | Int | 扫描页数 |
imageOfPage(at:) | UIImage | 获取指定索引处的页面图像 |
title | String | 用户可编辑的标题 |
func documentCameraViewController(_ controller: VNDocumentCameraViewController,
didFinishWith scan: VNDocumentCameraScan) {
controller.dismiss(animated: true)
for i in 0..<scan.pageCount {
let pageImage = scan.imageOfPage(at: i)
// Process with VNRecognizeTextRequest
}
}
文档分析 API
VNDetectDocumentSegmentationRequest
可用性:iOS 15+、macOS 12+
检测文档边界,适用于自定义相机界面或后期处理。
let request = VNDetectDocumentSegmentationRequest()
let handler = VNImageRequestHandler(ciImage: image)
try handler.perform([request])
guard let observation = request.results?.first as? VNRectangleObservation else {
return // No document found
}
// Get corner points (normalized)
let corners = [
observation.topLeft,
observation.topRight,
observation.bottomLeft,
observation.bottomRight
]
与 VNDetectRectanglesRequest 的区别:
- 文档:基于 ML,专门使用文档进行训练
- 矩形:基于边缘,可查找任意四边形
RecognizeDocumentsRequest(iOS 26+)
可用性:iOS 26+、macOS 26+
通过语义解析实现结构化文档理解。
基本用法
let request = RecognizeDocumentsRequest()
let observations = try await request.perform(on: imageData)
guard let document = observations.first?.document else {
return
}
DocumentObservation 层级结构
DocumentObservation
└── document: DocumentObservation.Document
├── text: TextObservation
├── tables: [Container.Table]
├── lists: [Container.List]
└── barcodes: [Container.Barcode]
表格提取
for table in document.tables {
for row in table.rows {
for cell in row {
let text = cell.content.text.transcript
let detectedData = cell.content.text.detectedData
}
}
}
检测到的数据类型
for data in document.text.detectedData {
switch data.match.details {
case .emailAddress(let email):
let address = email.emailAddress
case .phoneNumber(let phone):
let number = phone.phoneNumber
case .link(let url):
let link = url
case .address(let address):
let components = address
case .date(let date):
let dateValue = date
default:
break
}
}
TextObservation 层级结构
TextObservation
├── transcript: String
├── lines: [TextObservation.Line]
├── paragraphs: [TextObservation.Paragraph]
├── words: [TextObservation.Word]
└── detectedData: [DetectedDataObservation]
Visual Intelligence 集成
Visual Intelligence 是一项系统级功能(iOS 26+),用户可以将摄像头对准现实世界中的物体,并在各个应用中查找匹配内容。它不同于上文介绍的 Vision 框架(基于 VNRequest 的图像分析)。Vision 在你的应用中分析图像;Visual Intelligence 则允许系统在用户通过摄像头或屏幕截图进行搜索时调用你的应用。
工作原理
- 用户启动 Visual Intelligence 相机或截屏
- 系统分析用户正在看的内容
- 系统通过
IntentValueQuery查询参与的应用 - 您的应用会收到包含标签和/或像素数据的
SemanticContentDescriptor - 您的应用搜索内容,并返回匹配的
AppEntity结果 - 结果会显示在 Visual Intelligence 界面中,并展示您应用的品牌标识
所需框架
import VisualIntelligence
import AppIntents
SemanticContentDescriptor
系统提供的核心对象,用于描述用户正在看的内容。
| 属性 | 类型 | 描述 |
|---|---|---|
labels | [String] | 检测到项目的分类标签 |
pixelBuffer | CVReadOnlyPixelBuffer? | 检测到项目的视觉数据 |
使用标签快速与您的内容目录进行关键词匹配。标签不足时,使用像素缓冲区进行图像相似度搜索。
IntentValueQuery
Visual Intelligence 与您的应用通信的入口。实现 values(for:) 以接收搜索请求并返回匹配的实体。
struct LandmarkIntentValueQuery: IntentValueQuery {
@Dependency var modelData: ModelData
func values(for input: SemanticContentDescriptor) async throws -> [LandmarkEntity] {
if !input.labels.isEmpty {
return try await modelData.search(matching: input.labels)
}
guard let pixelBuffer = input.pixelBuffer else { return [] }
return try await modelData.search(matching: pixelBuffer)
}
}
返回多种结果类型
当您的应用可以在单次搜索中返回不同实体类型时,请使用 @UnionValue。
@UnionValue
enum VisualSearchResult {
case landmark(LandmarkEntity)
case collection(CollectionEntity)
}
显示表示
Visual Intelligence 使用实体的 DisplayRepresentation 来展示结果。为每个结果提供标题、副标题和图像。
struct LandmarkEntity: AppEntity {
var id: String
var name: String
var location: String
static var typeDisplayRepresentation: TypeDisplayRepresentation {
TypeDisplayRepresentation(
name: LocalizedStringResource("Landmark", table: "AppIntents"),
numericFormat: "\(placeholder: .int) landmarks"
)
}
var displayRepresentation: DisplayRepresentation {
DisplayRepresentation(
title: "\(name)",
subtitle: "\(location)",
image: .init(named: thumbnailImageName)
)
}
}
从结果进行深度链接
用户点按结果时,您的应用应打开相应内容。请在实体上提供 appLinkURL。
var appLinkURL: URL? {
URL(string: "yourapp://landmark/\(id)")
}
“更多结果”提示词
对于大型结果集,请提供一个 VisualIntelligenceSearchIntent,以打开您应用的完整搜索界面。
struct ViewMoreLandmarksIntent: AppIntent, VisualIntelligenceSearchIntent {
static var title: LocalizedStringResource = "View More Landmarks"
@Parameter(title: "Semantic Content")
var semanticContent: SemanticContentDescriptor
func perform() async throws -> some IntentResult {
// Open your app's search view with the semantic content
return .result()
}
}
最佳实践
- 快速返回结果 — Visual Intelligence 需要低延迟响应。将结果限制为 10-20 个最相关项
- 优先使用标签 — 标签匹配比像素缓冲区分析更快。标签为空或不足时,再使用像素缓冲区
- 全面本地化 — 显示表示会出现在系统界面中。所有面向用户的文本都应使用
LocalizedStringResource - 包含图像 — 带缩略图的结果在 Visual Intelligence 覆盖层中更容易识别
测试
- 在实体设备上构建并运行
- 启动 Visual Intelligence 相机,或对相关内容截屏
- 执行视觉搜索,并确认您的应用结果会显示
- 点按结果,确认深度链接会打开正确的内容
API 快速参考
主体分割
| API | 平台 | 用途 |
|---|---|---|
VNGenerateForegroundInstanceMaskRequest | iOS 17+ | 不依赖类别的主体实例 |
VNGeneratePersonInstanceMaskRequest | iOS 17+ | 分别检测最多 4 人 |
VNGeneratePersonSegmentationRequest | iOS 15+ | 检测所有人(单个蒙版) |
ImageAnalysisInteraction (VisionKit) | iOS 16+ | 用于主体提取的 UI |
姿势检测
| API | 平台 | 标志点 | 坐标 |
|---|---|---|---|
VNDetectHumanHandPoseRequest | iOS 14+ | 每只手 21 个 | 2D 归一化坐标 |
VNDetectHumanBodyPoseRequest | iOS 14+ | 身体 18 个关节 | 2D 归一化坐标 |
VNDetectHumanBodyPose3DRequest | iOS 17+ | 身体 17 个关节 | 3D 米制坐标 |
人脸与人体检测
| API | 平台 | 用途 |
|---|---|---|
VNDetectFaceRectanglesRequest | iOS 11+ | 人脸边界框 |
VNDetectFaceLandmarksRequest | iOS 11+ | 带详细标志点的人脸 |
VNDetectHumanRectanglesRequest | iOS 13+ | 人体躯干边界框 |
文本与条形码
| API | 平台 | 用途 |
|---|---|---|
VNRecognizeTextRequest | iOS 13+ | 文本识别(OCR) |
VNDetectBarcodesRequest | iOS 11+ | 条形码/二维码检测 |
DataScannerViewController | iOS 16+ | 实时相机扫描器(文本 + 条形码) |
VNDocumentCameraViewController | iOS 13+ | 文档扫描并进行透视校正 |
VNDetectDocumentSegmentationRequest | iOS 15+ | 以编程方式检测文档边缘 |
RecognizeDocumentsRequest | iOS 26+ | 结构化文档提取 |
视觉智能
| API | 平台 | 用途 |
|---|---|---|
SemanticContentDescriptor | iOS 26+ | 描述用户正在查看的内容(标签 + 像素缓冲区) |
IntentValueQuery | iOS 26+ | 接收视觉搜索请求的入口 |
VisualIntelligenceSearchIntent | iOS 26+ | 指向应用中“更多结果”的深层链接 |
观察类型
| 观察结果 | 返回方 |
|---|---|
VNInstanceMaskObservation | 前景/人物实例蒙版 |
VNPixelBufferObservation | 人物分割(单个蒙版) |
VNHumanHandPoseObservation | 手部姿势 |
VNHumanBodyPoseObservation | 身体姿势(2D) |
VNHumanBodyPose3DObservation | 身体姿势(3D) |
VNFaceObservation | 人脸检测/特征点 |
VNHumanObservation | 人物矩形框 |
VNRecognizedTextObservation | 文本识别 |
VNBarcodeObservation | 条形码检测 |
VNRectangleObservation | 文档分割 |
DocumentObservation | 结构化文档(iOS 26+) |
资源
WWDC:2019-234、2021-10041、2022-10024、2022-10025、2025-272、2023-10176、2023-111241、2023-10048、2020-10653、2020-10043、2020-10099
文档:/vision、/visionkit、/visualintelligence、/visualintelligence/semanticcontentdescriptor、/vision/vnrecognizetextrequest、/vision/vndetectbarcodesrequest
技能:axiom-vision、axiom-vision-diag