大多数浏览器和
Developer App 均支持流媒体播放。
-
利用 VisionKit 捕捉机器可读的代码和文本
了解 VisionKit 中的数据扫描器:此框架整合了 AVCapture 和 Vision,通过简单的 Swift API 实现对机器可读代码和文本的实时捕捉。我们将介绍如何指定条码符号系统和语言选择,从而控制 App 可以捕捉的内容类型。我们还将探索如何启用 App 中的指引,自定义物体高亮显示或兴趣区域,以及在您的 App 检测到某个物体后如何进行交互。要进一步了解如何通过静态图片或暂停视频帧与“实时文本”进行交互,请观看 WWDC22 的“在您的 App 中添加‘实时文本'交互”。
资源
相关视频
Tech Talks
WWDC22
-
下载
Ron Santos: 嗨 大家好 我是 Ron Santos 一名输入工程师 今天我和大家一起聊下 如何捕捉机读编码 以及从视频流中解析文本 或者 如我们常说的 数据扫描 什么是数据扫描呢 其实就是使用某种感应器 比如说相机,来读取数据的方法
通常是文本形式的数据 例如 收据的一些有趣资讯 如电话号码 日期和价格
或者是机器可读的编码数据 如常见的二维码 您之前可能使用过数据扫描 如在相机 App 中 或 iOS 15 中推出的 实况文本功能 我相信您在日常生活中 也用过 App 自带的扫描功能 但如果要搭建自己的 数据扫描器呢 应该怎么做呢 iOS SDK 视您的需要 提供了多种场景 选项之一就是 使用 AVFoundation 框架 建立拍摄图形 将输入和输出连接到 同一个 session 进行配置 生成如机器可读 代码的 AVMetadataObjects 如果您还想捕获文本 还有另一个选项 就是将 AVFoundation 与 Vision 框架相结合 在这个图表中 您创建的是视频数据的输出 而非元数据输出 视频数据输出 带来了 sample buffers 可以与文本一起输入到 Vision 框架 也可以和条码识别请求共同使用 进行 Vision的物体观察功能 关于使用 Vision 进行数据扫描的更多内容 可以查看 WWDC21 中“Extract document data using Vision”的内容 好 以上是使用AVFoundation 和 Vision 进行数据扫描的内容 在 iOS 16中 我们有一个新的选项 将这些工作都浓缩到了一起 VisionKit 框架中的 DataScannerViewController 正式推出 结合了 AVFoundation 和 Vision 的功能 专门用于数据扫描目的 DataScannerViewController 用户 可使用如 实时摄影机预览 实用的指引标签 物品高光显示功能 tap-to-focus (轻点对焦) 也是可选功能之一 最后 还可通过 pinch-to-zoom (手势缩放) 功能来放大图像
我们再来聊聊其他的 对开发者来说实用的功能 DataScannerViewController 是 UIViewController 的子类 您可以选择自己喜欢的展示方式 所识别物体的坐标 总是显示在观察坐标系中 您无需费时将图像空间 转换到 Vision 坐标 再到观察坐标 您也可以通过指定 观察坐标系中的感兴趣区域 限制观察的活动区间 文本识别方面 您可以指定内容类型 限制所查找的文本类型 在机器可读代码方面 您可以指定具体查找哪种符号 我明白 使用您的 App 我知道数据扫描只是 其众多功能之一 但是需要很多代码 通过 DataScannerViewController 我们的目标是为您完成常规工作 从而您可以将时间 聚焦在其它功能上 接下来 我给您介绍下 如何将其添加到 App 中 首先是隐私使用说明 App 尝试捕捉视频时 iOS 会询问用户 提供访问相机的明确权限 您要提供一段描述性信息 用于说明需求 那就需要在 App 的 Info.plist 文件中 添加 “privacy - camera usage description” 记得要尽可能详尽 这样用户知道他们提供权限的内容 接下来是代码实现 不管您要在哪里显示 数据扫描器 首先要导入 VisionKit
接下来 由于并不是所有型号的 设备都支持数据扫描 使用 isSupported 类属性 隐藏实现功能的 按钮或菜单 这样使用不到这一功能的用户 就不需要看到这个界面了
如果您想知道的话 可以告诉您 任何搭载 Apple Neural Engine 的 2018 及以上版本的 iPhone 和 iPad 设备 都支持数据扫描 您还要检查下可用性 还记得隐私使用说明吗 如果用户允许了相机权限 以及设备没有其它限制条件 则扫描功能可用 如 Screen Time 的 内容和隐私限制中 限制了 相机 App 的 访问权限 现在 您可以配置实例了 首先 指定您感兴趣的数据类别 例如 您可以扫描二维码和文本
您可以视需要发送 语言列表到文本识别器 作为不同处理方面的提示 如拼写纠错 如果您知道要查找什么语言 列出来 在两种语言脚本外观相似的情况下 这是很有用的 如果不提供指定语言 则默认为用户的语言偏好 您也可以请求具体的文本内容类型 在这一例子中 我想让扫描装置查找 URLs 既然您已经指明了 要识别的数据类型 就可以创建 DataScanner 实例了 在前面的案例中 我解释了条形码符号 识别语言和文本内容类型 容我花几分钟解释下 它们的其它可选选项 条形码符号方面 我们和 Vision 条码检测器 支持的符号一样 在语言方面 作为实况文本功能的一部分 DataScannerViewController 支持 同样的语言 我很高兴地说 在 iOS 16 中 我们新增支持日语和韩语 当然 未来这也可能有 进一步的变动 所以使用 supportedTextRecognitionLanguages 这一类属性获得更多最新列表 最后 当扫描有具体语义的文本时 DataScannerViewController 可以 查找这其中类型 我们的数据扫描器已准备好 展示给用户了 和其它 view controller 的 展示一样 全屏 使用表格 或将其添加到 另一个视图层级中 您可以自行决定 随后 展示完成后 调出 startScanning() 开始查找数据 所以现在 我想要倒退一步 用一点时间 再看下数据扫描器的初始化参数 我在这 用了 recognizedDataTypes 但还有其它可以多样化 您的体验 我们逐一看下 recognizedDataTypes 可以让您 指定需要识别的数据类型 文本 机器可读代码 以及各是什么类型 qualityLevel 可以设置为 平衡 快或准确 设置为快这一质量级别 则会在 识别大尺寸 清晰度高的物体时 为确保速度牺牲分辨率 如标志上的文本 准确这一质量级别可以 带来高精确性 即使是扫描微型二维码或 微小序列号 我推荐最开始使用平衡这一级别 这在大部分场景都适用 recognizesMultipleItems 可供您 在一个框架内识别一个或多个物体 比如如果您想一次识别多个条码 当出现错误时 用户没有点击别处的情况下 默认识别最中心的物体 绘制高光时开启高帧率跟踪 在相机移动或场景改变时 高光可尽可能跟随物体 开启或禁用 pinch-to-zoom (手势缩放) 我们还有一些方法 让您可以自行调整缩放范围 开启指引时 屏幕顶部 会显示对应的标签 帮助引导用户 最后 如果需要的话 您可以启用系统高光 或者也可以禁用 自行绘制高光 现在您知道如何展示 数据扫描器了 我们来聊聊如何摄取识别物体 以及如何绘制自定义高光
首先 为数据扫描器提供一个代理 有了代理后 可以执行 dataScanner didTapOn 方法 用户点击一个物体时 可调用此功能 通过这一方法 您可以看到这种 全新 RecognizeItem 的实例 RecognizedItem 是将文本或条形码 作为关联值的枚举类型 在文本方面 转录属性 保留识别字符串 在条形码方面 如果负载包含字符串 您可以使用 payloadStringValue 来获取 关于 RecognizedItem 还有两点需要知道的 首先 每个识别物体都有一个 独特的标识符 在它整个生命周期中 都可用其进行追踪 这一生命周期始于 物体首次识别之时 离开视野后则周期结束 第二 每个 RecognizedItem 都有一个性能界限 这一界限不是矩形 但包含有四个点 每个角落各一个点 接下来 我们来聊聊 场景改变时 识别物体需调用的 三种相关代理方法 第一种是 didAdd 在场景中识别新物体时调用 如果要自行绘制高光 可以在这里为每个新物体绘制一个 您可以根据关联值的 ID 跟踪高光 在新的视图中加入视图层级时 添加到 DataScanner 的 overlayContainerView 中 这样它们可以出现在相机预览的 上层 但在其它补充浏览器下层
下一个代理方法是 didUpdate 在物体移动或相机移动时调用 也可以在识别文本改变 需要转录时调用 扫描器扫描文本时间越久 转录越精准 因此会发生变化 使用更新物体的 ID 从您刚创建的词典中 获取高光 然后将视图绘制成更新的界限 最后是 didRemove 代理方法 在物体从场景中消失时调用 在这个方法中 您可以忽略所有高光视图 与移动视图相关联 从视图层级中移除物体 总而言之 如果您在物体上 自行绘制高光 这三种代理方法 在控制场景中的高光动画时 是非常重要的 将动作变成动画 将物体变成动画 通过三种代理方法 都会展示当前识别的所有物体数组 文本识别就比较简单了 因为物体都用自然阅读顺序排列 意味着用户在数值 0 时就可以 阅读到物体 在物体到达数值 1 时就可以 阅读到等等 这是如何使用 DataScannerViewController的概述 在结束前 我快速说下其它功能 如捕捉照片 您可以调用 capturePhoto 方法 从而异步返回一个 高质量的 UIImage
如果您没有自行绘制高光 可能不需要这三种代理方法 相反 您可以使用 recognizedItem 属性 这是一种 AsyncStream 在场景改变时会持续更新
感谢大家的观看 记住 iOS SDK 为您提供了 用 AVFoundation 和 Vision 框架 搭建计算机视觉工作流的选择 但可能您要构建一个 可从视频内容文本中 扫描文本 或机器可读代码的 App 如拣配和包装 App 后台仓库 App 或销售时点情报系统 App 如果是这样的话 那就看下 VisionKit 中的 DataScannerViewController 吧 如我今天所说 它有许多初始化参数 和代理方法可供选择 提供多样化的体验 以匹配您 App 的风格和需求
最后 强烈推荐大家看下 “Add Live Text interaction to your app” 这一讲座 您可以学习到关于 VisionKit 静态图像实况文本的功能
下次见 祝大家平安
-
-
4:40 - Creating a data scanner instance and present it
import VisionKit // Specify the types of data to recognize let recognizedDataTypes:Set<DataScannerViewController.RecognizedDataType> = [ .barcode(symbologies: [.qr]), // uncomment to filter on specific languages (e.g., Japanese) // .text(languages: ["ja"]) // uncomment to filter on specific content types (e.g., URLs) // .text(textContentType: .URL) ] // Create the data scanner, present it, and start scanning! let dataScanner = DataScannerViewController(recognizedDataTypes: recognizedDataTypes) present(dataScanner, animated: true) { try? dataScanner.startScanning() }
-
8:11 - Set a delegate
// Specify the types of data to recognize let recognizedDataTypes:Set<DataScannerViewController.RecognizedDataType> = [ .barcode(symbologies: [.qr]), .text(textContentType: .URL) ] // Create the data scanner, present it, and start scanning! let dataScanner = DataScannerViewController(recognizedDataTypes: recognizedDataTypes) dataScanner.delegate = self.present(dataScanner, animated: true) { try? dataScanner.startScanning() }
-
8:19 - Handling tap interactions
func dataScanner(_ dataScanner: DataScannerViewController, didTapOn item: RecognizedItem) { switch item { case .text(let text): print("text: \(text.transcript)") case .barcode(let barcode): print("barcode: \(barcode.payloadStringValue ?? "unknown")") default: print("unexpected item") } }
-
9:11 - Adding custom highlights via the didAdd delegate method
// Dictionary to store our custom highlights keyed by their associated item ID. var itemHighlightViews: [RecognizedItem.ID: HighlightView] = [:] // For each new item, create a new highlight view and add it to the view hierarchy. func dataScanner(_ dataScanner: DataScannerViewController, didAdd addItems: [RecognizedItem], allItems: [RecognizedItem]) { for item in addedItems { let newView = newHighlightView(forItem: item) itemHighlightViews[item.id] = newView dataScanner.overlayContainerView.addSubview(newView) } }
-
9:37 - Animating custom highlights during the didUpdate delegate method
// Animate highlight views to their new bounds func dataScanner(_ dataScanner: DataScannerViewController, didUpdate updatedItems: [RecognizedItem], allItems: [RecognizedItem]) { for item in updatedItems { if let view = itemHighlightViews[item.id] { animate(view: view, toNewBounds: item.bounds) } } }
-
10:03 - Removing custom highlights during the didRemove delegate callback
// Remove highlights when their associated items are removed. func dataScanner(_ dataScanner: DataScannerViewController, didRemove removedItems: [RecognizedItem], allItems: [RecognizedItem]) { for item in removedItems { if let view = itemHighlightViews[item.id] { itemHighlightViews.removeValue(forKey: item.id) view.removeFromSuperview() } } }
-
10:54 - Take a still photo and save it to the camera roll
// Take a still photo and save to the camera roll if let image = try? await dataScanner.capturePhoto() { UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil) }
-
11:10 - Using the recognizedItems async stream to keep track of items
// Send a notification when the recognized items change. var currentItems: [RecognizedItem] = [] func updateViaAsyncStream() async { guard let scanner = dataScannerViewController else { return } let stream = scanner.recognizedItems for await newItems: [RecognizedItem] in stream { let diff = newItems.difference(from: currentItems) { a, b in return a.id == b.id } if !diff.isEmpty { currentItems = newItems sendDidChangeNotification() } } }
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。