使用计算机视觉和深度学习创建现代 OCR 管道

在这篇文章中,我们将带您了解我们如何为[【移动文档扫描仪】构建最先进的光学字符识别(OCR)管道的幕后故事。我们使用了计算机视觉和深度学习的进步,如双向长短期记忆(LSTM),连接主义时间分类(CTC),卷积神经网络(CNN)等。此外,我们还将深入研究如何实际使我们的 OCR 管道在 Dropbox 规模上做好生产准备。

文档扫描仪可以使用手机拍照并[“扫描”]收据和发票等项目。我们的移动文档扫描仪仅输出图像 – 就计算机而言,图像中的任何文本都只是一组像素,无法复制粘贴,搜索或您可以对文本执行的任何其他操作。

因此,需要应用光学字符识别或OCR。此过程从我们的文档扫描图像中提取实际文本。运行 OCR 后,我们可以为 Dropbox Business 用户启用以下功能:

  • 提取扫描文档中的所有文本并为其编制索引,以便以后可以搜索
  • 创建隐藏的叠加层,以便可以从另存为 PDF 的扫描件中复制和粘贴文本

当我们构建移动文档扫描仪的第一个版本时,我们使用了一个商用现成的 OCR 库,以便在深入创建我们自己的基于机器学习的 OCR 系统之前进行产品验证。这意味着将商业系统集成到我们的扫描管道中,为我们的业务用户提供上述两种功能,以查看他们是否从OCR中找到了足够的用途。一旦我们确认用户对移动文档扫描仪和OCR的需求确实很强烈,我们决定构建自己的内部OCR系统,原因有几个。

首先,有一个成本考虑:拥有自己的OCR系统将为我们节省大量资金,因为许可的商业OCR SDK根据扫描次数向我们收费。其次,商业系统针对平板扫描仪图像的传统OCR世界进行了调整,而我们的操作场景要困难得多,因为手机照片更加不受约束,具有褶皱或弯曲的文档,阴影和不均匀的照明,模糊和反射高光等。因此,我们可能有机会提高识别准确性。

事实上,计算机视觉世界发生了翻天覆地的变化,这给了我们一个独特的机会。传统上,OCR系统是大量流水线的,手工构建和高度调整的模块利用了各种条件,它们可以假设使用平板扫描仪捕获的图像是正确的。例如,一个模块可能查找文本行,然后下一个模块将查找单词和段字母,然后另一个模块可能会对字符的每个部分应用不同的技术来找出字符是什么,依此类推。大多数方法都依赖于输入图像的二值化作为早期阶段,这可能很脆弱,并丢弃了重要的线索。构建这些 OCR 系统的过程非常专业且劳动密集型,系统通常只能处理来自平板扫描仪的相当有限的影像。

在过去的几年中,深度学习成功地应用于计算机视觉中的许多问题,这些问题为我们提供了强大的新工具来处理OCR,而不必复制过去复杂的处理管道,而是依靠大量数据让系统自动学习如何执行许多以前手动设计的步骤。

也许构建我们自己的系统的最重要原因是,它将让我们更好地控制自己的命运,并允许我们在未来开发更多创新功能。

在本博客文章的其余部分,我们将带您了解我们如何以 Dropbox 规模构建此管道的幕后故事。大多数商业机器学习项目遵循三个主要步骤:

  1. 研究和原型设计,看看是否有可能
  2. 为实际最终用户生产模型
  3. 在现实世界中完善系统

我们将依次引导您完成这些步骤中的每一个。

研究和原型设计

我们最初的任务是看看我们是否可以构建一个最先进的OCR系统。

我们首先收集了一组具有代表性的捐赠文档图像,这些图像与用户可能上传的内容相匹配,例如收据,发票,信件等。为了收集这一组,我们询问了一小部分用户,他们是否会捐赠一些图像文件供我们改进算法。在Dropbox,我们非常重视用户隐私,因此明确表示这是完全可选的,如果捐赠,文件将保持私密和安全。我们对此类用户捐赠的数据使用各种安全预防措施,包括从不将捐赠的数据保存在本地计算机上的永久存储中,维护广泛的审计,需要强大的身份验证才能访问其中任何数据,等等。

对于用户捐赠的数据,另一个重要的、特定于机器学习的组件是如何标记它。大多数当前的机器学习技术都是受到严格监督的,这意味着它们需要显式手动标记输入数据,以便算法可以学习自己进行预测。传统上,这种标签是由外部工人完成的,通常使用微工作平台,如亚马逊的Mechanical Turk(MTurk)。但是,使用MTurk的缺点是每个项目都可能被不同的工作人员看到和标记,我们当然不希望像这样在野外公开用户捐赠的数据!

因此,我们在Dropbox的团队创建了我们自己的数据注释平台,名为DropTurk。DropTurk可以向MTurk(如果我们处理公共非用户数据)或一小群雇用的承包商提交标签作业,以获取用户捐赠的数据。这些承包商遵守严格的保密协议(NDA),以确保他们不能保留或共享他们标记的任何数据。DropTurk包含注释任务UI模板的标准列表,我们可以针对新数据集和标记任务快速组装和自定义这些模板,这使我们能够非常快速地注释数据集。

例如,下面是一个 DropTurk UI,旨在为单个单词图像提供真实数据,包括以下选项之一供工作人员完成:

  • 转录图像中的实际文本
  • 标记单词的方向是否正确
  • 标记它是否为非英语脚本
  • 标记它是否不可读或不包含任何文本

imgDropTurk UI,用于为单词图像添加地面实况数据

我们的DropTurk平台包括仪表板,可查看过去作业的概述,观察当前作业的进度并安全地访问结果。此外,我们可以进行分析以评估员工的表现,甚至可以对正在进行的工作进行注释进行员工级别的图形监控,以便及早发现潜在问题:

DropTurk DashboardDropTurk Dashboard

使用DropTurk,我们收集了一个单词级数据集,其中包含单个单词及其注释文本的图像,以及一个完整的文档级数据集,其中包含完整文档(如收据)和完全转录文本的图像。我们使用后者来测量现有最先进的OCR系统的准确性;然后,这将通过告诉我们必须满足或击败我们自己的系统而达到或击败的分数来告知我们的努力。在这个特定的数据集上,我们必须达到的准确率是在90年代中期。

我们的第一个任务是确定 OCR 问题是否能在合理的时间内得到解决。因此,我们将 OCR 问题分为两部分。首先,我们将使用计算机视觉来获取文档的图像并将其分割成行和单词;我们称之为单词检测器。然后,我们将每个单词输入到深网中,将单词图像转换为实际文本;我们称之为“深网”这个词。

我们认为Word Detector会相对简单,因此我们首先将精力集中在Word Deep Net上,我们不太确定。

字深网

Word Deep Net结合了计算机视觉和自动语音识别系统中使用的神经网络架构。裁剪单词的图像被输入到具有多个卷积层的卷积神经网络(CNN)中。然后,CNN输出的视觉特征作为序列馈送到双向LSTM长短期记忆)(在语音识别系统中很常见),这使我们的单词“片段”有意义,最后使用连接主义时间分类(CTC)层进行文本预测。在适当的情况下使用批处理规范化

imgOCR 字深网

一旦我们决定了将单个单词的图像转换为文本的网络架构,我们就需要弄清楚如何收集足够的数据来训练它。深度学习系统通常需要大量的训练数据才能获得良好的识别性能。事实上,训练数据量往往是当前系统中最重要的瓶颈。通常,所有这些数据都必须收集然后手动标记,这是一个耗时且昂贵的过程。

另一种方法是以编程方式生成训练数据。然而,在大多数计算机视觉问题中,目前很难为训练算法生成足够逼真的图像:成像环境和转换的多样性太大,无法有效模拟。(当前研究的一个有前途的领域是生成对抗网络(GAN),它似乎非常适合生成现实数据。幸运的是,在这种情况下,我们的问题是使用合成数据的完美匹配,因为我们需要生成的图像类型非常受限制,因此可以自动渲染。与自然或大多数人造物体的图像不同,文档及其文本是合成的,并且单个字符的可变性相对有限。

我们的合成数据管道由三部分组成:

  1. 包含要使用的单词的语料库
  2. 用于绘制单词的字体集合
  3. 一组用于模拟真实世界扭曲的几何和光度变换

生成算法只是从每个样本中抽取样本,以创建一个独特的训练示例。

img合成生成的单词图像

我们从这三个字体开始,单词来自19世纪的古腾堡计划书籍,我们收集了大约一千种字体,以及一些简单的扭曲,如旋转,下划线和模糊。我们生成了大约一百万个合成单词,训练了我们的深度网络,然后测试了我们的准确性,大约是79%。这没关系,但还不够好。

通过多次迭代,我们以多种方式发展了合成数据管道的每一部分,以提高识别准确性。一些亮点:

  • 我们注意到我们在收据上做得不好,所以我们扩展了我们的单词语料库,以包括统一产品代码(UPC)数据库,该数据库包含诸如“24QT TISSUE PAPER”之类的条目,这些条目通常出现在收据上。
  • 我们注意到网络在处理具有断开连接的片段的字母时遇到了困难。这揭示了一个更深层次的问题:收据通常使用带有斑点,断开连接或墨水污迹的字母的热敏字体打印,但是我们的网络只获得了具有平滑连续字体(如来自激光打印机)或轻度位映射字符(如屏幕截图)的训练数据。为了解决这一缺点,我们最终找到了中国的一家字体供应商,他们可以为我们提供具有代表性的古代热敏打印机字体。

img使用不同的热敏打印机字体合成生成的单词,在收据中很常见

  • 我们的字体选择过程最初太天真了。我们最终手工选择了大约2000种字体。并非所有字体都得到同等使用。因此,我们对世界上排名前50位的字体进行了研究,并创建了一个字体频率系统,使我们能够更频繁地从常见字体(如Helvetica或Times New Roman)中采样,同时仍然保留长尾稀有字体(例如一些华丽的徽标字体)。此外,我们发现某些字体的符号不正确或支持有限,导致只有正方形,或者它们的小写或大写字母不匹配,因此不正确。我们必须手动遍历所有两千种字体,并标记那些具有无效符号,数字或大小写的字体,这样我们就不会无意中用不正确的数据训练网络。
  • 上游单词检测器(稍后描述)经过调整,可提供高召回率和低精度。在图像中查找文本过于热心,这样它就不会错过任何实际文本(高召回率),而牺牲了经常“找到”实际上不存在的单词(低精度)。这意味着Word Deep Net必须处理大量具有噪声的基本上空白的图像。因此,我们让合成数据管道生成具有代表性的负训练示例,其中包含空的地面真值字符串,包括常见的纹理背景,如木材、大理石台面等。

img合成生成的否定训练示例

  • 从合成生成的单词的直方图中,我们发现许多符号被低估了,例如/或&。我们通过合成生成具有代表性的日期、价格、URL 等,人为地提高了合成语料库中这些内容的频率。
  • 我们添加了大量的视觉转换,例如翘曲、假阴影和假折痕等等。

img假阴影效果

数据与使用的机器学习模型一样重要,因此我们花费了大量时间来优化此数据生成管道。在某个时候,我们将开源并发布这些合成生成的数据,供其他人训练和验证他们自己的系统和研究。

我们在 Amazon EC2 G2 GPU 实例上训练了我们的网络,并行启动了许多实验。我们所有的实验都放在一个实验室笔记本中,其中包括复制实验所需的一切,以便我们可以跟踪意外的准确性凸起或损失。

我们的实验室笔记本包含编号实验,最新的实验是第一个。它跟踪了机器学习可重复性所需的所有内容,例如所用代码的唯一 git 哈希、指向 S3 的指针以及生成的数据集和结果、评估结果、图形、该实验目标的高级描述等。当我们构建合成数据管道和训练网络时,我们还构建了许多专用工具来可视化字体、调试网络猜测等。

img示例早期实验跟踪错误率与我们的Word Deep Net训练了多长时间,与仅由单个单词组成的评估数据集(单字准确性)

我们早期的实验跟踪了Word Deep Net在单个单词的OCR图像上的表现,我们称之为单字准确性(SWA)。在这种情况下,准确性意味着深度网络有多少基本真理词是正确的。此外,我们还跟踪了网络的精度和召回率。精度是指深度网络返回的实际上正确的单词的比例,而召回率是指深度网络正确预测的评估数据的比例。在精度和召回率之间往往存在权衡。

例如,假设我们有一个机器学习模型,旨在将电子邮件分类为垃圾邮件。精确度将是分类器是否所有标记为垃圾邮件的东西,有多少实际上是垃圾邮件?相比之下,回想一下,在所有真正是垃圾邮件的东西中,我们是否标记了多少?可以正确标记垃圾邮件(高精度),同时不实际标记所有真正的垃圾邮件(低召回率)。

每周,我们跟踪我们做得有多好。我们将数据集划分为不同的类别,例如register_tapes(收据),屏幕截图,scanned_docs等,并为每个类别单独计算准确性,并计算所有数据的整体准确性。例如,下面的条目显示了我们实验室笔记本中第一次完整的端到端测试的早期工作,其中一个真正的单词检测器与我们真正的Word Deep Net相结合。你可以看到,我们在一开始做得非常糟糕:

img我们实验室笔记本中早期端到端实验的屏幕截图

在某一时刻,我们的合成数据管道在我们的OCR基准集上产生了高80年代的单字准确性(SWA)百分比,我们决定完成这一部分。然后,我们收集了大约20,000个真实的单词图像(相比之下,我们的100万个合成生成的单词),并使用这些图像来微调Word Deep Net。这把我们带到了90年代中期的SWA。

我们现在有一个系统,可以在单个单词图像上做得很好,但当然,一个真正的OCR系统可以对整个文档的图像进行操作。我们的下一步是专注于文档级的单词检测器。

字检测器

对于我们的 Word Detector,我们决定不使用基于网络的深度方法。这种方法的主要候选者是对象检测系统,如RCNN,它试图从图像中检测狗,猫或植物等物体的位置(边界框)。大多数图像可能只有给定对象的一到五个实例。

然而,大多数文档不仅只有几个单词 – 它们有数百甚至数千个单词,即比当时大多数基于神经网络的对象检测系统能够找到的对象多几个数量级。因此,我们不确定这样的算法是否会扩展到我们的OCR系统所需的水平。

另一个重要的考虑因素是,使用特征检测器的传统计算机视觉方法可能更容易调试,因为神经网络是出了名的不透明,并且具有难以理解和解释的内部表示。

我们最终使用了一种经典的计算机视觉方法,称为最大稳定极值区域(MSER),使用OpenCV的实现。MSER 算法查找图像的不同阈值或级别处的连接区域。从本质上讲,它们检测图像中的斑点,因此特别适合文本。

我们的单词检测器首先检测图像中的 MSER 特征,然后将这些特征串联成单词和行检测。一个棘手的方面是,我们的单词深度网络接受固定大小的单词图像输入。这要求字检测器有时在单个检测框中包含多个单词,或者如果单个单词太长而不适合深度网络的输入大小,则将其切成两半。然后,有关这种斩波的信息必须通过整个管道传播,以便我们可以在深网运行后重新组装它。另一个棘手的问题是处理深色背景上带有白色文本的图像,而不是白色背景上的深色文本,这迫使我们的 MSER 检测器能够处理这两种情况。

组合式端到端系统

一旦我们将Word Detector改进到可接受的点,我们就将其与Word Deep Net链接在一起,以便我们可以针对文档级图像而不是我们较旧的单字准确性基准测试套件对整个组合系统进行端到端的基准测试。然而,当我们第一次测量端到端的准确性时,我们发现我们的表现约为44%, 比竞争对手差得多。

主要问题是图像中噪声的间距和虚假的垃圾文本。有时我们会错误地将两个单词组合在一起,例如“helloworld”,或者错误地将单个单词片段化,例如“ wo rld”。

我们的解决方案是修改网络的连接主义时间分类 (CTC) 层,以便除了预测文本之外,还为我们提供置信度分数。然后,我们使用此置信度分数以三种方式对预测进行筛选:

  1. 如果置信度很高,我们保持预测不变。
  2. 如果置信度很低,我们只是简单地过滤掉它们,打赌这些是噪声预测。
  3. 如果置信度在中间的某个地方,然后我们通过牛津英语词典生成的词典进行运行,在单词预测框之间和内部应用不同的转换,尝试组合单词或以各种方式拆分它们以查看它们是否在词典中。

我们还必须处理由前面提到的Word Deep Net的固定接受图像大小引起的问题:即单个“单词”窗口实际上可能包含多个单词或仅包含很长单词的一部分。因此,我们通过一个称为Wordinator的模块将这些输出与来自单词检测器的原始输出一起运行,该模块为每个单独的OCRed单词提供了离散的边界框。这将生成单个单词坐标及其 OCRed 文本。

例如,在我们的系统中的以下调试可视化中,您可以在Wordinator之前看到检测到的单词周围的框:

imgWordinator 会将其中一些框分解为单独的单词坐标框,例如“of”和“Engineering”,它们当前是同一框的一部分。

最后,现在我们有了一个完全工作的端到端系统,我们生成了超过一千万个合成单词,并训练我们的神经网络进行大量的迭代,以尽可能多地提高准确性。所有这些最终为我们提供了准确性、精确度和召回率数据,这些数字都达到或超过了 OCR 最先进的技术。

我们短暂地拍了拍自己的后背,然后开始为下一个艰难的阶段做准备:生产。

生产化

在这一点上,我们有一个原型Python和Lua脚本包装Torch的集合 – 当然还有一个训练有素的模型!— 这表明我们可以实现最先进的 OCR 准确性。但是,这与实际用户可以在具有可靠性,性能和可靠工程的分布式环境中使用的系统相去甚远。我们需要创建一个适合数百万用户使用的分布式管道,以及一个取代原型脚本的系统。此外,我们必须在不中断现有 OCR 系统的情况下使用商用现成 SDK 来做到这一点。

下面是生产化 OCR 管道的图示:

img整体生产 OCR 管道

我们首先为不同的OCR引擎创建一个抽象,包括我们自己的引擎和商业引擎,并使用我们的内部实验框架Stormcrow对其进行了控制。这使我们能够在不中断现有 OCR 系统的情况下引入新管道的骨架,该系统已经为数百万商业客户在生产中运行。

我们还将基于Torch的模型(包括CTC层)移植到TensorFlow,原因有几个。首先,我们已经在生产环境中对TensorFlow进行了标准化,以便更轻松地管理模型和部署。其次,我们更喜欢使用Python而不是Lua,TensorFlow具有出色的Python绑定。

在新管道中,移动客户端将扫描的文档图像上传到我们的内部异步工作队列。上传完成后,我们通过远程过程调用 (RPC) 将图像发送到运行 OCR 服务的服务器群集。

实际的OCR服务使用OpenCV和TensorFlow,两者都是用C++编写的,并且具有复杂的库依赖关系;因此,安全漏洞是一个真正的问题。我们使用 LXCCGroupsLinux NamespacesSeccomp 等技术将实际的 OCR 部分隔离到 jail 中,以提供隔离和系统白名单,使用 IPC 进出隔离的容器。如果有人破坏了监狱,他们仍然会与我们系统的其余部分完全分离。

我们的 jail 基础结构允许我们在启动时一次性有效地设置昂贵的资源,例如加载我们训练的模型,然后将这些资源克隆到 jail 中以满足单个 OCR 请求。这些资源被克隆为写入时复制到分叉的 jail 中,并且对于我们如何使用模型是只读的,因此它非常高效和快速。我们必须修补TensorFlow,以便更容易地进行这种分叉。(我们在上游提交了补丁。

一旦我们获得单词边界框及其OCRed文本,我们就会将它们合并回移动文档扫描仪生成的原始PDF中,作为OCR隐藏层。因此,用户将获得一个包含扫描图像和检测到的文本的PDF。OCRed 文本也会添加到 Dropbox 的搜索索引中。用户现在可以突出显示和复制粘贴PDF中的文本,由于我们隐藏的单词框坐标,突出显示的位置将放在正确的位置。他们还可以通过 Dropbox 上的 OCRed 文本搜索扫描的 PDF。

性能调优

在这一点上,我们现在有一个实际的工程管道(带有单元测试和持续集成!),但仍然存在性能问题。

第一个问题是,我们是否会在推理时在生产中使用 CPU 或 GPU。训练深度网络比在推理时使用它需要更长的时间。在训练期间使用GPU是很常见的(就像我们所做的那样),因为它们大大减少了训练深度网络所需的时间。但是,在推理时使用 GPU 是目前更难进行的调用。

首先,在Dropbox等生产数据中心拥有高端GPU仍然有点异国情调,并且与其他机队不同。此外,基于 GPU 的机器更加昂贵,并且基于快速开发,配置正在更快地搅动。我们对我们的Word Detector和Word Deep Net在CPU和GPU上的表现进行了广泛的分析,假设充分利用每个CPU上的所有内核以及CPU的特征。经过大量分析,我们决定,与 GPU 机器相比,我们只需在 CPU 上即可达到性能目标,成本相似或更低。

一旦我们决定使用CPU,我们就需要针对Word Deep Net优化我们的系统BLAS库,稍微调整我们的网络,并将TensorFlow配置为使用可用内核。我们的单词检测器也是一个重要的瓶颈。我们最终以更模块化的方式重写了OpenCV C++MSER实现,以避免在执行两次传递时重复缓慢的工作(以便能够处理黑白文本以及黑文本上的白色);向我们的Python层(底层MSER树层次结构)公开更多内容,以实现更有效的处理;并使代码实际可读。我们还必须优化 MSER 后 Word 检测管道,以调整和矢量化其中的某些慢速部分。

在所有这些工作之后,我们现在有了一个生产化的高性能系统,我们可以为少数用户“影子打开”,从而进入第三个阶段:改进。

优雅

由于我们提议的系统在生产中与商业OCR系统并行运行,我们需要确认我们的系统确实更好,这是根据真实用户数据测量的。在 Dropbox,我们非常重视用户数据隐私,因此我们不能只查看和测试随机移动文档扫描图像。相反,我们使用前面详述的用户图像捐赠流程来获得评估图像。然后,我们使用这些捐赠的图像,非常小心地保护它们的隐私,对两个OCR系统进行端到端的定性黑盒测试,并且很高兴地发现我们确实执行了与旧的商业OCR SDK相同或更好的功能,使我们能够将我们的系统提升到100%的Dropbox Business用户。

接下来,我们测试了在这些捐赠文档上微调我们训练有素的深度网络与我们手工选择的微调图像套件是否有助于提高准确性。不幸的是,它没有移动针头。

另一个重要的改进是进行方向检测,这是我们在原始管道中没有完成的。来自移动文档扫描仪的图像可以旋转90°甚至倒置。我们使用另一个基于Inception Resnet v2架构的深度网络构建了一个方向预测器,更改了最后一层以预测方向,收集了方向训练和验证数据集,并从偏向于我们自己需求的ImageNet训练模型中进行了微调。我们将此方向预测器放入管道中,使用其检测到的方向将图像旋转到直立,然后再进行字检测和 OCRing。

方向预测器的一个棘手方面是,只有一小部分图像实际上是旋转的。我们需要确保我们的系统在尝试修复较少数量的非直立图像的方向时,不会无意中旋转直立图像(最常见的情况)。此外,我们必须解决各种棘手的问题,将我们的直立旋转图像与PDF文件格式可以应用自己的转换矩阵进行旋转的不同方式相结合。

最后,我们惊讶地发现,在 Apple 的原生预览应用程序中,包含扫描的 OCRed 隐藏层的 PDF 文件格式存在一些棘手的问题。大多数 PDF 呈现器都尊重文本中嵌入的空间以进行复制和粘贴,但 Apple 的预览应用程序会执行自己的启发式方法,以根据文本位置确定单词边界。这导致从此PDF渲染器复制和粘贴的质量不可接受,导致大多数空格被删除,并且所有单词都被“一起填充”。我们必须对一系列PDF渲染器进行广泛的测试,以找到正确的PDF技巧和解决方法来解决这个问题。

CRed 隐藏层的 PDF 文件格式存在一些棘手的问题。大多数 PDF 呈现器都尊重文本中嵌入的空间以进行复制和粘贴,但 Apple 的预览应用程序会执行自己的启发式方法,以根据文本位置确定单词边界。这导致从此PDF渲染器复制和粘贴的质量不可接受,导致大多数空格被删除,并且所有单词都被“一起填充”。我们必须对一系列PDF渲染器进行广泛的测试,以找到正确的PDF技巧和解决方法来解决这个问题。

总而言之,这一轮的研究、生产和改进花费了大约8个月的时间,最后,我们使用现代计算机视觉和深度神经网络技术为数百万用户构建并部署了最先进的OCR管道。我们的工作也为 Dropbox 未来基于 OCR 的产品奠定了坚实的基础。

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
xiaoxingxing的头像xiaoxingxing管理团队
上一篇 2023年2月23日 下午1:50
下一篇 2023年2月23日 下午1:51

相关推荐