VNRequest — 是 Vision 框架的抽象基类,代表图像或视频流的分析单元。每种分析类型 — 人脸检测、文本识别、扫描条码搜索、分类 — 都作为VNRequest的具体子类实现。根据Apple Developer Documentation (2024),开发者创建请求实例,配置参数,通过VNImageRequestHandler传递图像,并以VNObservation数组形式接收结果。
核心要点
VNRequest — 是 Vision 架构的基础元素,实现了 Request-Response 模式用于图像和视频分析。每个 VNRequest 子类负责一个具体的计算机视觉任务:搜索人脸、识别文本、分类内容。
VNRequest 架构将 “分析什么”(请求)与 “如何处理”(handler)分离。开发者配置请求(分析类型、额外参数),并将其与图像一起传递给 handler。 Handler 执行请求并返回结果,不需要开发者了解内部 ML 算法。
所有 VNRequest 子类遵循统一结构:使用可选的 completion handler 进行初始化、配置属性(分析区域、精度级别),然后传递给 handler。这使 API 具有可预测性和易扩展性 — 添加新的分析类型意味着创建新的 VNRequest 子类。
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),覆盖了移动设备上所有主要的计算机视觉任务。
Vision 包含超过 25 个 VNRequest 子类,分为以下类别:检测、识别、跟踪和分类。每个子类继承自 VNRequest 并添加任务特定属性。
VNDetectFaceRectanglesRequest — 在图像中搜索人脸。返回带有 bounding box 坐标和 confidence 的 VNFaceObservation。VNDetectHumanRectanglesRequest — 针对人类的类似功能。VNDetectHumanBodyPoseRequest — 确定人体姿态(骨架点)。
VNRecognizeTextRequest — 支持 13 种语言和两种精度级别的文本识别。VNReadCodeRequest — 用于专业代码。VNDetectTextRectanglesRequest — 搜索文本区域而不进行识别(更快,但只能得到矩形区域)。
VNClassifyImageRequest — 根据 1000 个 ImageNet 类别对图像进行分类。VNGenerateImageFeaturePrintRequest — 提取特征向量用于比较图像。VNDetectContoursRequest — 检测物体轮廓。
VNImageRequestHandler — 用于静态图像的处理器。接受 CGImage、CIImage 或 Data(JPEG/PNG),执行一个或多个 VNRequest。这是将 Vision 用于照片、截屏和上传图像的主要方式。
VNSequenceRequestHandler — 用于图像序列(视频帧)的处理器。接受相同的图像类型,但专为逐帧处理设计,保持帧之间的状态(物体跟踪必须)。
// 单张图像用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 — 所有 Vision 请求结果的基类。每个 VNObservation 子类包含特定分析类型的数据:bounding box 坐标、识别的文本、置信度(confidence)、唯一标识符(uuid)和时间戳(timeRange)。
主要 VNObservation 子类:VNFaceObservation(带有 bounding box 和 landmarks 的人脸检测结果)、VNRecognizedTextObservation(带有 candidates 的识别文本)、VNBarcodeObservation(带有 payload 和 symbology 的解码条码)、VNClassificationObservation(带有 confidence 的分类类别)。
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 会内部优化执行顺序并重用共同的计算(如图像预处理)。
这允许在一次过程中获取关于图像的完整数据集:同时检测人脸、识别文本、查找条码和分类内容。这种方法比逐个调用每个请求更加高效。
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 — 是 Core ML 和 Vision 之间的桥梁,允许将任何 Core ML 模型作为 Vision 请求运行。模型包装在 VNCoreMLModel 中,传递给 VNCoreMLRequest,Vision 自动处理图像预处理(缩放、裁剪到模型输入尺寸)。
VNCoreMLRequest 继承自 VNRequest,因此支持所有标准功能:regionOfInterest、completion handler、多个请求。这使得可以将自定义 ML 模型与 Vision 内置检测器组合在一个 pipeline 中。
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 都有 cancel() 属性取消请求执行。但是,取消只在处理开始前有效 — 如果 ML 模型已经启动,取消不会中断计算。要可靠地取消,请在 completion handler 中同时使用 DispatchWorkItem.cancel() 和 VNRequest.cancel()。
VNDetectFaceRectanglesRequest 只能找到人脸的矩形区域。VNDetectFaceLandmarksRequest 还能确定人脸的 68 个关键点(眼睛、眉毛、鼻子、嘴巴、轮廓)。VNDetectFaceLandmarksRequest 更慢,但为动画、面具和 AR 效果提供更多数据。简单计数人脸时,VNDetectFaceRectanglesRequest 就够了。
是的,VNDetectBarcodesRequest — 针对所有类型条码和 QR 码的正确请求。它支持 EAN、UPC、Code 39、Code 128、PDF417、Aztec、QR 和其他格式。结果以带有 payload 和 symbology 的 VNBarcodeObservation 形式返回。对于视频流,请使用 AVCaptureMetadataOutput — 它对于实时扫描更快。
可以,VNImageRequestHandler 通过 init(ciImage:options:) 初始化器接受 CIImage。还支持 Data(JPEG/PNG)和 NSURL(文件路径)。当图像已通过 Core Image pipeline 加载时,CIImage 很方便 — 这避免了内存中不必要的数据拷贝。
数量没有限制,但实际上 3–5 个请求 是最佳数量。超过 5 个请求可能导致内存消耗增加,因为每个请求都会加载自己的 ML 模型。如果需要执行 10+ 种不同分析,请将它们分为 2–3 组并逐次执行。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。