VNRequest — iOS中Vision请求的架构说明

作者: IT Sectr 发布日期: 2026-07-20 阅读时间: 8 分钟

VNRequest — 是 Vision 框架的抽象基类,代表图像或视频流的分析单元。每种分析类型 — 人脸检测、文本识别、扫描条码搜索、分类 — 都作为VNRequest的具体子类实现。根据Apple Developer Documentation (2024),开发者创建请求实例,配置参数,通过VNImageRequestHandler传递图像,并以VNObservation数组形式接收结果。

核心要点

Vision中VNRequest是什么?

VNRequest — 是 Vision 架构的基础元素,实现了 Request-Response 模式用于图像和视频分析。每个 VNRequest 子类负责一个具体的计算机视觉任务:搜索人脸、识别文本、分类内容。

VNRequest 架构将 “分析什么”(请求)与 “如何处理”(handler)分离。开发者配置请求(分析类型、额外参数),并将其与图像一起传递给 handler。 Handler 执行请求并返回结果,不需要开发者了解内部 ML 算法。

所有 VNRequest 子类遵循统一结构:使用可选的 completion handler 进行初始化、配置属性(分析区域、精度级别),然后传递给 handler。这使 API 具有可预测性和易扩展性 — 添加新的分析类型意味着创建新的 VNRequest 子类。

swift
import Vision

// 1. 创建请求
let request = VNDetectFaceRectanglesRequest { req, _ in
    // 3. 处理结果
    guard let faces = req.results as? [VNFaceObservation]
    else { return }
    print("Found \\(faces.count) faces")
}

// 2. 通过handler执行
let handler = VNImageRequestHandler(cgImage: cgImage, options: [:])
try handler.perform([request])

VNRequest 关键属性:regionOfInterest(图像上的感兴趣区域,用于加快分析)、preferBackgroundProcessing(后台模式)、revision(算法版本)和cancellationSupport。正确配置这些属性可使您针对特定任务优化性能。

根据 Apple WWDC 2024,在 Vision 存在的 7 年里,可用的 VNRequest 子类数量从 8个(iOS 11)增长到超过 25个(iOS 18),覆盖了移动设备上所有主要的计算机视觉任务。

分析用的主要VNRequest类型

Vision 包含超过 25 个 VNRequest 子类,分为以下类别:检测、识别、跟踪和分类。每个子类继承自 VNRequest 并添加任务特定属性。

检测和识别

VNDetectFaceRectanglesRequest — 在图像中搜索人脸。返回带有 bounding box 坐标和 confidence 的 VNFaceObservation。VNDetectHumanRectanglesRequest — 针对人类的类似功能。VNDetectHumanBodyPoseRequest — 确定人体姿态(骨架点)。

文本分析

VNRecognizeTextRequest — 支持 13 种语言和两种精度级别的文本识别。VNReadCodeRequest — 用于专业代码。VNDetectTextRectanglesRequest — 搜索文本区域而不进行识别(更快,但只能得到矩形区域)。

分类和分析

VNClassifyImageRequest — 根据 1000 个 ImageNet 类别对图像进行分类。VNGenerateImageFeaturePrintRequest — 提取特征向量用于比较图像。VNDetectContoursRequest — 检测物体轮廓。

VNImageRequestHandler和VNSequenceRequestHandler

VNImageRequestHandler — 用于静态图像的处理器。接受 CGImage、CIImage 或 Data(JPEG/PNG),执行一个或多个 VNRequest。这是将 Vision 用于照片、截屏和上传图像的主要方式。

VNSequenceRequestHandler — 用于图像序列(视频帧)的处理器。接受相同的图像类型,但专为逐帧处理设计,保持帧之间的状态(物体跟踪必须)。

swift
// 单张图像用VNImageRequestHandler
let imageHandler = VNImageRequestHandler(
    cgImage: cgImage,
    orientation: orientation,
    options: [:])

// 视频用VNSequenceRequestHandler
let sequenceHandler = VNSequenceRequestHandler()
try sequenceHandler.perform([trackingRequest],
    on: cgImage)

重要区别:VNSequenceRequestHandler不支持多个请求的并行执行 — 每次 perform() 调用只处理一个帧的一组请求。对于多线程视频处理,为不同线程创建单独的 handler 实例。

VNImageRequestHandler 可以在后台队列中执行。Apple 建议对交互式场景(用户等待结果)使用 DispatchQueue.global(qos: .userInitiated),对批量处理(如分析整个照片库)使用 .background。

VNObservation:结果结构

VNObservation — 所有 Vision 请求结果的基类。每个 VNObservation 子类包含特定分析类型的数据:bounding box 坐标、识别的文本、置信度(confidence)、唯一标识符(uuid)和时间戳(timeRange)。

主要 VNObservation 子类:VNFaceObservation(带有 bounding box 和 landmarks 的人脸检测结果)、VNRecognizedTextObservation(带有 candidates 的识别文本)、VNBarcodeObservation(带有 payload 和 symbology 的解码条码)、VNClassificationObservation(带有 confidence 的分类类别)。

swift
func handleTextResults(request: VNRequest) {
    guard let observations = request.results
        as? [VNRecognizedTextObservation]
    else { return }

    for observation in observations {
        let bbox = observation.boundingBox
        let text = observation.topCandidates(1).first ?? ""
        print("\\(text) at \\(bbox)")
    }
}

confidence 属性(从 0.0 到 1.0)存在于所有 VNObservation 中,表示模型对结果的置信程度。Apple 建议对大多数任务抛弃 confidence < 0.5 的观察结果。对于关键应用(医疗、安全),应将阈值提高到 0.8–0.9。

VNObservation 还包含 timeRange(用于视频请求)和 uuid(用于帧之间匹配的唯一 ID)。这使得可以通过视频帧序列跟踪同一个物体(如人脸)。

同时执行多个请求

VNRequest 的关键优势之一 — 能够在一次 handler.perform() 调用中对一张图像执行多个不同请求。Vision 会内部优化执行顺序并重用共同的计算(如图像预处理)。

这允许在一次过程中获取关于图像的完整数据集:同时检测人脸、识别文本、查找条码和分类内容。这种方法比逐个调用每个请求更加高效。

swift
import Vision

// 单个数组中的多个请求
let faceRequest = VNDetectFaceRectanglesRequest()
let textRequest = VNRecognizeTextRequest()
let barcodeRequest = VNDetectBarcodesRequest()
let classifyRequest = VNClassifyImageRequest()

let handler = VNImageRequestHandler(cgImage: cgImage, options: [:])
try handler.perform([
    faceRequest,
    textRequest,
    barcodeRequest,
    classifyRequest
])

// 从每个请求访问结果
print("Faces: \\(faceRequest.results?.count ?? 0)")
print("Text blocks: \\(textRequest.results?.count ?? 0)")

局限性:并非所有请求都能与其他请求组合。例如,VNGenerateImageFeaturePrintRequest 必须单独执行。Apple 建议按类型分组请求(检测、识别、分类),并在目标设备上测试组合。

性能:在一次 perform() 中组合 3–4 个请求比逐次执行快 30–40%,因为 Vision 重用共同的 ML 计算和图像预处理(缩放、颜色校正)。

使用VNCoreMLRequest的自定义请求

VNCoreMLRequest — 是 Core ML 和 Vision 之间的桥梁,允许将任何 Core ML 模型作为 Vision 请求运行。模型包装在 VNCoreMLModel 中,传递给 VNCoreMLRequest,Vision 自动处理图像预处理(缩放、裁剪到模型输入尺寸)。

VNCoreMLRequest 继承自 VNRequest,因此支持所有标准功能:regionOfInterest、completion handler、多个请求。这使得可以将自定义 ML 模型与 Vision 内置检测器组合在一个 pipeline 中。

swift
import Vision
import CoreML

// 包装Core ML模型
guard let mlModel = try VNCoreMLModel(
    for: MyCustomClassifier().model)
else { return }

// 创建VNCoreMLRequest
let coreMLRequest = VNCoreMLRequest(model: mlModel) { request, _ in
    guard let results = request.results
        as? [VNClassificationObservation]
    else { return }

    for result in results.prefix(5) {
        print("\\(result.identifier): \\(result.confidence)"
    }
}
coreMLRequest.imageCropAndScaleOption = .centerCrop
coreMLRequest.regionOfInterest = faceBoundingBox

imageCropAndScaleOption 确定 Vision 如何将图像缩放到模型输入:.centerCrop(从中央裁剪)、.scaleFill(拉伸)或 .scaleFit(保持比例缩放)。选择取决于模型类型和图像中物体的位置。

实际案例:通过 VNDetectFaceRectanglesRequest 检测人脸,然后通过 VNCoreMLRequest 使用自定义模型(如确定性别或年龄)对每个人脸进行分类。将两个请求组合在一次 perform() 中,您可以在一次过程中获得完整的人脸分析 pipeline。

常见问题

可以取消正在执行的 VNRequest 吗?

可以,每个 VNRequest 都有 cancel() 属性取消请求执行。但是,取消只在处理开始前有效 — 如果 ML 模型已经启动,取消不会中断计算。要可靠地取消,请在 completion handler 中同时使用 DispatchWorkItem.cancel() 和 VNRequest.cancel()。

VNDetectFaceRectanglesRequest 和 VNDetectFaceLandmarksRequest 有什么区别?

VNDetectFaceRectanglesRequest 只能找到人脸的矩形区域。VNDetectFaceLandmarksRequest 还能确定人脸的 68 个关键点(眼睛、眉毛、鼻子、嘴巴、轮廓)。VNDetectFaceLandmarksRequest 更慢,但为动画、面具和 AR 效果提供更多数据。简单计数人脸时,VNDetectFaceRectanglesRequest 就够了。

搜索条码应该使用哪个请求 — VNDetectBarcodesRequest?

是的,VNDetectBarcodesRequest — 针对所有类型条码和 QR 码的正确请求。它支持 EAN、UPC、Code 39、Code 128、PDF417、Aztec、QR 和其他格式。结果以带有 payload 和 symbology 的 VNBarcodeObservation 形式返回。对于视频流,请使用 AVCaptureMetadataOutput — 它对于实时扫描更快。

可以在 CIImage 而不是 CGImage 上执行 VNRequest 吗?

可以,VNImageRequestHandler 通过 init(ciImage:options:) 初始化器接受 CIImage。还支持 Data(JPEG/PNG)和 NSURL(文件路径)。当图像已通过 Core Image pipeline 加载时,CIImage 很方便 — 这避免了内存中不必要的数据拷贝。

一次 perform() 可以执行多少个 VNRequest?

数量没有限制,但实际上 3–5 个请求 是最佳数量。超过 5 个请求可能导致内存消耗增加,因为每个请求都会加载自己的 ML 模型。如果需要执行 10+ 种不同分析,请将它们分为 2–3 组并逐次执行。

总结

  • VNRequest — Vision 的基类,用于所有类型的图像和视频分析,采用统一的 Request-Response 架构。
  • Vision 包含 25+ 个 VNRequest 子类,用于人脸检测、OCR、条码、分类、轮廓、跟踪和 ML 模型。
  • VNImageRequestHandler 在静态图像上执行请求;VNSequenceRequestHandler 在序列帧上用于跟踪。
  • 结果以 VNObservation 形式返回,包含 bounding box、confidence、uuid 和类型特定数据。
  • 一次 perform() 中的 多个请求 由于重用 ML 计算,比逐次调用快 30–40%。
  • VNCoreMLRequest 将自定义 Core ML 模型集成到 Vision pipeline 中,带有自动图像预处理。
  • 所有请求都在 设备本地 执行,无需将数据发送到服务器,确保隐私和离线工作。

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读