简介这份OpenCV数字识别基础项目面向具备C基础、希望入门计算机视觉与图像识别的开发者围绕印刷体数字识别串联图像读取、灰度化与二值化等预处理、模板匹配及OCR识别思路并涉及OpenCV跨平台接口与OCR字符识别的基本用法。压缩包共13个文件以10个jpg、2张png图像素材和1个cpp源码文件为主图像素材可用于对照观察处理前后效果源码承载图像加载、预处理与识别流程整体仅21KB轻量易取。项目已有357人学习适合作为计算机视觉入门的小型实践案例也便于按图像素材与源码对照复盘。读者可从中了解如何加载图像、执行灰度化与二值化等预处理、调用模板匹配或OCR识别函数并查看输出结果也能结合Linux运行环境与Windows兼容性说明排查路径、编译器和依赖问题为后续更复杂的图像处理任务打下基础。1. 先别急着写代码OpenCV 数字识别到底在做什么如果你刚听到 opencv 识别又想做电脑版数字识别先别被“识别”两个字吓住。你可以把它想成教电脑看一张写着数字的图片先把彩色图变成黑白图再把每个数字从背景里剪出来最后才判断它是 0 到 9 里的哪一个。它适合零基础练手因为输入简单、结果直观哪一步不对都能马上看见。你不需要先学高深数学先会装环境、会读图、会看黑白结果就能迈出第一步。这一篇就按这个顺序带你走。2. 为什么从数字识别入门先看懂“图像变矩阵矩阵变黑白”数字识别听起来像“人工智能”但入门阶段你不用一上来就碰模型。电脑看到的图片本质上是一堆数字排成的表格每个格子叫像素。彩色图通常有蓝、绿、红三个通道灰度图只有一个通道二值图更简单只有黑和白两种值。OpenCV 做的就是帮你读图、改像素、找轮廓、缩放尺寸这些事情。你先把这些基础动作跑顺后面再学模板匹配或简单分类器就不会觉得是在看黑匣子。2.1 为什么数字识别适合零基础输入小、反馈快、错误看得见很多新手一上来就想做“识别整张照片里的所有文字”结果被光照、角度、背景、字体搞得晕头转向。数字识别更适合入门因为目标范围小通常只关心 0 到 9 这十个类别。你可以先拿一张白底黑字的数字图练手读进来、转灰度、二值化、找轮廓每一步都有中间结果可以保存下来看。哪一步黑了、白了、裁歪了打开图片就能发现不用靠猜。我第一次学的时候最大的误区是以为“识别”就是一个函数喂图片进去就出答案。后来才发现真正花时间的是前面的准备工作图片清不清楚、数字有没有连在一起、背景有没有噪点、每个数字大小是否一致。把这些基础问题处理顺后面的识别反而没那么玄学。你先把“看清”做好再谈“认字”学习压力会小很多。数字识别还有一个好处练习成本低。你不需要准备大量素材用 OpenCV 自己画一个数字就能开始。画出来的图虽然简单但足够让你理解读图、灰度、阈值、轮廓、裁剪这些动作。等你把单张图跑通再换成手写数字、印刷数字、截图数字慢慢增加难度。这个顺序比一上来追求高准确率更稳。2.2 先把流程拆成两段预处理负责“看清”识别负责“认字”入门阶段建议把流程硬拆成两段。第一段叫预处理目标是把原始图片变成干净的黑底白字小图。常见动作有读图、灰度化、二值化、去噪、找轮廓、裁剪、缩放到统一尺寸。第二段才叫识别目标是给每个小图一个 0 到 9 的标签。你可以先用模板匹配或简单分类器不必一开始就写复杂网络。为什么要拆开因为识别效果差时你需要知道问题出在哪。如果裁出来的小图本身缺笔画、歪半边、背景一堆白点再好的识别方法也救不回来。反过来如果小图干净、大小一致、数字居中哪怕用很朴素的方法也能得到可用的结果。新手最容易踩的坑就是把所有步骤揉成一团最后只看到一个错误答案不知道从哪查。你可以把预处理想成整理考卷先把每道题剪下来摆正擦掉多余墨迹再交给阅卷人。识别方法就是阅卷人。考卷没整理好换几个阅卷人也没用。先把整理动作练熟后面换方法才有意义。这个思路会贯穿后面的代码例子。2.3 第一个小目标把一张数字图当成 5×5 矩阵来观察先不急着识别我们做一个小实验用 0 和 255 画一个粗糙的“1”看看图片在程序里长什么样。下面这段代码需要 OpenCV 和 NumPy安装放到下一章现在先理解形状和像素值的含义装好环境后再回来跑一遍。import numpy as np import cv2 # 5x5 的小图0 表示黑255 表示白中间画一个粗糙的“1” tiny np.array([ [0, 0, 255, 0, 0], [0, 255, 255, 0, 0], [0, 0, 255, 0, 0], [0, 0, 255, 0, 0], [0, 255, 255, 255, 0], ], dtypenp.uint8) print(形状, tiny.shape) # (5, 5) print(第一行, tiny[0]) # 看第一行像素值 # 放大到 250x250最近邻插值让每个像素变成 50x50 的方块 big cv2.resize(tiny, (250, 250), interpolationcv2.INTER_NEAREST) cv2.imwrite(tiny_digit.png, big) print(保存完成tiny_digit.png)这段代码的逻辑很直白先造一个 5×5 的二维数组数组里的 0 代表黑色255 代表白色tiny.shape会输出(5, 5)表示高 5、宽 5、单通道cv2.resize把这张小图放大到 250×250interpolationcv2.INTER_NEAREST表示最近邻插值放大后每个原始像素会变成一个方块不会糊成一片cv2.imwrite把结果保存成图片。你打开tiny_digit.png会看到一个很粗糙的“1”这就是电脑眼里的数字图。参数上(250, 250)是目标宽度和高度OpenCV 的尺寸顺序是宽在前、高在后dtypenp.uint8表示像素值用 0 到 255 的整数保存这是图片最常见的格式。你不需要背这些先记住一件事图片在程序里就是数字表格改像素就是改表格里的值。后面做灰度化、二值化本质上也是在改这张表格。提示这个例子只帮你建立“图像是矩阵”的感觉还不是识别。你能把保存出来的图打开看一眼就已经完成第一个小目标了。3. 第一步怎么迈电脑版环境装好跑通一张数字图的二值化这一章开始动手。你要做的事情不复杂确认电脑上有 Python建一个英文目录安装 OpenCV 和 NumPy然后跑通“生成数字图、读图、灰度化、二值化、保存结果”这一条线。别小看这条线后面找轮廓、裁数字、做识别全都建立在它上面。第一次配置环境容易烦我建议你一次只做一件事每做完一步就验证一下不要一口气敲完所有命令再猜哪里错了。3.1 装环境前先做三件事确认 Python、建英文目录、准备终端第一件事确认 Python 能正常运行。在 Windows 的终端里输入python --version如果提示找不到命令可以试py --version在 macOS 或 Linux 的终端里常见写法是python3 --version。你能看到版本信息就说明 Python 已经在了。看不到也没关系去 Python 的常规安装流程里装一个稳定版本安装时留意把“加入环境变量”的选项勾上省得后面终端找不到命令。第二件事建一个专门练手的目录。路径尽量用英文和数字比如D:\opencv_digit\或~/opencv_digit/不要在路径里塞一堆中文空格和特殊符号。新手常见的翻车点不是代码写错而是图片路径里有中文、空格、反斜杠转义程序读不到图还以为是 OpenCV 坏了。目录建好后在里面再建一个data文件夹放图片后面代码会往这里写结果。第三件事打开终端并进入这个目录。Windows 可以用cd /d D:\opencv_digitmacOS 或 Linux 用cd ~/opencv_digit。你可以在终端里输入pwd或cd看一眼当前目录确认自己站在练习目录里。这个习惯很重要因为代码里的相对路径data/xxx.png是相对于终端当前目录找的。你站在别的地方运行图片就可能写到别处或者读不到。注意目录名和文件名先保持简单等流程跑通再换成自己的素材。入门阶段少一个变量就少一类排查问题。3.2 安装和验证三条命令确认 OpenCV 能正常导入进入练习目录后先升级一下包管理工具再安装 OpenCV 和 NumPy。下面的命令不写死版本号装当前稳定版即可如果你用的电脑里同时有多个 Python建议统一用python -m pip这种写法能减少“装到了另一个 Python 里”的麻烦。# 升级 pip减少旧版安装器带来的奇怪问题 python -m pip install --upgrade pip # 安装 OpenCV 的 Python 包和数值计算包 python -m pip install opencv-python numpy # 验证能否导入并打印 OpenCV 版本信息 python -c import cv2, numpy as np; print(opencv ok, cv2.__version__)这三条命令的逻辑是第一条更新安装器第二条安装opencv-python和numpy前者提供读图、灰度、二值化、找轮廓等函数后者负责数组运算第三条用一行 Python 代码导入两个包并打印 OpenCV 版本。你能看到opencv ok开头的信息就说明环境基本可用。如果提示No module named cv2大概率是安装到了另一个 Python 环境回到上一步确认你用的python和pip是不是同一个。如果python命令不存在把命令里的python换成py再试如果终端提示权限问题不要急着改系统目录先在当前练习目录里操作。安装完成后建议再运行一次验证命令确认不是“装的时候成功、导入的时候失败”。环境问题越早发现越省时间别等到代码写到一半才回头查。3.3 第一个能跑的例子生成数字 7灰度化再二值化保存现在跑第一个完整例子。为了让你没有素材也能开始代码会先用 OpenCV 画一张白底黑字的数字 7然后读回来转成灰度图再做二值化。二值化的意思是设定一个阈值把像素分成黑和白两类。这里用反转阈值让白底黑字变成黑底白字后面找轮廓时数字会更“站出来”。import os import cv2 import numpy as np os.makedirs(data, exist_okTrue) # 1. 造一张白底黑字的数字图方便没有素材也能跑 canvas np.full((220, 320, 3), 255, dtypenp.uint8) cv2.putText( canvas, 7, (100, 170), cv2.FONT_HERSHEY_SIMPLEX, 5.0, (0, 0, 0), 12, cv2.LINE_AA ) raw_path data/digit_7_raw.png cv2.imwrite(raw_path, canvas) # 2. 读图读不到就直接报错别让 None 往后跑 img cv2.imread(raw_path) if img is None: raise FileNotFoundError(f读不到图片{raw_path}) print(原图形状, img.shape) # (高, 宽, 通道) # 3. 灰度化把三通道压成单通道 gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) print(灰度形状, gray.shape) # 4. 二值化白底黑字 - 黑底白字 _, binary cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV) binary_path data/digit_7_binary.png cv2.imwrite(binary_path, binary) print(二值图形状, binary.shape) print(二值图里出现的值, np.unique(binary))这段代码分四步。第一步用np.full建一张 220 高、320 宽、3 通道的白色画布255是白色cv2.putText在画布上写一个数字 7(100, 170)是文字左下角起点cv2.FONT_HERSHEY_SIMPLEX是字体5.0是字号(0, 0, 0)是黑色12是线宽cv2.LINE_AA让边缘平滑一些。第二步用cv2.imread读图读不到就抛错避免后面拿到None还继续算。第三步用cv2.cvtColor转灰度cv2.COLOR_BGR2GRAY是 OpenCV 常用的彩色转灰度方式。第四步用cv2.threshold做二值化127是阈值255是最大值cv2.THRESH_BINARY_INV表示反转原本比阈值暗的像素变白比阈值亮的像素变黑。跑完你会得到两张图data/digit_7_raw.png是白底黑字data/digit_7_binary.png是黑底白字。打开二值图看一眼数字应该是白色背景应该是黑色。如果反了说明阈值类型或原图底色和预期不一致先别往下走把二值图调对。参数怎么改如果背景不够干净可以把阈值从 127 调到 100 或 150 试试如果数字笔画太细可以先检查原图线宽别急着怪阈值。np.unique(binary)一般会输出[0 255]说明图里只剩黑白两档。提示二值图是后面找轮廓的输入。你每次改完参数都保存一张图看一眼比盯着终端输出有效得多。4. 让数字站出来用轮廓裁剪出 0 到 9 的小窗口上一章得到的是整张黑白图。整张图里既有数字也有大片背景。识别之前你要把每个数字单独裁出来变成一个小窗口。OpenCV 里常用的做法是找轮廓把连在一起的白像素区域圈出来再用外接矩形裁剪。听起来有点抽象你可以把它想成在一张黑纸上找白色贴纸找到每张贴纸的边框然后把边框里的内容剪下来。裁剪完还要统一尺寸否则后面比较或分类时大小不一会让结果很不稳。4.1 为什么不能直接识别整张图先找轮廓再裁剪直接拿整张图去识别问题很多。数字可能偏左、偏右、偏上、偏下背景里还可能有一堆小白点。识别方法看到的是一整块区域很难知道哪部分是数字、哪部分是噪声。先找轮廓相当于先定位“哪里有东西”再把每个东西单独拿出来。这样每个小图只包含一个数字后续处理会简单很多。找轮廓前输入最好是黑底白字。因为cv2.findContours找的是白色前景的边界。你上一章用THRESH_BINARY_INV把白底黑字反转成黑底白字就是为了这一步。轮廓找到后用cv2.boundingRect得到每个轮廓的外接矩形矩形包含左上角坐标、宽和高。再用数组切片把矩形区域裁出来就得到单个数字小图。裁剪时还要注意顺序。一张图里如果有“123”轮廓返回的顺序不一定是从左到右。你后面要按位置拼回“123”就得先按左上角 x 坐标排序。这个细节很小但新手很容易忽略最后得到“231”还以为是识别错了。先排序再保存文件名按顺序编号后面排查会轻松很多。4.2 跟做从“123”图里切出三个数字小图下面这段代码会生成一张写着“123”的白底黑字图然后二值化、找轮廓、过滤小噪点、按从左到右排序、裁剪并缩放到 28×28。你可以直接接着上一章的目录跑。import os import cv2 import numpy as np os.makedirs(data/crops, exist_okTrue) # 1. 生成一张包含 123 的测试图 canvas np.full((220, 520, 3), 255, dtypenp.uint8) cv2.putText( canvas, 123, (30, 170), cv2.FONT_HERSHEY_SIMPLEX, 4.0, (0, 0, 0), 10, cv2.LINE_AA ) raw_path data/digits_123.png cv2.imwrite(raw_path, canvas) # 2. 读图、灰度、二值化 img cv2.imread(raw_path) if img is None: raise FileNotFoundError(f读不到图片{raw_path}) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) _, binary cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV) # 3. 找轮廓不同 OpenCV 版本返回值个数可能不同这里取最后两个 found cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) contours, hierarchy found[-2:] boxes [] for cnt in contours: area cv2.contourArea(cnt) if area 80: # 过滤太小的小白点数值可按图片调整 continue x, y, w, h cv2.boundingRect(cnt) boxes.append((x, y, w, h)) # 4. 按 x 坐标从左到右排序避免裁出来的顺序乱掉 boxes.sort(keylambda b: b[0]) # 5. 逐个裁剪缩放到 28x28并保存 for i, (x, y, w, h) in enumerate(boxes): roi binary[y:y h, x:x w] roi_28 cv2.resize(roi, (28, 28), interpolationcv2.INTER_AREA) out_path fdata/crops/digit_{i}.png cv2.imwrite(out_path, roi_28) print(f第 {i} 个x{x}, y{y}, w{w}, h{h}, 保存到 {out_path}) print(共裁出, len(boxes))这段代码的关键在cv2.findContours。cv2.RETR_EXTERNAL表示只取最外层轮廓适合数字这种前景块cv2.CHAIN_APPROX_SIMPLE会压缩轮廓点减少计算量。found[-2:]是为了兼容不同 OpenCV 版本返回两个值或三个值的情况拿到轮廓列表和层级信息。cv2.contourArea算轮廓面积面积太小的多半是噪点用area 80过滤掉。cv2.boundingRect返回外接矩形的x、y、w、hbinary[y:yh, x:xw]就是按矩形裁图。排序用boxes.sort(keylambda b: b[0])b[0]是左上角 x 坐标数字越小越靠左。裁剪后cv2.resize(roi, (28, 28), interpolationcv2.INTER_AREA)把每个数字缩到 28×28INTER_AREA在缩小图像时通常更平滑。你跑完应该看到data/crops/里有digit_0.png、digit_1.png、digit_2.png三张图打开看分别对应 1、2、3。如果数量不对先检查面积阈值是不是把数字也过滤了或者背景里是不是有连在一起的白块。4.3 裁剪后还要统一尺寸28×28 和 0 到 1 归一化怎么理解裁剪出来的数字大小往往不一样“1”很窄“8”很宽手写数字还可能高矮不一。如果直接把不同尺寸的图拿去比较结果会很乱。统一缩放到 28×28 是入门阶段常用的做法不是为了好看而是为了让每个样本有相同的像素数量。你可以把它想成把不同大小的照片都装进同样大小的相框后面比较时才有共同尺度。缩放时要注意变形问题。直接resize到 28×28 会把窄数字拉宽、宽数字压扁。入门阶段可以先接受这一点先把流程跑通等准确率不稳时再改成“先补边成正方形再缩放”。补边的意思是给数字四周加黑边让宽高比尽量保留然后再缩到目标尺寸。这个改进不复杂但新手不必在第一遍就加先把“裁出来、能保存、能打开看”做好。另一个常见动作是归一化。二值图里的像素值是 0 和 255有些分类方法更喜欢 0 到 1 之间的小数。你可以用一行代码把像素值除以 255roi_float roi.astype(float32) / 255.0。这样 0 还是 0255 变成 1。它不会改变数字形状只是换了一个数值范围。入门阶段先知道有这一步即可等你用模板匹配或 KNN 时再按方法要求处理。注意裁剪图保存成 PNG 时仍然是 0 和 255 的整数图归一化通常是在送进分类方法前临时做不要把浮点数图直接当普通图片保存后还期待它看起来一样。5. 避坑与排查零基础做数字识别最常卡住的 5 个地方数字识别入门最容易让人泄气的不是概念难而是小问题反复出现图片读不到、黑白反了、轮廓一大堆、裁出来的图大小不一、换一张图就翻车。下面这五个坑基本覆盖了新手最常遇到的情况。每条都按“现象、原因、解决”拆开写你遇到问题时可以直接对号入座。排查时先保存中间图再看终端输出别只盯着最后结果。5.1 图片读进来是 None路径、文件名和当前目录现象运行到cv2.imread后打印出来是None后面cv2.cvtColor直接报错或者程序提示“读不到图片”。原因最常见的是路径不对。代码里写的是相对路径但终端当前目录不在练习目录也可能是文件名拼错、扩展名大小写不一致、图片实际是jpeg却写成了png。还有一种情况是路径里有中文或特殊符号某些环境下cv2.imread读起来不稳定。新手看到None容易以为 OpenCV 坏了其实多数是文件根本没被找到。解决先打印当前目录确认自己站在哪里print(os.getcwd())再用os.path.exists(raw_path)检查文件是否存在。路径尽量改成英文目录文件名保持简单。如果确实需要读中文路径可以用 NumPy 先读字节再让 OpenCV 解码import numpy as np import cv2 path data/数字图.png img cv2.imdecode(np.fromfile(path, dtypenp.uint8), cv2.IMREAD_COLOR) if img is None: raise FileNotFoundError(f仍然读不到{path}) print(img.shape)这段代码用np.fromfile把文件读成字节数组cv2.imdecode再把字节解码成图像cv2.IMREAD_COLOR表示按彩色图读取。它适合路径里含中文的情况但不能解决文件名写错的问题。排查顺序建议是先看文件在不在再看路径对不对最后才考虑编码和读取方式。每次读图后加一句“读不到就报错”能省下很多莫名其妙的后续错误。5.2 黑白反了THRESH_BINARY 和 THRESH_BINARY_INV 选错现象二值图保存出来背景是白的、数字是黑的后面找轮廓时找到一大片背景或者裁出来的图全是反的。原因cv2.threshold的最后一个参数决定黑白关系。cv2.THRESH_BINARY会把比阈值亮的像素变白、暗的变黑cv2.THRESH_BINARY_INV则反过来。你的原图是白底黑字时想让数字变成白色前景就要用反转阈值。原图如果是黑底白字再反转就会把背景变白数字变黑轮廓自然找错。解决先打开原图和二值图对比确认你要的前景是白色。白底黑字用cv2.THRESH_BINARY_INV黑底白字可以先试cv2.THRESH_BINARY。阈值 127 不是固定答案光照不均时可以试 100、150或者先做模糊再阈值。不要在同一张图上反复盲调保存二值图看一眼比盯着数字猜快得多。提示找轮廓前前景最好是你关心的数字背景尽量是黑色。这个约定能减少后面一半的麻烦。5.3 轮廓一大堆噪点、边框和面积过滤现象一张图里明明只有三个数字却裁出十几个小图里面还有小白点、细边、纸纹。原因二值化后背景里的小噪点、图片边框、阴影、数字断裂处都会形成轮廓。cv2.findContours不会自动知道哪个是数字它只负责找白色区域。面积很小的轮廓多半是噪声面积特别大的轮廓可能是边框或整块背景。还有一些数字笔画断开会被拆成多个轮廓。解决先加面积过滤把太小的轮廓丢掉如果边框很烦可以在二值化前把图片四周裁掉几个像素或者用形态学开运算去掉小白点。开运算的写法是import cv2 import numpy as np kernel np.ones((3, 3), np.uint8) clean cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel, iterations1)np.ones((3, 3), np.uint8)建一个 3×3 的小核cv2.MORPH_OPEN表示开运算先腐蚀再膨胀通常能去掉孤立小白点iterations1表示做一次。如果数字笔画也被削细了可以把核改小或减少次数。面积阈值area 80也要按图片调整图很小就调低图很大就调高。排查时把每个轮廓的面积打印出来看看数字和噪声的面积差多少再定阈值。5.4 尺寸和位置不一致模板匹配和分类前必须统一现象单张图看着没问题一换数字模板匹配分数忽高忽低用简单分类方法时同一个数字稍微偏一点就认错。原因裁剪出来的数字大小、位置、笔画粗细不一致。直接缩放会把窄数字拉宽数字没居中会让像素对不齐不同字体的笔画粗细也会影响比较结果。入门阶段很容易只拿一张图调参数调到这张图刚好换一张就翻车。解决先统一尺寸再做居中。简单做法是先把裁剪区域补成正方形再缩放到 28×28更稳一点的做法是找到数字外接框后在四周留固定边距再把数字放到画布中心。样本方面每个数字至少准备几种字体、几种粗细、几种位置别只用一张图。你可以在data/crops/里按数字建子目录比如0/到9/每个目录放多张样本后面评估时才有对比。5.5 只拿一张图调参换字体、换背景就翻车现象在自己画的那张图上准确率很高换成截图、手写、不同字体后错误明显变多甚至完全找不到轮廓。原因参数被单张图“喂”得太刚好。阈值、面积过滤、缩放尺寸都和那张图的背景、字号、线宽绑定了。换一张图光照、对比度、数字大小变了原来的玄学参数就不适用。数字识别入门最常见的错觉就是“这张图跑通等于学会了”。解决准备一个小测试集至少包含不同来源的十几张图固定一套预处理流程跑一遍把失败案例保存下来。每次改参数不要只看一张图至少看五张。记录哪些图失败、失败在二值化还是裁剪再针对性调整。血泪经验是先让流程在多张图上稳定再追求单个数字的识别准确率。单张图调出来的参数往往没有后悔药。6. 下一步学什么从能切数字到能认数字的练习路线走到这里你已经能把数字从图里裁出来下一步才是“认字”。入门建议按难度走先模板匹配再简单 KNN最后再考虑小型卷积网络。模板匹配适合理解“比较像素”的基本思路KNN 适合理解“用样本投票”小型卷积网络适合在样本更多时提升效果。不要一上来就跳到最复杂的方法先把数据整理和评估做顺。阶段目标检查点模板匹配用 0 到 9 的标准小图去比对裁剪图能输出每个数字的匹配分数知道分数低时先看裁剪图简单 KNN每个数字准备多张样本按像素距离投票能统计一批测试图的错误案例知道错在哪个数字小型卷积网络样本量增加后提升泛化能固定训练集和测试集不拿测试图调参模板匹配的关键不是调出一个高分而是学会看失败图。分数低时先打开裁剪图看数字是不是缺笔画、没居中、黑白反了。KNN 的关键是样本质量每个数字至少准备几十张不同字体和粗细的小图尺寸统一到 28×28像素值归一化到 0 到 1。小型卷积网络可以放到后面等你有一批干净样本再碰不然训练集太小结果会很不稳。这份资源可以当作练习底稿拿到后先按第 3 章的环境检查跑一遍再按第 4 章修改面积阈值把 0 到 9 都试一次。每次改完参数保存二值图和裁剪图别只看终端输出。我第一次学的时候拿一张图把阈值调到刚好换一张就翻车从那以后我每次调参前都先凑十张不同来源的小图先跑通再微调。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?