ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MATLAB汉字识别实战:从图像预处理到特征分类的完整流程解析

MATLAB汉字识别实战:从图像预处理到特征分类的完整流程解析 简介本资源是一套基于MATLAB实现的汉字图像识别完整程序面向数字图像处理课程学习者、本科生课程论文实践及初学者算法验证需求聚焦于手写或印刷体汉字的预处理、特征提取与贝叶斯分类识别全流程。压缩包共124个文件含69张PNG与38张JPG格式的汉字样本图像构成训练/测试字库13个核心MATLAB源码文件如create_database.m、tryy.m等实现数据库构建与分类器调用以及辅助脚本和中间数据文件整体仅403KB轻量易部署。已有18245人学习下载反映其在教学实践中的广泛参考价值。用户可直接复现贝叶斯分类器在汉字识别任务中的应用获得从字库生成、单字切分、灰度归一化到概率判别的一整套可运行代码并通过ASV备份文件了解关键参数调试痕迹具备清晰的工程模块划分与典型图像处理链路示范作用。1. 项目整体设计与思路拆解1.1 汉字识别到底在解决什么问题先说结论这个课题是数字图像处理课程里最经典的综合性大作业之一我也带过几届学生做类似题目。表面上看任务是把一张包含汉字的图片输入到 MATLAB 里程序自动告诉你这些字是什么但拆开来看它其实横跨了数字图像处理最核心的几个环节图像预处理、字符分割、特征提取、模式分类。每一个环节单独拉出来都能写一篇论文串起来就是一个完整的 OCR光学字符识别雏形。我见过不少同学拿到这个题就直接搜“MATLAB 汉字识别源码”下下来一堆 .rar 却发现跑不通或者跑通了但换个图片就识别得乱七八糟。原因很简单汉字识别不是一个“调个函数就能搞定”的问题它的难点在于汉字本身的结构复杂性。汉字类别极多常用字就有三千多个而且存在大量字形高度相似的字比如“未”和“末”、“日”和“曰”、“已”和“己”像素级差别很小。再加上图片拍摄角度、光照、噪声、字体变化等因素识别难度就上去了。那这个项目适合谁我个人觉得它特别适合三类人一是数字图像处理课程的本科生需要一个能交作业且能讲清楚原理的完整项目二是准备做毕业设计、想从代码里体会图像处理全流程的同学三是对 OCR 感兴趣、想用 MATLAB 快速验证算法思路的入门研究者。这篇文章里我会把从图像读入到最后输出识别结果的完整流程拆开讲包括每一段关键代码、参数怎么选、为什么这么选以及我实际踩过的坑。1.2 技术路线为什么这么选围绕“数字图像处理”“MATLAB”“图像中汉字识别”这几个关键词市面上的实现方案大概分三类第一类纯模板匹配。把待识别字符和字库里的模板图逐像素比对相似度最高的就是结果。优点是实现简单、跑得快缺点是对字体、大小、位置极其敏感换一个字体基本就废了。它适合识别印刷体、字体固定的场景比如车牌字符识别、验证码识别里偶尔还这么干。第二类特征提取加分类器。从字符图像里提取特征向量比如网格特征、投影特征、笔画密度再用最近邻、BP 神经网络、SVM 等分类器做判别。这是目前课程项目和论文里最主流的路线因为特征一旦提取好分类器的选择就非常灵活而且对字体变化的鲁棒性比纯模板匹配好得多。本文采用的核心方案就是这一类。第三类深度学习方法。用卷积神经网络直接端到端识别。识别率确实高但问题是 MATLAB 跑深度学习需要额外的 Deep Learning Toolbox而且训练数据需求量大、训练时间长对课程大作业来说属于“杀鸡用牛刀”。除非你后续要做课题研究否则我不建议在这个项目里一上来就上 CNN。至于为什么选 MATLAB 而不选 Python不是情怀问题是场景问题。MATLAB 自带的图像处理工具箱函数太全了rgb2gray、graythresh、bwlabel、regionprops 这些函数可以直接调用矩阵运算天然适合图像数据调试时变量可视化也方便。对课程作业来说用 MATLAB 能在最短时间内验证完整流程把精力放在算法理解上而不是花大量时间处理环境依赖。当然代码写多了你会觉得 MATLAB 循环慢、语法繁琐但那是后话不影响它作为教学和快速原型工具的价值。1.3 完整的识别流程框架整个项目的核心流程可以概括为六个步骤图像读入与显示imread 读图把彩色图或灰度图统一转成灰度图。图像预处理灰度化、去噪、二值化、倾斜校正、字符归一化。预处理的质量直接决定后续分割和识别的上限。字符分割把图片中的每一行、每一个汉字单独切出来。这一步是汉字识别和字母数字识别差异最大的地方汉字是方块字排版上横排、竖排都有需要针对性地做投影分析。特征提取对每个字符子图计算一组能代表字形特征的数值向量。训练分类器或建立模板库用一批已知字符的样本提取特征存成模板库。识别与评估对待识别字符提取同类型特征用分类器判别输出汉字结果并统计识别准确率。我在带学生做这个项目时一直强调一句话流程框架是通用的但每一步的参数都要根据你实际图片的情况去调。不要指望拿一套代码通吃所有图片这也是为什么网上很多现成源码“换个图就翻车”的根本原因。2. 图像预处理细节与实操要点2.1 灰度化、二值化、去噪的选型思路图像预处理是整个识别流程里最枯燥但最致命的一步。我见过很多同学在这个阶段图省事直接一句I imread(test.png); bw imbinarize(I);就完事了结果后面分割一塌糊涂。这里必须把每一步的原理和参数选择讲清楚。先说灰度化。如果输入是彩色图先用rgb2gray转换。它内部用的是加权平均法公式是Y 0.299 × R 0.587 × G 0.114 × B为什么不是简单平均因为人眼对绿色最敏感、对蓝色最不敏感加权平均出来的灰度图更符合视觉感知也能让后续二值化时目标与背景的对比度更稳定。这一段代码非常简单但要注意一点如果你的图片是带透明通道的 PNG 或者索引图rgb2gray可能报错需要先im2gray或者ind2gray这也是我踩过的坑后面问题排查部分会细说。然后是去噪。汉字识别场景里常见噪声一般是椒盐噪声和高斯噪声。对椒盐噪声中值滤波是最好的选择它能在去噪的同时保留边缘细节。对高斯噪声可以用高斯滤波imgaussfilt但要注意高斯滤波会让边缘变模糊对后续字符分割反而不利。我的经验是如果图片本身比较干净宁可跳过滤波步骤也不要乱滤滤波引入的模糊有时比噪声更麻烦。只有在有明显噪点时才用medfilt2(I, [3 3])这样的中值滤波窗口不要太大3×3 就够了太大会把笔画细节一起抹掉。接下来是最关键的二值化。二值化的目标是把灰度图变成黑白两色让字符像素和目标背景彻底分开。最常用的方法是 Otsu 全局阈值法MATLAB 里就是graythreshimbinarizeI_gray rgb2gray(I); level graythresh(I_gray); % Otsu 自动计算阈值范围 [0,1] bw imbinarize(I_gray, level);Otsu 的原理是最大化类间方差简单说就是让前景和背景两类的像素灰度差异最大从而找到最优分割阈值。它适合目标和背景灰度分布比较均匀的情况。但如果你拍的图片有阴影、光照从一侧照过来导致亮度不均匀全局阈值就会失效——图像一边白一边黑Otsu 选出来的阈值只能照顾到一部分区域。这时候就需要局部自适应阈值MATLAB 里可以用imbinarize(I_gray, adaptive)它会根据每个像素邻域的灰度分布动态计算阈值对光照不均的图片效果明显更好。我的建议是先上 Otsu看看二值化结果是不是你想要的。如果字符残缺或者背景有大量黑色噪点再换 adaptive 或者加形态学处理。不要一上来就搞复杂方案简单方案能满足需求时复杂方案只会增加调试成本。还有一个容易被忽视的问题imbinarize二值化后字符是白色1还是黑色0取决于图片本身的明暗关系。有的图片是黑字白底Otsu 之后黑字变 0、白底变 1有的图片是白字黑底情况刚好相反。MATLAB 的很多区域处理函数默认前景是白色所以通常我会加一步把字符统一转成白色前景if mean(bw(:)) 0.5 bw ~bw; % 背景占多数时反转 end这就是一个非常实用的细节不处理的话后面连通域分析会全是噪点区域char 分割会炸。2.2 字符分割投影法与连通域分析字符分割是整个项目里最体现“工程能力”的环节。汉字是方块字排版相对规整所以最经典的方法是投影法。所谓投影就是把二值图像分别在水平方向和垂直方向上累加像素值得到一行和一列的“投影曲线”。文字的每一行、每一列会在投影曲线上形成明显的峰和谷找到谷底就是字符之间的空隙。水平投影用来切行。假设bw是二值图前景为白色horiz_proj sum(bw, 2); % 每一行像素和得到一个列向量这个列向量里有字符的区域数值大行间距区域数值接近 0。遍历这个向量从非零跳到零的位置就是行结束从零跳到非零的位置就是行开始把所有行切出来就完成了分行。垂直投影用来切每个字。对每一行子图再做列方向投影vert_proj sum(row_bw, 1); % 每一列像素和同理找出每一列的起止位置就能把每个汉字单独切出来。投影法的优点是直观、快、好解释缺点是怕倾斜和粘连。图片稍微倾斜投影谷底的数值就不是 0 了行与行之间会粘连在一起分割就会出错。解决倾斜有两个思路一是预处理阶段做倾斜校正传统方法用 Radon 变换或者 Hough 变换检测文本行的角度然后旋转校正二是分割阶段用连通域分析替代纯投影。连通域分析用bwlabel给每个连通的白色像素区域编号再用regionprops提取每个区域的包围盒BoundingBox。对于没有粘连、笔画完整的字符连通域分析可以直接把每个字独立框出来比投影法更鲁棒。但问题是如果一个汉字里左右两部分离得比较远——比如“林”“好”这类左右结构的字——有可能被检测成两个连通域。这时可以用一个简单的策略统计所有字符连通域的平均宽度把宽度明显小于平均宽度一半、且和水平相邻区域中心距离很近的连通域合并。我实际做项目时通常把投影法和连通域分析结合使用先用水平投影切行再在每行里用连通域分析切字最后用平均宽度做粘连合并。代码大致是这样cc bwconncomp(row_bw); stats regionprops(cc, BoundingBox); boxes cat(1, stats.BoundingBox); % boxes 每一行是 [x, y, width, height]这套组合在绝大多数规整的印刷体图片上都能稳定工作比单靠一种方法靠谱得多。2.3 字符归一化为什么必须统一尺寸分割出来的字符大小肯定不统一有的字大有的字小有的高有的矮直接提取特征会受尺寸干扰。所以归一化是必须的。两个层面的归一化一是位置归一化把字符的重心移到图像中心。汉字是方块字重心偏离会影响后续特征提取的一致性。用regionprops的Centroid可以拿到重心坐标然后做个平移即可但简单场景下这步可以省略。二是尺寸归一化把字符统一缩放到固定尺寸常见的是 32×32 或 64×64。MATLAB 里直接imresize就可以resized imresize(char_img, [32 32], bilinear);这里有个细节插值方法选 bilinear双线性就够用不要用 nearest最近邻否则缩放后锯齿严重也没有必要用 bicubic双三次计算量大而且对二值图来说效果提升不明显。尺寸选多大我个人经验是 32×32 足够应付大多数课程项目。太小会丢失笔画细节太大特征维度高、计算慢。如果后面要提取 8×8 的网格特征32×32 的字符图可以很自然地划分成 64 个小网格每个网格大小是 4×4 像素数学上非常顺。3. 特征提取与分类器实战3.1 特征工程网格特征与投影特征组合特征提取是整个汉字识别项目的灵魂很多人做完预处理就直接进入匹配发现识别率上不去问题往往出在特征描述能力不够。最经典的特征是粗网格特征。以 32×32 的归一化字符图为例把它划分成 8×8 的网格每个网格统计白色像素占该网格总像素的比例得到一个 64 维的特征向量。这个特征描述的是汉字的大致笔画分布优点是计算简单、对笔画细节的微小偏移不敏感缺点是区分相似字形时能力有限。为了提升区分度我会把投影特征也加进去。把二值字符图分别在水平方向和垂直方向做像素累加再对这两个累加序列做归一化各得到 32 维特征。合并后总特征维度是 64 32 32 128 维。很多论文还会加对角线投影、外围轮廓特征、笔画密度特征但对课程项目来说网格特征加双向投影已经能取得不错的效果特征再多反而容易过拟合有限样本。特征提取的完整代码如下function feat extractFeature(char_img, grid_row, grid_col) % 输入二值字符图已归一化到 32x32 % 输出特征向量 img imresize(char_img, [32 32], bilinear); img double(img); % 网格特征 r 32 / grid_row; c 32 / grid_col; grid_feat zeros(1, grid_row * grid_col); idx 1; for i 1:grid_row for j 1:grid_col block img((i-1)*r1:i*r, (j-1)*c1:j*c); grid_feat(idx) sum(block(:)) / numel(block); idx idx 1; end end % 水平投影 horz sum(img, 2) / max(sum(img, 2)); % 垂直投影 vert sum(img, 1) / max(sum(img, 1)); feat [grid_feat, horz, vert]; end注意最后投影特征除了一个最大值做归一化为了让特征值落在 0 到 1 之间避免数据范围和网格特征差异太大影响后续距离度量。3.2 分类器怎么选模板匹配、最近邻、BP 网络对比特征提取完成后接下来的问题是怎么判断“这个特征向量属于哪个汉字”。我按从易到难介绍三种方案你可以根据自己对课程要求的理解来选。第一种模板匹配。对模板库里的每个汉字样本提取特征向量保存成矩阵。识别时把待识别字符的特征向量和模板库里每个特征向量算欧氏距离距离最小的那个就是识别结果。欧氏距离公式d sqrt(sum((x - y).^2))这里 x 是待识别特征y 是模板特征。MATLAB 里pdist2一行就能算整个距离矩阵。这个方案实现最简单适合模板库小的场景。缺点是如果某个汉字有多个样本多个模板之间的差异会被平均掉导致对字体变化敏感。第二种K 近邻KNN。相当于模板匹配的升级版模板库里每个类存多个样本识别时找最近 K 个样本投票决定类别。K 一般取 3 或 5。优点是对少量噪声和形变鲁棒性好缺点是识别时需要和所有样本算距离样本多了会比较慢。但对几百个模板的场景完全够用代码复杂度也很低。第三种BP 神经网络。用 feedforwardnet 建立多层感知机特征向量作为输入汉字类别编号作为输出。训练过程需要大量样本而且网络结构、学习率等超参数需要调对课程作业来说有点重。但它有个实打实的优势如果老师要求你“体现模式识别的现代方法”BP 网络是能说明白的亮点。MATLAB 里实现很简单net feedforwardnet([20 20]); net train(net, feat_matrix, target_matrix); output net(test_feat);注意feedforwardnet的输入矩阵是“特征维度 × 样本数”的布局所以训练数据要转置。这个布局问题我见很多人踩过一train就报维度错误其实就是转置没做。我个人的推荐是课程作业首选 KNN 或模板匹配理由是小样本下它们足够稳定、可解释性强答辩时你能清楚说出“为什么这个字被识别成另一个字”。如果数据量充足比如每个字有 20 个以上样本再上 BP 网络效果会有明显提升。3.3 相似汉字的特殊处理项目做到最后你会发现绝大多数识别错误都集中在相似字上。比如“日”和“目”、“土”和“士”、“大”和“太”。这些字网格特征和投影特征非常接近欧氏距离很小分类器很容易混淆。针对这个问题我的经验是在特征层面做补救。一个有效的方法是增加局部精细特征在字符的某些关键区域单独提取特征比如把“日”和“目”的上部区域单独切出来比较因为它们主要差在内部横画数量上。具体到代码就是在上面的extractFeature函数里除了全图网格特征再对字符图的上半部分、中间部分各提取一次网格特征把局部特征拼到全局特征后面。维度会变高但有区分度。如果加了特征还是分不清那就只能是模板库的样本问题。检查一下模板库里“日”和“目”的样本是不是本身就写得不清晰或者是分割切割时边缘把内部横画切掉了。很多时候相似字误识别根源不在这两个字本身而在前面分割步骤把笔画切残缺了。所以一旦发现识别错误集中在这几个字上我建议先回头验证该字符的分割包围盒完整不完整而不是急着换分类器。4. 完整 MATLAB 程序执行流程4.1 主程序结构设计整个项目的主程序我建议按“模块化 可配置”的方式来组织。不要把所有代码堆在一个脚本里否则后面调参和排查会非常痛苦。我的目录结构通常是ChineseOCR/ ├── data/ │ ├── template/ % 训练样本图 │ └── test/ % 测试样本图 ├── lib/ │ ├── preprocess.m % 预处理函数 │ ├── segmentChar.m % 字符分割函数 │ ├── extractFeature.m% 特征提取函数 │ └── buildTemplate.m % 构建模板库 ├── main.m % 主程序 └── recognize.m % 单张图片识别函数main.m的主要流程是先调用buildTemplate构建模板库然后读入测试图片依次调用预处理、分割、特征提取、分类识别最后显示识别结果。recognize.m单独封装“一张图片 - 一串汉字”的流程方便之后对批量图片做测试。4.2 构建模板库的细节模板库是识别的基础构建时最关键的是监督信息要准确。我的做法是将模板库组织成“一个子文件夹对应一个汉字”文件夹名就是汉字里面放多张该字的不同样本图。这样构建模板库时可以自动读取文件夹名作为标签不会因为手动维护标签顺序而出错。buildTemplate.m的核心逻辑function [templates, labels] buildTemplate(template_dir) folders dir(template_dir); folders folders([folders.isdir] ~startsWith({folders.name}, .)); templates []; labels {}; for k 1:length(folders) label folders(k).name; % 文件夹名即汉字 files dir(fullfile(folder, folder_path, *.png)); for f 1:length(files) img imread(fullfile(folder, folder_path, files(f).name)); img preprocess(img); % 预处理到二值图 img imresize(img, [32 32]); % 归一化 feat extractFeature(img, 8, 8); templates [templates; feat]; labels{end1} label; end end end文件夹名直接用汉字的好处是识别结果可以直接用标签 Index 索引到真实汉字不需要额外维护编码表这对展示非常方便。4.3 单张图片端到端识别代码下面给出一段完整的单张图片识别调用代码注意这是实际可运行的主流程前提是已经跑通了上面的模板库构建。% recognize.m function text recognize(img_path) % 读取并预处理 I imread(img_path); bw preprocess(I); % 二值图字符为白色(1) % 水平投影切行 horz_proj sum(bw, 2); rows extractLines(horz_proj); % 得到 [startRow, endRow] 矩阵 % 逐行切字并识别 text ; for i 1:size(rows, 1) row_bw bw(rows(i,1):rows(i,2), :); [char_imgs, char_boxes] segmentChar(row_bw); for j 1:length(char_imgs) feat extractFeature(char_imgs{j}, 8, 8); label classifyKNN(feat, templates, labels); % KNN 分类 text [text, label]; end text [text, newline]; % 行间换行 end % 显示结果 figure; imshow(I); title(strrep(text, newline, )); end这里的extractLines和segmentChar需要单独实现我在第三节已经讲了原理这里就不重复贴代码了。需要提醒的是extractLines里判断“行空行”的阈值不要设成 0我习惯取投影最大值的 5% 作为阈值否则抗噪声能力太差。4.4 KNN 分类器的最小实现不依赖任何工具箱手写一个简单 KNN 也很容易我这里贴一个精简但能用的版本function label classifyKNN(feat, templates, labels, K) if nargin 4 K 3; end d sqrt(sum((templates - feat).^2, 2)); [~, idx] sort(d); neighbors labels(idx(1:K)); label mode(neighbors); % 取投票最多的标签 end对课程作业来说这个实现已经足够了。如果你想在作业里体现一点技术含量可以改成距离加权投票每个样本权重取 1 / (d eps)然后按权重累计投票这样距离近的样本对结果影响更大识别稳定性会好一点。5. 常见问题与排查技巧实录5.1 问题速查表我在带项目过程中发现大家遇到的高频问题高度集中整理成一张速查表方便你按图索骥现象可能原因解决方案二值化后字符变成黑色、背景白色前景/背景明暗关系判断反了统计黑白像素占比超过一半则取反分割出的字符框明显偏移只框住半个字噪声或笔画断裂导致连通域破碎先做形态学闭运算imclose(bw, strel(square, 3))行的投影曲线上有毛刺行切分不准图片有轻微倾斜或扫描噪点水平投影前先做倾斜校正或调大阈值识别结果中“日”“目”频繁互相误判特征区分度不足增加局部精细网格特征换一张图片完整识别率骤降预处理参数是针对旧图调的过拟合了单张图片用多张图片验证预处理效果参数取鲁棒值trainBP 网络时报维度错误特征矩阵的维度布局错了把样本矩阵转置成特征维度 × 样本数rp分割后出现大量面积 1~2 像素的小区域没有去噪或二值化阈值不理想先用bwareaopen(bw, 30)删除小面积噪点区域5.2 独家避坑经验预处理参数要可视化验证我反复跟学生强调一件事预处理阶段不能只盯着最终的识别率调参而是要每一步都用imshow把中间结果打出来看。二值化之后立刻imshow(bw)肉眼看字符有没有粘连、有没有断笔分割完之后把每个char_imgs用 subplot 拼起来显示看每一张是不是正好一个完整的汉字。很多时候你以为是分类器的锅其实早在前面的分割步骤就已经错得离谱了。只要中间结果是对的最终识别率通常会比较稳定。这是一条可以节省你五小时以上的经验。另外一个容易翻车的点是文件格式。很多课程作业给的测试图是.jpg但 JPG 是有损压缩格式在字体边缘会产生压缩伪影直接二值化后字符边缘会出现很多毛刺。如果条件允许测试图尽量用 PNG 或 BMP。如果只能用 JPG那预处理时记得加一步中值滤波。同样模板库的样本图一定要保证质量一张模糊的模板图会让整个类别都识别不对。5.3 识别率上不去的排查思路当你的识别率卡在一个瓶颈比如 60% 到 70%不要急着调分类器我建议按照下面这个顺序排查第一检查分割结果。把整张图识别时所有字符框画出来肉眼数一数和真实字符数是否一致。如果字符框数量都不对那一定是分割出了问题分类器再强也没用。这一步能解决约一半的识别率问题。第二检查特征可视化。把每个字符提取出的网格特征用imagesc(reshape(feat(1:64), 8, 8))画出来看看特征热力图是否大致符合字形结构。如果特征图完全看不出字的形状说明归一化或二值化没做好。第三检查模板库覆盖度。你的模板库里每个字准备了多少个样本如果只有 1 个样本那么任何和模板字体差异较大的测试字都会识别失败。我实际做的时候一般每个字至少准备 5 个不同风格的样本识别率会有一个明显跃升。第四检查分类器参数。KNN 里的 K 值、BP 网络的隐层节点数这些参数影响相对前三个因素要小但确实存在一个最优区间。K 太大会引入噪声样本的干扰K 太小对噪声敏感我建议从 K 3 开始尝试逐个比对识别率。5.4 扩展思路从识别到端到端项目做到能稳定识别规整图片后你还可以往几个方向扩展丰富作业或论文的亮点一是加入倾斜校正模块。用 Radon 变换检测文本行倾斜角度旋转校正后再走后面流程。这能让项目从“只能识别端正图片”升级为“能识别有一定倾斜的图片”实用性提升明显。二是加入批量评估脚本。准备一批带标签的测试图片让程序自动跑完并统计每个字的识别准确率最终输出混淆矩阵。这个对课程报告来说是非常硬核的支撑材料也能帮你快速定位是哪些字在混淆。三是对接摄像头实时识别。用 MATLAB 的webcam支持包配合 OCR 流程做成实时拍摄识别。这个扩展很强能把项目从“离线大作业”变成“可演示的成品系统”期末展示时效果拉满。我自己的经验是这个项目最坑的往往不是算法本身而是“你觉得图片看起来没问题但程序读到的是另一幅图像”。比如有的截图工具保存的图片默认带一个很窄的白色边框二值化后边框变成一个连通的白色矩形把所有的字符连通域都包进去了。用regionprops的时候就会只检测到一个大包围盒分割完全失败。遇到这种情况除了预处理时做imclearborder清除边缘连通域别无他法。这种问题不真正跑一遍光看文档根本想不到所以动手跑代码、打印中间结果永远是排错的第一法则。最后再分享一个小技巧如果你在调参过程中发现某一张图无论怎么调参数都识别不对先别死磕把它放到“疑难杂症”文件夹里继续做下一张。等整体流程稳定后再回头分析这些失败样本你往往一眼就能看出它们的共性问题——可能是图像对比度极低、可能是字体特别花哨。集中治理比逐个攻坚效率高得多。这也是我做图像处理项目这么多年养成的工作习惯希望能帮你少走一些弯路。本文还有配套的精品资源点击获取
返回列表