
1. 中文OCR里的字符分割到底卡在哪一步做过OCR相关工作的朋友应该都有体会英文或者数字识别拿一套开源引擎跑起来很容易准确率也说得过去。但一换到中文场景问题就接踵而来——字体千变万化、结构左右上下嵌套、打印体带倾斜透视、手写体更是没谱。很多人在这个环节翻车其实不是卡在识别模型上而是卡在“字符分割”上。字符分割这个词听起来像是个预处理的小步骤但它在整个中文OCR链路里的地位有点像做饭之前的备菜。菜没切好后面炒得再好也白搭。你可以把OCR理解成三步检测文字区域、分割出单个字符、对每个字符做识别。中文OCR里第二步的分割质量直接决定了第三步识别的上限。如果字符被切歪了、切碎了、或者把两个汉字黏在一起切不开再强的CRNN模型也救不回来。这篇文章想聊的就是中文字符图片的分割方法。我会把投影法、连通域分析、轮廓外接矩形这些经典手段捋一遍再讲清楚为什么现在很多开源中文OCR项目比如基于CRNN的方案开始绕开“显式分割”这条路改走CTC这种隐式对齐的路线。最后还会附上我自己在实操中踩过的一些坑以及一个可复现的Python示例帮你从零把一张包含中文文字的长图切成一个一个干净的字符图。这篇文章适合谁看如果你正在做中文文档识别、票据识别、车牌识别或者对开源中文OCRCRNN方向感兴趣但被分割环节困扰那这篇应该正好对胃口。哪怕你只是刚接触OpenCV不久只要跟着操作走也能跑通一套完整的字符切分流程。2. 中文字符分割的核心难点与整体思路2.1 中文字符和西文的本质差异先说为什么中文分割比西文麻烦。西文字符大多结构简单字母之间有明显的间隔字符宽度相对接近而且大多数单词是横向排列。分割西文基本上靠垂直投影就能做到八九分准。中文不一样。汉字是方块字笔画多结构复杂有左右结构如“好”、上下结构如“台”、左中右结构如“树”、上中下结构如“意”、半包围结构如“同”甚至还有一个字内部部件之间紧凑到几乎无法用规则切分的如“疆”。这些字内部部件的间距有时候比字与字之间的间距还要大。这意味着如果你直接用垂直投影去找字符边界很容易把一个左右结构的汉字从中间劈开切成两个错误的“字”。中文排版还天然存在文字密度高的问题。同样尺寸的图片中文能容纳的信息量远大于西文字符间粘连的情况非常常见尤其在低分辨率截图、扫描件、手机拍摄的文档中笔画和笔画之间糊在一起边界极其模糊。2.2 中文OCR的三种分割路线对比既然难那行业内是怎么处理的实际主流路线有三种各有取舍第一种是“先检测后切割再识别”的传统路线。先检测出文本框然后通过图像处理方法把框里的文字切成单字再送识别模型。这种方式逻辑最直观分割结果可干预、可调试对于印刷体、标准字体的场景效果不错但对手写体、倾斜文字、光照不均的情况非常脆弱。问题出在“分割正确率”是串联进整个系统的分割一旦出错识别必定出错而且这个错误不可逆。第二种是“整行识别隐式对齐”的路线。以CRNNCTC为代表。模型直接输入整行文字图片输出一串字符序列CTC损失函数负责在训练时自动找到每个字符对应的特征位置。这种方式不需要显式分割字符而是把分割问题“溶解”到了模型训练中。实际效果确实比传统方法抗造很多尤其对粘连字符、倾斜文字、手写体更为友好。这也是现在开源中文OCR更倾向CRNN的原因之一。第三种是基于目标检测的“端到端”路线。直接训练一个检测模型让模型自己输出“每一个字符”的外接框。典型实现比如EAST、DB、PaddleOCR里的基于检测的文本识别方案。这种方式依赖于大量标注好的单字符位置数据训练成本高但它把分割问题变成了一个目标检测问题检测框天然就是字符边界效果上对复杂背景适应性更强。三条路线的本质区别在于分割规则是人写的还是模型学出来的。前者透明可控但脆弱后者黑盒但鲁棒。实际项目里如果你的场景固定、字体统一、背景干净传统路线完全够用而且性能开销小、部署简单。如果场景复杂、样本变化大那就应该认真考虑CRNN这类无分割方案或者直接上基于检测的端到端模型。2.3 预处理为什么比分割本身更关键大多数人在做分割时容易忽略一件事图像预处理的质量比分割算法本身更能决定成败。我见过太多人拿一张灰蒙蒙、光照不均、有大量椒盐噪声的图片直接做投影分割回头跑来问“为什么投影曲线毛刺这么多、波峰波谷根本分不清”。答案很简单你的图没洗干净分割算法再优秀也发挥不出来。中文字符分割前的预处理主要有这么几步灰度化、降噪、二值化、倾斜校正。每一步都有讲究后面我会结合实操展开。这里先记住一个原则分割算法的上限由预处理决定。2.4 图片分割在工程里的真实位置另外要明确一个认知分割不是孤立的一步。它在整个OCR流水线里和文字检测、识别模型强耦合。实际工程中用传统方法切字往往是先通过文本框检测比如CTPN、EAST、DB拿到文字区域再在区域内做行分割和字分割。也就是说切字通常是在“已知这块区域有文字”的前提下进行的。这也是为什么现在很多开源项目倾向于端到端方案——流水线越短误差累积越少。但传统分割方法也远没有过时它在很多轻量级场景下依然高效。而且理解分割的原理对理解CTC如何隐式对齐也很有帮助两者并不冲突。3. 中文字符图片分割的经典方法详解3.1 基于投影的分割法投影法是字符分割里最基础也最常用的方法。核心思想很简单统计图像在水平方向和垂直方向上的像素分布把统计结果画成直方图根据直方图中的“波峰”和“波谷”来确定行和列的分割位置。具体来说如果我们有一张二值图背景为0前景为1水平投影就是统计每一行上前景像素的数量垂直投影就是统计每一列上前景像素的数量。文字行之间通常存在水平方向上的空白带表现在水平投影上就是局部低谷字符列之间也存在垂直方向上的空白带表现在垂直投影上就是局部低谷。找到这些低谷就能确定切割位置。举个例子一张图上有三行文字每一行像素在水平投影上会形成一个峰行与行之间是谷。先按水平投影把三行切出来然后对每一行再做垂直投影在每个字与字之间的谷处切下去就能得到一个个单字符图片。两步操作先切行再切列这就是投影法的完整思路。投影法的优点是计算量极小、实现简单、速度快对印刷体、等宽字体、排版规整的文字效果很好。缺点是抗干扰能力弱文字倾斜时投影曲线会糊成一片字符粘连时低谷不明显噪声会导致曲线毛刺多这个时候直接找谷底经常切错位置。针对这些缺点有一些改进思路。一个是“平滑投影”先对投影曲线做高斯模糊或移动平均把毛刺去掉再找谷底效果会稳定很多。另一个是“动态阈值”不固定用0作为谷底判断标准而是根据投影曲线的局部均值动态确定低谷这样能适应不同字号、不同字间距的情况。3.2 基于连通域分析的分割法另一种常见思路是连通域分析。把二值图像中像素值为1且彼此相邻的区域找出来每个连通区域就是一个独立的“块”。对于汉字来说一个完整的字通常但不总是对应一个连通域。把所有连通域提取出来再取每个人的外接矩形就能得到候选字符区域。OpenCV里对应的函数是cv2.connectedComponentsWithStats它会返回每个连通域的标签图、统计信息和中心点坐标。这个方法对笔画断裂不严重的中文文字效果很好而且天然支持任意角度排版——只要文字不是倾斜得太夸张外接矩形依然能框住完整的字。但中文有一个比较头疼的问题一个字内部经常自带断裂。比如“讠”字旁和右边的部件之间并不相连“氵”三点水更是天然断成三个部分。“树”这个字更是三个部件彼此独立。直接用连通域切字会把一个字拆成多个碎片输出一堆残缺图。所以实际工程里连通域分析往往不会单独用而是和投影法结合先通过垂直投影找到每个字符的大致位置区间再在这个区间内用连通域合并把断裂的部件拼回去。还有一种做法是对连通域做距离判断——如果几个外接矩形在垂直方向上的重叠度很高且水平间距小于设定的阈值就把它们合并成一个字。这个阈值一般取当前字符高度的四分之一到三分之一具体需要根据实际图片微调。3.3 基于轮廓外接矩形的分割法和连通域思路类似但实现上走的是轮廓检测路线。先用cv2.findContours找到所有文字笔画的轮廓再对每个轮廓取外接矩形cv2.boundingRect然后同样按重叠度和间距规则合并矩形最终得到字符的包围框。这个方法的优势是边界更精确因为轮廓携带形状信息不像连通域只给一个粗糙的区域标签。缺点也很明显轮廓数量极大一个汉字可能有十几个甚至几十个小轮廓合并规则写起来比较复杂规则设得过严会漏字设得过松又会切烂。我在实际项目中更常用的是“外接矩形合并”这个思路来做后处理。我会先从垂直投影拿到候选切分线然后对每个候选区域跑一遍连通域统计区域里有多少个独立块。如果块数很多而且各块之间的水平间距小于某个经验阈值就认为这是同一个字符的内部部件不应该被切开。这个“投影初步分割连通域校验合并”的组合方案比任何单一方法都稳。3.4 基于深度学习的无分割方案CRNN CTC前面说的方法都是“显式分割”也就是先用图像处理手段把字符位置定出来再切成小图。而CRNNCTC走的是完全不同的路子。CRNN是“卷积循环神经网络”的缩写结构上可以理解为前面几层卷积网络负责提取图片的特征序列中间接一层双向LSTM负责建模特征之间的序列关系最后接一个CTC损失层。关键点在于CTC允许模型输出的序列长度和真实标签长度不一致它会把输出序列和标签做“软对齐”——模型不需要精确知道每个字符在图片的哪个位置开始、哪个位置结束只需要保证整个序列的预测结果能够匹配上目标字符串。你可以把CTC理解成一个“对答案”的过程。模型输出了比如50个时间步的预测分布而真实标签只有5个字CTC会在所有可能的对齐路径里找到一条和这5个字最匹配的路径。训练完成后推理时模型直接输出字符序列根本不需要分割单字。这套方案的工程意义非常大它把分割错误这个环节直接从系统里拿掉了。中文OCR最怕的就是分字分错而CRNN天生不存在这个问题。所以现在主流的开源中文OCR项目像PaddleOCR的识别模块、一些基于CRNN的训练框架都是直接对整行文字做识别不做显式分割。但要注意CRNN并不是完全没有限制。它对输入图片的宽度有一定要求比如很多模型要求输入图片宽度是16的整数倍高度统一缩放为32或64。如果输入一张特别宽的横幅文字需要先做等比缩放确保宽度在合理范围内。如果一行文字特别长宽度被压缩得太狠字符会挤在一起识别率照样下降。所以哪怕用了CRNN预处理依然重要。至少你要保证文字行是接近水平的图片不要有大幅度旋转背景和文字的对比度要足够明显。4. 从零实操用OpenCV切出一张中文图片中的所有字符4.1 准备环境与图片先把这个环节需要的工具准备好。我用的是Python OpenCV NumPy装好就能跑不需要额外依赖pip install opencv-python numpy matplotlib测试图片最好自己生成一张这样可控性强。我用PIL在白色背景上写了几个中文汉字字号大一点字间留白均匀然后保存成PNG。你也可以直接用系统截图截一段文字但建议第一张用来练手的图尽量干净背景纯白文字横平竖直字号至少30像素以上。下面以一张示例图为例图片内容为“中文OCR字符分割”字体为黑体字号40字间距正常。实际尺寸大约400x80像素。4.2 预处理三步灰度化、二值化、降噪拿到图片后第一步是把彩色图转成灰度图。这一步没什么可说的直接cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)。第二步是二值化。二值化的目的是把前景文字变成白色像素值255背景变成黑色像素值0或者反过来。关键是阈值怎么取。如果图片光照均匀直接用全局阈值就行比如cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV cv2.THRESH_OTSU)。这里的THRESH_OTSU是让算法自动根据灰度直方图计算最佳阈值比手动指定127这种拍脑袋值靠谱得多。我建议这里用THRESH_BINARY_INV也就是前景为白、背景为黑。原因是后续做投影时统计的是白色前景像素的分布这样更直观。如果使用THRESH_BINARY前景黑、背景白那投影统计的就是黑色像素逻辑上也能做但OpenCV的很多轮廓检测和连通域函数默认按“前景为白”来理解统一用INV会省去很多调参烦恼。第三步是去噪。二值化之后图片上经常会有一些孤立的噪声点这些点会在投影曲线上产生毛刺影响谷底判断。常用的手段是中值滤波cv2.medianBlur(binary, 3)或者用形态学开运算cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)去掉小的白点。建议先做开运算再做一次闭运算这样既能去噪又能把笔画内部的细小裂缝补上。我的处理顺序是灰度化 → Otsu二值化INV模式 → 中值滤波 → 开运算 → 闭运算。这五步做完图片已经非常干净了。4.3 水平投影切行下面进入正题先切行。水平投影的代码很直接import cv2 import numpy as np # 假设 binary 已经是预处理后的二值图前景为白色 h, w binary.shape horiz_proj np.sum(binary, axis1) / 255 # 每行的白色像素数量 # 把投影值小于阈值的行标记为目标行间距 threshold int(w * 0.01) # 阈值取图片宽度的1%可根据实际情况调整 rows_with_text horiz_proj threshold # 找到文字行的起始和结束位置 line_ranges [] in_line False for i in range(h): if rows_with_text[i] and not in_line: start i in_line True elif not rows_with_text[i] and in_line: end i line_ranges.append((start, end)) in_line False if in_line: line_ranges.append((start, h - 1))这里的核心逻辑是统计每一行的白色像素总数如果某一行有大量白色像素说明这行属于文字区域如果一行几乎没有白色像素说明这行是行间距空白带。把连续的文字行合并成一个区间就得到每一行的上下边界。实际操作中threshold的取值很关键。图片宽度越大即使一行里只有一点点噪声投影值也会被放大。所以阈值用图片宽度的百分比来定比如1%或者2%比固定写死一个数字更合理。4.4 垂直投影切字拿到每一行的上下边界后对每一行区域做垂直投影再按同样的逻辑切出字符边界。def split_chars(line_img): 对一行文字图片做垂直投影切分返回每个字符的左右边界列表 h, w line_img.shape vert_proj np.sum(line_img, axis0) / 255 threshold int(h * 0.02) # 垂直投影阈值取行高的2% cols_with_text vert_proj threshold char_ranges [] in_char False for i in range(w): if cols_with_text[i] and not in_char: start i in_char True elif not cols_with_text[i] and in_char: end i # 过滤掉太窄的“字符”大概率是噪声 if end - start 5: char_ranges.append((start, end)) in_char False if in_char: if w - 1 - start 5: char_ranges.append((start, w - 1)) return char_ranges切完之后把每个左右边界对应的区域抠出来统一缩放到固定大小比如32x32就可以作为单字符识别的输入了。这一步很容易踩坑的是中文标点符号逗号、句号、引号的投影宽度很窄间隙又大容易被误判成噪声被过滤掉而左右结构的汉字内部间隙又可能小到被合并成一个字符。所以end - start 5这种过滤条件要根据实际图片调整不能照搬。我的建议是先不设最小宽度把所有候选段都输出到一张调试图上眼睛扫一遍再决定怎么过滤。4.5 处理粘连字符滴水算法与形态学分割上面讲的方法对字间距清晰的印刷体文字效果很好但一旦遇到字符粘连也就是两个字的笔画连在一起垂直投影的谷底会变得不明显甚至消失直接切分就会把两个字符当成一个。处理粘连的思路主要有几种。第一种最简单是用形态学腐蚀操作把粘连处“腐蚀”断然后再做连通域或投影分析。腐蚀核的大小要控制好太大会把正常笔画的细节也腐蚀掉。第二种是用所谓“滴水算法”Drop Fall Algorithm。这个算法模拟一滴水从字符顶部往下滴遇到笔画时就沿着笔画的边缘往下滑根据重力和局部形状决定往左还是往右从而绕开笔画从两个字符之间最薄弱的“瓶颈”处穿过。实现起来比较繁琐需要对每个可能的落点做局部邻域分析但对付轻中度粘连效果确实比简单腐蚀好。第三种是更现代的思路直接把粘连的图片喂给深度模型不做分割。比如用CRNN整行识别或者训练一个检测模型来定位每个字符。这其实又回到了第三条路线——与其费力缝合图像处理的分割漏洞不如换一个根本不依赖分割的模型架构。如果你只是临时处理少量粘连图片我的建议是先试形态学腐蚀把粘连处断开。腐蚀完了跑一遍连通域看看能不能把字符分开。如果不行再考虑滴水算法或直接上CRNN。不要一上来就写复杂算法先用最简单的方案解决问题复杂方案留给真正搞不定的样本。4.6 倾斜校正为什么要先转正再分割如果图片是倾斜的直接做投影投影曲线会变得很“钝”波峰和波谷之间的对比度大幅下降边界很难找准。倾斜校正的经典方法是用cv2.minAreaRect找文字连通域的最小外接矩形得到旋转角度再通过仿射变换把图片转正。对于一行文字来说找出所有前景像素点做最小外接矩形矩形的角度就是文字的倾斜角度。# 找出所有前景像素点坐标 coords np.column_stack(np.where(binary 0)) # 计算最小外接矩形 rect cv2.minAreaRect(coords) angle rect[-1] # 根据角度构造旋转矩阵校正图像 if angle -45: angle -(90 angle) else: angle -angle M cv2.getRotationMatrix2D((w / 2, h / 2), angle, 1.0) rotated cv2.warpAffine(binary, M, (w, h), flagscv2.INTER_CUBIC, borderValue(0, 0, 0))注意cv2.minAreaRect返回的角度定义比较绕正负号容易搞反。我的经验是拿到角度后先打印出来看一眼旋转后的效果如果方向反了就把角度取负再转一次。这个角度问题没有捷径就是要多试。倾斜校正做一次就够了没有必要重复校正。如果校完之后文字还是歪的多半是原图存在透视变形比如手机拍文档时的近大远小那种情况需要用透视变换来处理普通旋转解决不了。5. 常见问题与排查技巧实录5.1 投影曲线毛刺多找不到清晰谷底这是最高频的问题。通常有三个原因图片没去噪、二值化阈值不合适、字符本身笔画断裂。排查思路是先把中间过程的图片可视化出来看看二值化之后文字是否完整、背景是否有噪点。如果背景有噪点先把形态学开运算的核调大一点。如果文字笔画细碎先做闭运算把裂缝补上。中文笔画多尤其是字体比较细的宋体、仿宋这一步很重要。如果投影曲线还是毛刺很多可以对投影向量做一次高斯平滑比如用cv2.GaussianBlur处理形状为(1, n)的投影向量再用平滑后的结果找谷底。记住一个原则能通过预处理解决的问题不要靠算法硬扛。5.2 左右结构的汉字被错误切开这是中文OCR分割里最典型的翻车现场。比如“明”字左边“日”和右边“月”之间有一条明显的竖直空隙垂直投影在这里会产生一个低谷如果不加判断就会被当成字符边界切开。我的解决办法是加一个“最小字符宽度”约束。正常人写在图片上的汉字宽度一般不会小于行高的三分之一。如果一个候选字符的宽度小于行高的0.4倍就认为它可能是某个汉字的一半需要和左右相邻的块合并。还有一个更稳的方法在初步分割完成后把所有候选块按宽度从小到大排序把宽度异常小的块和相邻块做合并尝试合并后的结果再用分类器或者规则判断是否符合汉字的长宽比常见汉字宽高比约在0.7到1.2之间。这个后处理逻辑能救回很多被错误切开的左右结构汉字。5.3 字符之间粘连严重投影分割直接失效如果是印刷体汉字字间距一般比较明显出现严重粘连的情况不多。真正容易粘连的是手写体或者低分辨率图片中两个相邻字符被放大后笔画糊在一起。对这种情况我先试形态学腐蚀核大小从3x3开始逐级增加每试一次就做一次投影分割看效果。如果腐蚀到文字本身都变形了还没分开就换滴水算法。如果滴水算法也不理想那就别再和分割死磕了直接用CRNN整行识别或者用检测模型找单字位置。说句实在话对于粘连严重的场景传统分割方法能做到八十分已经不错了真正能解决问题的是换模型架构。懂得及时止损是一个工程师成熟的标志。5.4 标点符号和窄字符被误过滤句号、逗号、引号这些中文标点宽度小在投影图上对应的低谷不明显很容易被误判为噪声过滤掉。如果后续识别模型本身能处理标点但输入里被过滤了结果就会永远缺标点。我的做法是过滤噪声时不要用绝对宽度作为唯一标准而是和同行的平均字符宽度做比较。如果一个块的宽度小于平均宽度的0.3倍再判断它的“形态”是否像标点。比如句号通常是实心小方块或小圆圈密度很高逗号则是一个小而密的块。这些可以通过块内前景像素密度来区分。密度高、宽度小、高度和正常字符接近的块大概率是标点应该保留。5.5 一个有效的调试方法中间结果可视化分割是一个过程性的操作只看最终结果很难定位问题。我的习惯是把中间的每一步都输出成图片原始图、灰度图、二值图、去噪图、水平投影曲线、垂直投影曲线、切分线标注图、最终字符图。把这些图拼在一起一眼就能看出问题出在预处理还是分割。这里用matplotlib画出投影曲线可以这样做import matplotlib.pyplot as plt plt.figure(figsize(12, 4)) plt.plot(horiz_proj, colorb) plt.title(Horizontal Projection) plt.xlabel(row index) plt.ylabel(white pixel count) plt.show()看投影曲线找谷底比自己脑补分割位置直观得多。这招对新手尤其管用可以帮你快速建立“图像像素分布”和“字符边界”之间的直觉。6. 开源中文OCR项目里字符分割与识别的配合方式6.1 CRNN框架下还有没有分割很多初学者会问一个问题既然CRNN不需要显式分割为什么还要学习字符分割答案很简单你不一定总是用CRNN。在很多轻量级的场景里OCR引擎跑在嵌入式设备上算力有限整行识别模型不一定跑得动而提前切好字再喂给一个小型分类模型反而更高效。另外处理表格、公式、票据这类结构复杂的内容时字符级的位置信息本身就有用——比如要记录“这句话里第几个字是什么”显式分割能直接给你答案。还有一点用CRNN训练模型时虽然模型不需要你提供字符位置标注但如果你有一个强力的传统分割器可以自动生成大量“单字符图片-标签”对用来做数据增强或者预训练一个分类器这在实际工程里是个很划算的方案。6.2 数据增强在中文OCR中的关键作用无论你最后走哪条路线数据增强都是中文OCR绕不开的环节。中文的量级很大常用汉字就有三千多个生僻字更是不计其数靠人工标注覆盖全部场景不现实。一个比较实用的增强策略是用字体渲染工具比如PIL、FontForge把不同字体、不同字号、不同颜色的中文字渲染成图片再叠加噪声、模糊、透视变换、旋转模拟真实场景中的各种退化。具体来说可以这样增强随机字体宋体、黑体、楷体、仿宋、微软雅黑能多准备几种就多准备几种。随机背景纯色、渐变、网格纸、带水印的底图。随机干扰高斯噪声、椒盐噪声、运动模糊、局部遮挡。几何变化小角度旋转、水平/垂直拉伸、透视扭曲。有了丰富的数据增强CRNN模型才能在真实业务场景里站得住。这个环节的重要性不亚于模型结构本身。6.3 开源工具链怎么选目前开源中文OCR工具链里PaddleOCR是做完整的检测识别流程比较成熟的方案内部识别模块用的就是基于CRNN的改进结构。它对中文字符的支持、部署、预训练模型的丰富程度都很不错。如果你想快速验证CRNNCTC在中文上的效果PaddleOCR是上手最快的一条路。如果不想依赖庞大的框架只想自己训练一个CRNN模型可以选择百度的PaddleOCR提取核心代码或者基于PyTorch从零搭一个简化版CRNN。从零搭的好处是你能把CTC的细节彻底搞明白坏处是训练时间和调参成本比较高不适合只想解决业务问题的人。7. 实操心得分享我做中文OCR有一段时间了最大的感受是字符分割这件事传统图像处理方法的下限很低上限也不算高但它在整个OCR技术栈中承担的角色极其重要。即使你现在用的是CRNN这类无分割方案理解分割的原理也会让你在处理复杂图片时更有底气——你会知道为什么某些图识别不好是字符贴得太紧了还是笔画太细断了或者是倾斜角度超出模型耐受范围了。分享一个我最近在用的策略对于一个新场景先跑传统分割流程把中间结果全部可视化快速判断图片质量和文字形态如果传统分割能做到八九成的准确率说明这个场景的图片质量不错可以放心用轻量级方案如果传统分割乱七八糟说明图片本身很复杂直接上深度学习方案更稳妥。这个方法帮我避免了很多无效尝试。最后再留一个小建议做中文OCR不要只盯着模型和算法数据质量永远是最值得投入的方向。与其花大量时间调分割参数不如花点心思把钱花在数据收集和数据清洗上。中文OCR的难点从来不在某一个单点而在从图像到文字的完整链路里每一个环节都做到足够鲁棒最终的准确率才能让人满意。