周末晚上,你和朋友走进热闹的夜市,想统计每家摊位招牌上写着什么。可放眼望去,霓虹灯闪烁、人潮涌动、招牌歪七扭八,有的被电线挡了一半,有的字小得眯眼都看不清。你首先要做的,不是“读出”招牌,而是“找出”招牌——先判断“哪里有字、字占多大一块地方”,然后才轮到看清上面写的是“烤冷面”还是“炒酸奶”。 这件事放到电脑上,就叫文字检测(Text Detection):给定一张图像,输出所有文字区域的位置框;而把框里的字真正“读”出来,是文字识别(Recognition)的任务。两者拼在一起,才是完整的 OCR(光学字符识别)。在 OCR 流水线里,检测是“眼睛先扫到字”,识别是“大脑再读懂字”——检测一旦漏掉或错位,后面的识别再强也无从下手。 本文就用“夜市找招牌”这条主线,把文字检测的概念、难点、经典方法、评估指标与工程优化一一讲透。
文字检测是 OCR 与文档智能化的第一道技术关卡。掌握它,你才真正理解“从图片到文字”的完整链路,也为阅读各类视觉大模型打下地基。
目录
可视化演示
展示系统处理流水线、实时性能指标曲线及多方案对比分析,包含数据流转、吞吐延迟监控与方案评估。
本节配有交互动效(进入视口后自动加载,约 3KB)。
系统可视化 处理流程:输入→处理→模型→输出 性能监控:实时指标 P=L×T
基础概念认知:先找到招牌,再读招牌
在夜市里,你扫一眼就能圈出哪几个摊位有招牌,哪怕招牌字体各异、颜色不同。人脑天生擅长“定位文字”——不管它长什么样,你都能快速划出“字在那一块”。这正是文字检测模仿的能力:只回答“文字在哪儿”,不回答“写了什么”。
在 AI 领域,文字检测被定义为:输入一张图像,输出一个或多个边界框,每个框圈住一块文字区域。它属于计算机视觉(CV)中的目标检测分支——目标检测本来就是“在图像里找到物体并画框”的任务,只是文字检测把目标类别锁定为“文字”一类,且允许框随文字方向旋转。
与文字识别要严格区分:检测输出坐标,识别输出字符串。完整的 OCR 流水线是“图像预处理 → 文字检测 → 文字识别 → 后处理”,检测是前置地基。一旦检测漏掉或框歪了,识别结果必然跟着出错——就像你在夜市圈错了招牌,读到的自然是隔壁烧烤摊的菜单。
就像你逛夜市时,脑子里自动生成了一张“招牌地图”——每块招牌位置了然于胸,至于读不读,那是下一站的事。检测与识别,正是这样两个接力棒。
- 检测模型f_det 表示文字检测器,它接收一张图像并推断文字位置。
- 输入图像整张图像 I 被送入模型,里面混杂着文字、背景、灯光等各类内容。
- 输出框集合模型返回 n 个检测框,每个 B_i 表示一块文字区域的位置与大小。
任务定义难点:在眼花缭乱中锁定文字
夜市找招牌其实没想象中简单:招牌斜挂着、被电线遮住、霓虹灯和招牌长得像。你得不断判断:“这是字,还是装饰?” 这种“文字 vs 非文字”的纠结,正是文字检测任务的核心难点之一。
技术上,文字检测要解决两件事:一是判断哪些像素或区域属于文字(文字与背景区分),二是把这些区域用合适的边界框出来(边界框形式多样)。由于自然场景中的文字可以旋转、弯曲甚至变形,检测框常常不是水平矩形,而是带角度的四边形框。
场景多变进一步放大了难度:光照不均(一半亮一半暗)、图像模糊(手机手抖)、低对比度(白字灰底)、密集排布(招牌挤在一起)、艺术字(笔画夸张变形)。这些情况让“文字”和“背景”的边界变得模糊,简单规则根本划不清。
就像夜市老手会斜着看、蹲下看、凑近看,来判断一块亮闪闪的东西到底是招牌还是灯箱——检测模型的任务,就是把这种“眼力”自动化、规模化。
- 候选区域图像被划分成许多候选窗口,每个区域 R_i 都要回答“是不是文字”。
- 文字概率模型为区域 R_i 输出属于文字的概率,值越接近 1 越像招牌文字。
- 阈值判决概率超过阈值 τ 判为文字(y=1),否则判为背景(y=0)。
传统检测方法:用一套手工规则淘金
在深度学习流行之前,大家靠“手工特征”找文字,就像老字号夜市摊靠祖传配方吸引顾客——配方是固定的几条规则,不学习、不进化。这套“配方”里的两招最经典。
第一招 MSER(最大稳定极值区域):把图像想象成一张灰度地形图,水位从低到高慢慢上涨,有些“水洼”(连通区域)在很大水位区间里面积几乎不变——它们很可能是文字笔画,因为笔画内部灰度相对均匀,不像背景那样忽明忽暗。第二招 SWT(笔画宽度变换):招牌文字有一个惊人规律——笔画宽度大致恒定,沿着边缘找到宽度一致的连通笔画带,就顺藤摸瓜找到了字。
这两种方法在干净的文档扫描件上效果不错:速度快、无需海量标注数据。但面对复杂背景、模糊、弯曲、艺术字时,误检漏检严重——手工规则毕竟是“祖传配方”,覆盖不了现实世界的千变万化。夜市里一块花纹复杂的灯箱,就足以让 MSER 和 SWT 同时“看走眼”。
就像夜市里真正的招牌就算灯光忽明忽暗,轮廓依然清晰可辨;而霓虹灯拼成的假装饰则一变再变。MSER 找的正是这种“不管怎么变都稳定”的形状。
- 极值区域把灰度图看成地形,Q_i 是在灰度阈值 i 下连成一体的“水洼”。
- 抬高与降低Q_{i+Δ} 与 Q_{i-Δ} 分别是阈值上下浮动 Δ 后的同源水洼区域。
- 面积变化量两次阈值之间的面积差越小,说明水洼轮廓越稳定、越不容易变形。
- 稳定度比值用变化面积除以当前面积,q_i 越小说明越稳定,越可能是文字笔画。
深度学习检测:让神经网络学会找招牌
手工规则终究敌不过现实复杂,于是大家改用“教”的:给神经网络看成千上万张“夜市照片”,并告诉它每块招牌的位置,让它自己总结规律。这就是深度学习文字检测——数据驱动取代手工配方。
三个代表性模型构成了一条清晰的技术脉络。CTPN:把文字行想象成一排队列,先检测一个个“小片段”(竖条),再用序列模型把片段串成完整文本行——擅长水平文字,是早期经典。EAST:跳过分段,直接从像素“一步到位”回归出整个四边形框——速度快,适合自然场景,是“少步骤、高效率”路线的代表。DBNet:提出可微二值化,把“文字/背景”的分割概率图平滑地变成清晰文字区域,解决了分割与检测割裂的问题,兼顾精度与速度。
深度检测的共同骨架是:骨干网络提取特征 → 特征金字塔融合多尺度信息 → 分类头判断文字/背景 → 回归头输出边界框 → 后处理得到最终结果。其中数据决定上限:标注越准、场景越多样,模型越强。这也解释了为什么“标注师傅”在 OCR 团队里如此重要。
深度模型像一位走遍无数夜市的“招牌通”,见过的招牌多了,自然练就火眼金睛——甚至能认出被树枝挡了一半、倒着挂的招牌。这是手工规则无法企及的。
- 分割概率网络先预测每个像素 (i,j) 属于文字的概率,得到一张软概率图。
- 缩放系数k 控制曲线的陡峭程度,k 越大,文字/背景的边界越锐利。
- S型映射整个分式把任意概率值压向 0 或 1 之间,且处处可导,梯度能正常回传。
性能评估指标:用数字丈量火眼金睛
都说自己眼力好,怎么量化?夜市考官给你一张照片,让你圈出所有招牌,再对照标准答案打分。打分之前,必须先定规则:什么叫“找对了”?
“找对”的判定用 IoU(交并比):预测框与真实框的交集面积除以并集面积,得到一个 0 到 1 的重合度。超过阈值(常用 0.5 或 0.7)就算命中。IoU 是检测任务最基础的度量,就像圈出的招牌区域和真实招牌范围重合了多少。
判定命中后,再统计三笔账:TP 找对的招牌、FP 把装饰误当招牌、FN 漏掉的招牌。由此得到精确率 Precision = 找出来的里面真招牌的占比;召回率 Recall = 所有真招牌里被找到的占比。两者像跷跷板:框得保守,Precision 高但 Recall 低;框得激进,反之。F1 用调和平均综合两者,防止模型偏科。
夜市考官最终看 F1 打分:既不喜欢你乱圈(误报多),也不喜欢你漏圈(漏报多),要的是“稳、准、全”。任何一个调参工程师,都要学会用这三把尺子说话。
- 精确率TP 是找对的招牌数,FP 是误报数,精确率回答“找出来的够不够纯”。
- 召回率FN 是漏报数,召回率回答“所有真招牌被找回来了多少”。
- F1 调和平均只有精确率和召回率同时高,F1 才高,防止模型走极端。
优化策略实践:让找招牌又快又稳
王牌夜市通也要练技巧:有的招牌大得占半面墙,有的小如巴掌。同一个人,得远近结合地看、来回确认地看,才能一个不漏。检测模型同样需要成套的“看家功夫”。
多尺度检测:把图像缩放成多个尺寸分别检测再合并结果,让大招牌、小招牌都能被抓住;数据增强:训练时把照片随机旋转、调亮度、加模糊、模拟遮挡,让模型“见多识广”,在真实世界的刁钻角度下不慌;后处理 NMS(非极大值抑制):检测会产出一大堆重叠的候选框,NMS 按置信度排序,保留最可信的框、抑制冗余重复框,得到干净利落的最终输出。
部署层面还有:模型量化(把浮点权重压成整数以提速)、知识蒸馏(大模型当老师教小模型)、TensorRT 等推理加速。工程上常备“降级策略”:超长文本行要切块检测,避免行被截断;低置信度区域要二次确认,宁可多跑一遍也不能漏检。
就像夜市通看完一圈还会回头再扫一遍,把重复认的招牌合并、把漏掉的小招牌补上——“多尺度 + 数据增强 + NMS”就是这套回头再确认的功夫,让检测又快又稳。
- 候选框排序模型输出许多重叠框,按置信度从高到低逐个处理这些候选。
- 重叠计算当前框与所有已保留框逐一计算 IoU,判断是不是重复框。
- 抑制规则若与任一保留框重叠超过阈值 t,说明是重复框,丢弃;否则保留。
应用场景展望:从夜市走向世界
“会找招牌”的本事放大了,就是整个 OCR 世界的入场券。从夜市摊位的几块招牌,到满城的门牌、路牌、屏幕,会“找字”的 AI 正在把物理世界的文字变成可检索的数据。
文档扫描识别:把纸质合同、发票拍照,检测先把“正文区、标题区、表格区”找出来,再逐块识别,是办公自动化的基础;场景文字提取:手机拍照翻译、街景路牌识别、自动驾驶读路标,检测必须应对旋转、光线与遮挡;票据审核:银行、财务把发票和身份证的关键字段区域先定位再录入,检测精度直接决定“少录、错录”率。
趋势上,检测与识别正从“两个模型串联”走向“端到端联合”——一个模型同时输出位置和文字,共享特征、互相促进。大模型与 Transformer 架构也进入检测领域,配合视觉-语言预训练,让“找字”变得更鲁棒、更通用。
从夜市的一两块招牌,到整座城市的文字海洋,检测是第一步,却也是最关键的一步——它为所有“读懂世界”的 AI 应用铺好了地基。
- 检测损失L_det 衡量预测框与真实框的位置和分类误差,保证框得准。
- 识别损失L_rec 衡量识别出的字符与真实文本的误差,保证读得对。
- 联合加权λ 调节两者权重,端到端训练让检测与识别共享特征、互相促进。
AI 应用场景
合同票据数字化归档
阶段:模型训练与推理部署
解决的问题:财务部每天收到数百张发票、合同照片,人工录入慢且易错。传统做法用固定模板定位字段位置,但照片角度、光照千差万别,模板一碰就碎。AI 文字检测先自动定位每个字段区域(发票号、金额、税号),再交给识别模型提取内容。
具体案例:某企业报销系统:员工拍照上传发票 → 检测模型圈出“发票代码、发票号码、金额”等区域 → 识别模型逐框读取并填入表单 → 与税务系统自动比对。检测准确率从模板法的 82% 提升到 97%,单张处理时间从 2 分钟降到 5 秒。
手机拍照翻译与路牌识别
阶段:端侧推理与模型优化
解决的问题:出国旅游想看懂菜单、路牌,需要实时检测画面中的文字区域。手机端算力有限,要求检测模型轻量化。正如夜市找招牌既要快又要准,端侧检测必须在几百毫秒内完成多尺度扫描与 NMS 去重。
具体案例:翻译 App 的“即时取词”功能:摄像头取景 → 轻量检测模型每帧输出文字框 → 翻译模型渲染结果覆盖在屏幕上。旋转、倾斜、弯曲的招牌都能被四边形框准确框住,用户举着手机扫一圈,整条街的招牌意思尽收眼底。
证件关键字段提取
阶段:数据标注与模型训练
解决的问题:银行开户、车管所登记需要从身份证、驾照照片中提取姓名、住址、有效期。证件照经常有反光、折痕、倾斜,直接整图识别会被背景干扰。检测模型先在整图中定位“姓名”“住址”等标签与对应值的区域,再聚焦识别,显著降低噪声。
具体案例:某银行开户系统对身份证正反面拍照后,检测模块稳定输出 8 个固定字段区域框,识别模块逐框提取,人工复核率从 60% 降到 5%,柜台业务办理时间缩短约 40%。
Python 演示
import numpy as np class SyntheticScene: """构造一张合成"夜市招牌"图: 4 块招牌加随机噪点""" def __init__(self, width=160, height=100, seed=7): self.rng = np.random.default_rng(seed) self.img = np.zeros((height, width), dtype=float) self.gt_boxes = [] self._paint_text() self._paint_noise() def _paint_text(self): h, w = self.img.shape for _ in range(4): x = int(self.rng.integers(5, w - 40)) y = int(self.rng.integers(5, h - 30)) bw = int(self.rng.integers(18, 32)) bh = int(self.rng.integers(10, 16)) self.gt_boxes.append([x, y, x + bw, y + bh]) for i in range(bw // 3): self.img[y:y + bh, x + i * 3:x + i * 3 + 2] = 1.0 def _paint_noise(self): h, w = self.img.shape for _ in range(30): x = int(self.rng.integers(0, w)) y = int(self.rng.integers(0, h)) r = int(self.rng.integers(1, 3)) for dx in range(-r, r + 1): for dy in range(-r, r + 1): if dx * dx + dy * dy <= r * r: xx, yy = x + dx, y + dy if 0 <= xx < w and 0 <= yy < h: self.img[yy, xx] = 1.0 def _row_to_box(img, y0, y1): band = img[y0:y1 + 1] col_density = band.sum(axis=0) / max(band.shape[0], 1) cols = col_density > 0.2 xs = [i for i, v in enumerate(cols) if v] return [xs[0], y0, xs[-1], y1] if xs else [0, y0, 0, y1] def detect_text_blocks(img): """按行/列密度聚类的简化检测器: 把高密度区域围成候选框""" h, w = img.shape row_density = img.sum(axis=1) / max(w, 1) rows = row_density > 0.05 boxes = [] start = None for y in range(h): if rows[y] and start is None: start = y elif not rows[y] and start is not None: boxes.append(_row_to_box(img, start, y - 1)) start = None if start is not None: boxes.append(_row_to_box(img, start, h - 1)) return boxes def iou(box_a, box_b): ax0, ay0, ax1, ay1 = box_a bx0, by0, bx1, by1 = box_b ix0, iy0 = max(ax0, bx0), max(ay0, by0) ix1, iy1 = min(ax1, bx1), min(ay1, by1) iw, ih = max(0, ix1 - ix0), max(0, iy1 - iy0) inter = iw * ih union = (ax1 - ax0) * (ay1 - ay0) + (bx1 - bx0) * (by1 - by0) - inter return inter / union if union > 0 else 0.0 def evaluate(preds, gts, iou_thresh=0.5): matched = [] for p in preds: for i, g in enumerate(gts): if i not in matched and iou(p, g) >= iou_thresh: matched.append(i) break tp = len(matched) fp = len(preds) - tp fn = len(gts) - tp precision = tp / (tp + fp) if tp + fp else 0.0 recall = tp / (tp + fn) if tp + fn else 0.0 f1 = 2 * precision * recall / (precision + recall) if precision + recall else 0.0 return precision, recall, f1 def main(): scene = SyntheticScene(seed=7) preds = detect_text_blocks(scene.img) precision, recall, f1 = evaluate(preds, scene.gt_boxes) print("真实招牌: %d 检测框: %d" % (len(scene.gt_boxes), len(preds))) print("P=%.2f R=%.2f F1=%.2f" % (precision, recall, f1)) if __name__ == "__main__": main()
scene = SyntheticScene(seed=7)生成一张含 4 块“招牌”和随机噪点的合成图像,作为检测的舞台。self.gt_boxes.append([x, y, x + bw, y + bh])记录每块招牌的真实位置,作为评估用的“标准答案”。row_density = img.sum(axis=1) / max(w, 1)统计每一行有多少“文字像素”,密度高的行可能是招牌区域。cols = col_density > 0.2在文字行内按列密度切分,确定招牌的左右边界。union = (ax1 - ax0) * (ay1 - ay0) + (bx1 - bx0) * (by1 - by0) - inter计算两框并集面积:各自面积相加再减去重叠部分。return inter / union if union > 0 else 0.0交集除以并集即 IoU,衡量预测框与真实框的重合程度。if i not in matched and iou(p, g) >= iou_thresh:用 IoU≥0.5 判定“找对了”,每个真实招牌只匹配一次,避免重复计数。f1 = 2 * precision * recall / (precision + recall) if precision + recall else 0.0调和平均综合精确率与召回率,防止模型偏科。
常见误区
误区初学者以为文字检测跑完,程序就能直接把图里的字“吐”出来,像截图识别那样一键得到全部文本。
正解文字检测只负责“定位”,输出的是坐标框;真正把框内像素变成字符串的是文字识别。完整 OCR 是“检测 → 识别 → 后处理”流水线。就像在夜市找招牌:你圈出了招牌位置,不代表你读出了“烤冷面”三个字,那是下一步的事。
为何常见:市面上的 OCR 工具把检测和识别封装成一步,用户只看到“图片进、文字出”,自然误以为检测本身就包含识别。
误区觉得把边框抠得和文字严丝合缝才算厉害,IoU 能到 0.99 才是好模型。
正解检测的目的是为识别提供干净的输入,通常 IoU≥0.5 即可判定命中。过度追求边界精确,收益很低,还容易在旋转、模糊场景下过拟合。识别模型本身对轻微偏移有鲁棒性,真正该关心的是整条 OCR 流水线的最终准确率。
为何常见:目标检测竞赛常晒出超高 IoU 的框,让人误以为这是衡量一切的标准;但在 OCR 场景,大家更关心“能不能读对”。
误区汇报指标只看 Precision,认为 98% 的精确率一定碾压 90% 的模型。
正解精确率只回答“找出来的里面多少是真招牌”,完全不看漏了多少。一个只框最显眼那块招牌的“懒模型”,Precision 可以是 100%,但 Recall 极低。必须结合 F1 看——精确率和召回率都高,才是真的好模型。
为何常见:人眼查看检测结果时,偶尔几个误报非常刺眼,漏报却难以察觉,于是直觉上更在意精确率。
误区深度学习是王道,传统手工方法就是过时废物,学都不用学。
正解在文档扫描、证照等背景干净、文字规整的场景,MSER/SWT 仍然零训练成本、速度快、可解释性强,常被用作候选区域生成或兜底方案。很多现代检测器也采用“传统方法生成候选 + 深度分类器精筛”的混合策略。
为何常见:技术文章爱突出新旧对比、制造“颠覆”叙事,让新人误以为旧方法彻底失效,忽略了工程里“够用就好”的务实逻辑。
面试题
Q1. 文字检测模块最典型的输出结果是什么?
- A.图像中每个文字的语音读音
- B.文字区域的坐标边界框← 正确答案
- C.图像的场景分类标签
- D.文字的翻译结果语句
答案:B。文字检测只回答“字在哪儿”,输出的是边界框坐标;读音、翻译、分类都超出它的职责。夜市场景中,检测就是先圈出招牌位置,至于招牌上写什么,是识别环节的事。
Q2. 关于 IoU 交并比,下列表述正确的是?
- A.两框交集面积与并集面积之比← 正确答案
- B.两框中心点间的欧氏距离
- C.两框面积之和与图像面积之比
- D.两框周长的算数平均值
答案:A。IoU 衡量两个框的重合程度:交集面积除以并集面积。它就像判断你圈出的招牌范围与真实招牌范围有多大重叠,是“找得准不准”的量化标准。
Q3. 真实招牌共有 10 处,模型输出 12 个框中 8 个命中真值,召回率是?
- A.0.67
- B.0.75
- C.0.80← 正确答案
- D.0.50
答案:C。召回率 = TP /(TP + FN),真实招牌 10 处,找到 8 处、漏掉 2 处,所以 R = 8/10 = 0.80。这好比夜市考官问“所有真招牌里你找回了多少”;输出框总数里有多少误报只影响精确率。
Q4. F1 分数的主要作用是什么?
- A.只衡量检测模型的速度
- B.综合平衡精确率与召回率← 正确答案
- C.衡量模型参数量大小
- D.计算训练集样本总数
答案:B。精确率和召回率像跷跷板,一个高另一个往往低。F1 用调和平均把两者合成一个分数,只有两项都高 F1 才高。夜市找招牌不能只求“圈出来都对”却漏掉一半,也不能“全圈上”却误报满天飞。
Q5. MSER 利用文字的什么特性来寻找候选区域?
- A.笔画内部灰度随阈值变化保持稳定← 正确答案
- B.所有文字都具有完全一致的颜
- C.文字行总是水平排列在图像中央
- D.文字区域的边缘始终笔直清晰
答案:A。MSER 把图像当地形,在灰度阈值连续变化时,文字笔画内部灰度均匀,区域形状保持稳定、面积变化小。就像真正的招牌在灯光忽明忽暗下轮廓依然可辨,这是 MSER 选块的依据。
Q6. EAST 相比 CTPN 的主要优势是?
- A.用 LSTM 对文本片段做序列建模
- B.直接回归四边形框免去合并← 正确答案
- C.只能够检测水平方向文字
- D.依赖两阶段候选区域网络
答案:B。CTPN 先检测竖条小片段再用序列模型串联,适合水平文本;EAST 直接用分割加回归一步输出旋转四边形框,跳过分段与合并,速度更快、对倾斜文本更友好,更适合自然场景。
Q7. 自然场景文字检测的典型难点包括哪些?
- A.文本行存在旋转弯曲变形← 正确答案
- B.光照不均与阴影遮挡← 正确答案
- C.招牌与背景装饰相似← 正确答案
- D.图像文字永远水平排列
答案:ABC。自然场景中文字常旋转、弯曲、被遮挡,光照不均会吞掉笔画,招牌与装饰背景也容易混淆;而“文字永远水平排列”显然不成立。夜市里斜挂的招牌、似字非字的灯箱,正是这些难点的写照。
Q8. 下列属于文字检测评估指标的有哪些?
- A.精确率 Precision← 正确答案
- B.召回率 Recall← 正确答案
- C.F1 调和平均← 正确答案
- D.识别词错误率
答案:ABC。检测评估关心“找得准、找得全、综合平衡”,对应精确率、召回率和 F1,IoU 则是判定命中的前提指标。而“识别词错误率”衡量识别环节输出字符串的错误,不属于检测指标。
Q9. 关于 DBNet 的可微二值化,下列说法正确的有哪些?
- A.用 S 型函数平滑逼近阈值← 正确答案
- B.训练时梯度可以正常回传← 正确答案
- C.推理阶段必须用可微二值化
- D.分割概率图直接阈值不可导← 正确答案
答案:ABD。DBNet 用可微的 S 型函数逼近二值化,让梯度在训练时能正常回传;推理时用标准二值化保持简洁。普通分割图直接阈值不可导,正是 DBNet 要解决的问题;且它输出四边形框,旋转文本也能检测。
Q10. 提升检测模型鲁棒性的工程手段包括哪些?
- A.多尺度图像金字塔检测← 正确答案
- B.随机旋转亮度数据增强← 正确答案
- C.用 NMS 合并重复预测框← 正确答案
- D.删除后处理以提升速度
答案:ABC。多尺度金字塔让模型兼顾大小招牌,旋转和亮度增强让模型适应光影变化,NMS 把重叠重复框合并成干净结果,三者都是提升鲁棒性的常用手段。删除后处理虽变快,却会留下大量重叠框,反而损害检测质量。