mcpField
A
axiom-vision-ref

axiom-vision-ref

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

关于 axiom-vision-ref

面向 iOS 开发者的 Vision 框架 API 参考,涵盖图像分割、姿态与人脸检测、OCR、条码识别和文档扫描。内容包括请求处理器选择、API 用法及视频序列中的状态处理。

主要功能

  1. 01前景与人物分割 API
  2. 02手部和身体姿态检测
  3. 03人脸分析与文本识别
  4. 04条码检测和文档扫描
  5. 05图像与序列请求处理器说明

适用场景

  1. 01从图像提取前景主体
  2. 02为手势或健身应用追踪姿态
  3. 03在图像中识别文字或条码
  4. 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 为静态图像和视频提供计算机视觉算法:

核心工作流:

  1. 创建请求(例如,VNDetectHumanHandPoseRequest())
  2. 使用图像创建处理器(VNImageRequestHandler(cgImage: image))
  3. 执行请求(try handler.perform([request]))
  4. 从 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:要包含的实例的 IndexSet
  • croppedToInstancesContent:
    • 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 个关键点
.thumb4 个拇指关节点
.indexFinger4 个食指关节点
.middleFinger4 个中指关节点
.ringFinger4 个无名指关节点
.littleFinger4 个小指关节点
// 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 KeyPoints
.all全部 18 个关键点
.face5 个面部关键点
.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 识别(神经网络 → 行/单词识别)

属性
PropertyTypeDescription
recognitionLevelVNRequestTextRecognitionLevel.fast 或 .accurate
recognitionLanguages[String]BCP 47 语言代码,顺序即优先级
usesLanguageCorrectionBool使用语言模型进行纠错
customWords[String]特定领域词汇
automaticallyDetectsLanguageBool自动检测语言(iOS 16+)
minimumTextHeightFloat最小文本高度,占图像高度的比例(0-1)
revisionIntAPI 版本(影响支持的语言)
语言支持
// Check supported languages for current settings
let languages = try VNRecognizeTextRequest.supportedRecognitionLanguages(
    for: .accurate,
    revision: VNRecognizeTextRequestRevision3
)

语言纠错:可提高准确度,但需要处理时间。识别代码/序列号时应停用。

自定义词汇:添加特定领域词汇,以提升识别效果(医学术语、产品代码)。

VNRecognizedTextObservation

boundingBox:包含已识别文本的归一化矩形

topCandidates(_:):按置信度顺序返回 [VNRecognizedText]

VNRecognizedText
属性类型描述
stringString已识别的文本
confidenceVNConfidence0.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功能
111+基本检测,一次检测一个编码
215+Codabar、GS1、MicroPDF、MicroQR,改进 ROI
316+基于 ML,支持多个编码,改进边界框
VNBarcodeObservation
属性类型描述
payloadStringValueString?解码后的内容
symbologyVNBarcodeSymbology条码类型
boundingBoxCGRect归一化边界
topLeft/topRight/bottomLeft/bottomRightCGPoint角点

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
属性类型描述
pageCountInt扫描页数
imageOfPage(at:)UIImage获取指定索引处的页面图像
titleString用户可编辑的标题
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 则允许系统在用户通过摄像头或屏幕截图进行搜索时调用你的应用。

工作原理
  1. 用户启动 Visual Intelligence 相机或截屏
  2. 系统分析用户正在看的内容
  3. 系统通过 IntentValueQuery 查询参与的应用
  4. 您的应用会收到包含标签和/或像素数据的 SemanticContentDescriptor
  5. 您的应用搜索内容,并返回匹配的 AppEntity 结果
  6. 结果会显示在 Visual Intelligence 界面中,并展示您应用的品牌标识
所需框架
import VisualIntelligence
import AppIntents
SemanticContentDescriptor

系统提供的核心对象,用于描述用户正在看的内容。

属性类型描述
labels[String]检测到项目的分类标签
pixelBufferCVReadOnlyPixelBuffer?检测到项目的视觉数据

使用标签快速与您的内容目录进行关键词匹配。标签不足时,使用像素缓冲区进行图像相似度搜索。

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 覆盖层中更容易识别
测试
  1. 在实体设备上构建并运行
  2. 启动 Visual Intelligence 相机,或对相关内容截屏
  3. 执行视觉搜索,并确认您的应用结果会显示
  4. 点按结果,确认深度链接会打开正确的内容

API 快速参考

主体分割
API平台用途
VNGenerateForegroundInstanceMaskRequestiOS 17+不依赖类别的主体实例
VNGeneratePersonInstanceMaskRequestiOS 17+分别检测最多 4 人
VNGeneratePersonSegmentationRequestiOS 15+检测所有人(单个蒙版)
ImageAnalysisInteraction (VisionKit)iOS 16+用于主体提取的 UI
姿势检测
API平台标志点坐标
VNDetectHumanHandPoseRequestiOS 14+每只手 21 个2D 归一化坐标
VNDetectHumanBodyPoseRequestiOS 14+身体 18 个关节2D 归一化坐标
VNDetectHumanBodyPose3DRequestiOS 17+身体 17 个关节3D 米制坐标
人脸与人体检测
API平台用途
VNDetectFaceRectanglesRequestiOS 11+人脸边界框
VNDetectFaceLandmarksRequestiOS 11+带详细标志点的人脸
VNDetectHumanRectanglesRequestiOS 13+人体躯干边界框
文本与条形码
API平台用途
VNRecognizeTextRequestiOS 13+文本识别(OCR)
VNDetectBarcodesRequestiOS 11+条形码/二维码检测
DataScannerViewControlleriOS 16+实时相机扫描器(文本 + 条形码)
VNDocumentCameraViewControlleriOS 13+文档扫描并进行透视校正
VNDetectDocumentSegmentationRequestiOS 15+以编程方式检测文档边缘
RecognizeDocumentsRequestiOS 26+结构化文档提取
视觉智能
API平台用途
SemanticContentDescriptoriOS 26+描述用户正在查看的内容(标签 + 像素缓冲区)
IntentValueQueryiOS 26+接收视觉搜索请求的入口
VisualIntelligenceSearchIntentiOS 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

评论

支持 Markdown