首页/新闻资讯/正文详情

道路坑洼识别CNN二分类实战:从数据预处理到PyQt5界面部署

发布时间:2026/9/23 2:42:42 来源:云帆数科 栏目:资讯中心
道路坑洼识别CNN二分类实战:从数据预处理到PyQt5界面部署
简介这是一套基于PyTorch与CNN的道路坑洼识别方案配套完整数据集面向深度学习初学者及道路病害检测方向的动手实践者。压缩包共252个文件其中246张JPG图片覆盖正常与坑洼两类样本并包含旋转、填充灰边等增强后的图像3个TXT文件用于存储图片路径与标签3个Python脚本分别实现数据预处理、模型训练及PyQt界面展示整体压缩包约10.19MB。目前已有133人浏览/学习适合希望完整复现图像分类训练的开发者。代码围绕数据准备、模型训练和界面测试三个环节展开预处理时在短边增加灰边使图片变为正方形并按角度旋转扩充数据集随后用生成的TXT文本划分训练集与验证集完成CNN模型训练后本地保存模型并输出每个epoch的损失值与准确率日志最后通过可视化界面加载模型进行道路坑洼识别。资源体量适中、流程完整可帮助快速理解从数据整理到部署识别的全链路实践。1. 道路坑洼识别CNN二分类项目里最容易被低估的环节道路坑洼识别是路面养护场景里很典型的图像二分类问题核心就两件事判断一张路面图里有没有坑洼以及把这件事做成能交付的桌面工具。这个资源正好把这两件事都包了自带一个分好类的数据集跑通三个 Python 脚本就能完成从数据整理、CNN 模型训练到 PyQt5 界面识别的完整流程。环境基于 pytorch训练和推理代码都不长适合刚接触深度学习的同学拿来当第一个能跑通的项目。脚本设计得很像一个最小可复用的工程模板数据文本生成、模型训练、界面推理三段分离每一段都能单独替换。如果你是准备做课程设计、毕业设计或者想积累一个带数据的 CNN 实战项目这套代码的性价比很高。2. 数据准备与 CNN 选型为什么先处理正方形输入再谈模型很多人拿到带数据集的项目第一反应是直接调参训练结果往往在读取图片那一步就翻车。这个项目在数据预处理上做了一件很关键的事把每张图通过给较短边加灰边的方式变成正方形。这个设计和后面使用的 CNN 模型结构有关系得从数据到模型一起讲才能理解每个脚本存在的意义。2.1 数据集预处理灰边补正方形和旋转扩增先说补灰边。常见做法是用 OpenCV 的copyMakeBorder给较短边填充一圈灰色像素让宽高相等。为什么要填灰边而不是直接 resize直接 resize 会改变物体长宽比对路面裂缝、坑洼这类纹理敏感的目标来说形变会引入伪特征。填灰边则保持原有内容不被拉伸模型学到的特征更接近真实路况。项目里已经生成了类似pothole18_flip.jpg、pothole18_rotated45.jpg这样的文件名说明预处理里已经带了水平翻转和旋转 45 度两种扩增策略。这就是数据增强目的是让模型对拍摄角度、光照变化更鲁棒。预处理部分可以梳理成一张参数表方便你对照检查预处理项实现方式参数建议作用正方形化短边补灰边灰度值 128统一模型输入尺寸避免形变水平翻转cv2.flip(img, 1)概率 0.5增强左右对称特征旋转扩增cv2.warpAffine角度 45 度模拟不同拍摄角度归一化像素值除以 255可选加速收敛这里有个容易被忽略的细节旋转 45 度后图像四个角会露出黑色区域代码里一般会用borderModecv2.BORDER_CONSTANT指定填充色如果这个值设置成 0就会变成黑边和正常路面差异很大。我一般建议填充值跟补灰边保持一致也就是 128这样扩增后的样本视觉上更自然。预处理完的数据并不需要真正生成新的图片文件可以在Dataset的__getitem__里实时做变换这样省磁盘也能在每次 epoch 迭代时生成不同的扩增结果相当于给训练集加了随机性。如果你的显存够大也可以把扩增后的图片直接导出到文件夹里用torchvision.datasets.ImageFolder读取两种方式效果差别不大。2.2 制作训练文本01 脚本里的路径与标签逻辑项目里第一个要跑的脚本是01数据集文本生成制作.py它的作用是扫描dataset文件夹下每个类别目录把所有图片路径和对应标签写进 txt 文件。这里的标签规则很直接normal类对应 0pothole类对应 1生成结果类似下面这样import os import random data_root dataset classes [normal, pothole] # 标签顺序不能乱 with open(train.txt, w) as train_f, open(val.txt, w) as val_f: for label, cls in enumerate(classes): cls_dir os.path.join(data_root, cls) imgs [f for f in os.listdir(cls_dir) if f.endswith((.jpg, .png))] random.shuffle(imgs) # 先打乱再按比例切分 split_idx int(len(imgs) * 0.8) for i, name in enumerate(imgs): line f{os.path.join(cls_dir, name)} {label}\n if i split_idx: train_f.write(line) else: val_f.write(line)这段代码的核心是“路径 空格 标签”的文本格式。PyTorch 后续的Dataset读这个 txt 时会按行拆分取第一部分是图片路径第二部分是标签整数。这里的classes列表顺序决定了标签值一旦训练完成后就不能再改否则模型输出的类别含义就全乱了。我习惯在生成之后手动看一眼 txt 前几行确认路径分隔符在 Windows 下是\还是/。这个资源默认在 Linux 风格环境下写的如果你在 Windows 上跑可能出现路径带\导致读取失败的情况。常见做法是在写入时用os.path.abspath转成绝对路径并统一替换为/。另外8:2 的划分比例对这个体量的数据集是合理的但如果某个类别图片特别少建议先统计类别数量再考虑是否需要分层采样。2.3 模型选型二分类场景下 CNN 卷积神经网络的配置这个项目用的是 CNN 卷积神经网络而不是直接上 YOLOv8 或 Transformer。原因很简单坑洼识别是单类别检测的二分类问题不需要框坐标只需要判断“有”还是“没有”一个轻量 CNN 完全够用。相比 YOLOv8 训练自己的数据集需要标注 bounding box这个资源只需要图片级标签门槛低很多。对于这种任务我会优先用 ResNet18 作为 backbone预训练权重从torchvision加载把最后一层全连接改成 2 输出。训练脚本里的模型构造大致长这样import torchvision.models as models def create_model(): model models.resnet18(pretrainedTrue) in_features model.fc.in_features model.fc torch.nn.Linear(in_features, 2) # 二分类 return model用预训练权重的理由是坑洼和正常路面的纹理差异在 ImageNet 上有一定迁移基础模型训练收敛更快准确率更容易上去。如果你在的环境下载不了预训练权重也可以把pretrained改成False从头训只是需要更多的 epoch 和更好的数据增强来补。模型输入尺寸建议设成 224 x 224这是 ResNet 系列的标准输入。Batch Size 在显存允许的情况下尽量设 32太小会导致梯度震荡太大在小数据集上容易过拟合。优化器用 Adam初始学习率 0.001配合 StepLR 每 10 个 epoch 衰减 0.1这样整体训练曲线会比较稳。3. 训练与界面pytorch 训练流程和 PyQt5 识别的完整闭环数据文本生成之后接下来就是模型训练和界面推理。这一章把02深度学习模型训练.py和03pyqt_ui界面.py两个脚本拆开讲搞清楚每个脚本的职责边界后面遇到问题才知道去哪里排查。3.1 训练脚本数据集划分、优化器参数与模型保存训练脚本的核心流程是读取 train.txt 和 val.txt构造 Dataset 和 DataLoader定义模型和优化器循环训练若干 epoch每个 epoch 结束后在验证集上算损失和准确率。自定义 Dataset 的写法需要认真学习因为后面接任何数据集都要用这套模板from torch.utils.data import Dataset from PIL import Image class RoadDataset(Dataset): def __init__(self, txt_path, transformNone): self.samples [] with open(txt_path, r) as f: for line in f.readlines(): path, label line.strip().split() self.samples.append((path, int(label))) self.transform transform def __len__(self): return len(self.samples) def __getitem__(self, idx): path, label self.samples[idx] img Image.open(path).convert(RGB) if self.transform: img self.transform(img) return img, label这段代码里有两个参数值得注意。第一个是convert(RGB)把灰度图统一转成三通道避免某些读取出来的图片是单通道导致 CNN 输入维度不匹配。第二个是line.strip().split()它把一行拆成[路径, 标签]两部分如果 txt 里有空行或多余空格这里会直接报错。训练时的 transform 通常配合数据增强一起用from torchvision import transforms train_transform transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ])这里的Resize(256)和CenterCrop(224)是先放大再裁剪相当于给模型一个带随机位置的视野比直接Resize(224)效果更好。归一化的均值和标准差用的是 ImageNet 标准值和预训练权重配套不能随意改。如果你把均值设成 0.5模型收敛速度会明显变慢。训练循环本身不复杂保存模型时要保留两个东西模型权重和类别标签映射。常见的保存写法是torch.save(model.state_dict(), best_model.pth)但这样只存了权重加载时必须手动重建模型结构还要自己记住classes [normal, pothole]的顺序。我更推荐连元信息一起存torch.save({ model_state: model.state_dict(), classes: [normal, pothole] }, best_model.pth)这样后面写界面代码时直接从字典里读类别列表不用重新手写避免标签顺序搞混。3.2 日志与验证准确率、损失值和 epoch 的关系训练脚本会在本地生成 log 日志文件记录每个 epoch 的验证集损失值和准确率。这个日志的定位很重要它是判断模型是否过拟合、学习率是否合适的唯一依据。我一般会把训练过程的曲线画出来横轴是 epoch纵轴分别画 loss 和 accuracy。如果看到训练损失持续下降但验证损失在第 10 个 epoch 后开始反弹说明模型开始过拟合此时应该停止训练或者增加数据增强的强度。如果验证准确率一直在 50% 上下抖动大概率是标签和数据没对齐不是模型问题。快速验证的方法是拿十张就知道结果的图喂给模型看预测概率分布如果连训练集都拟合不了那就是代码链路有问题。3.3 PyQt5 界面从加载模型到单张图片预测第三个脚本03pyqt_ui界面.py做的事情比较直观弹出一个窗口选择图片读取模型权重输出这张图属于正常还是坑洼并显示置信度。界面代码的关键不在界面布局而在推理部分的图像预处理要和训练时保持完全一致。很容易出现的问题是这样的训练时图片经过了Resize(256)CenterCrop(224) 归一化界面推理时直接Resize(224)就送进模型输入分布变了准确率立刻崩掉。推理部分的处理必须复用训练时的 transform而且要注意torch.no_grad()包裹def predict_image(model, img_path, device): img Image.open(img_path).convert(RGB) img_tensor val_transform(img).unsqueeze(0).to(device) model.eval() with torch.no_grad(): outputs model(img_tensor) probs torch.softmax(outputs, dim1)[0] return probs.cpu().numpy()unsqueeze(0)这一步是给图片加一个 batch 维度因为模型期望的输入是[B, C, H, W]单张图只有[C, H, W]。softmax把输出转成概率值两个数分别对应正常和坑洼类别的概率。界面里显示图片时PyQt5 的QLabel和 OpenCV 的 BGR 通道顺序有坑如果你用cv2.imread读图再转QPixmap颜色会偏蓝需要用cv2.cvtColor(img, cv2.COLOR_BGR2RGB)转一次。4. 避坑与常见问题环境配置到训练完成的五个坑这个项目整体流程短但真到自己复现时坑基本集中在环境、路径和预处理不一致这三类。下面这几个问题都是这个场景里最容易翻车的按“现象到解决”一条条列出来。4.1 现象requirement.txt 安装后 PyQt5 启动闪退Windows 上跑03pyqt_ui界面.py时窗口一闪而过控制台报错提示缺少Qt platform plugin windows。原因是 PyQt5 安装之后系统环境变量里没有正确指向PyQt5\Qt5\plugins目录。解决方法是找到你的 Python 安装目录把Lib\site-packages\PyQt5\Qt5\plugins加到QT_QPA_PLATFORM_PLUGIN_PATH环境变量里。我一般直接在代码开头加一段import os os.environ[QT_QPA_PLATFORM_PLUGIN_PATH] .../site-packages/PyQt5/Qt5/plugins安装依赖时用pip install -r requirement.txt没问题但 PyQt5 的版本最好单独确认新版 PyQt5 与 Python 3.10 以下版本组合时偶尔会有兼容问题。如果控制台报的是ModuleNotFoundError那多半是某个包没装全逐个补装就行。4.2 现象训练时报错说找不到图片路径报错信息类似FileNotFoundError: [Errno 2] No such file or directory: dataset/normal/xxx.jpg但打开文件夹检查图片明明存在。这类问题几乎都是工作目录不对。脚本里用的dataset是相对路径如果你不是在代码所在目录启动 Python解释器当前工作目录就变了。解决方法是让代码自己定位项目根目录而不是依赖终端所在位置。在脚本最上面加import os os.chdir(os.path.dirname(os.path.abspath(__file__)))os.path.dirname(os.path.abspath(__file__))拿到的是当前脚本的绝对路径目录切换过去之后所有相对路径都稳定了。这招在跑任何带数据集的 Python 项目时都适用。4.3 现象训练时显存不够batch size 一调小就报错显存溢出是 pytorch 项目里最常见的报错提示通常是CUDA out of memory。很多人直接把 batch size 从 32 改成 8但忽略了另一个显存大户是torchvision的预训练模型在前向传播时保存的中间激活值。解决步骤分两步先把 batch size 改成 16 或 8同时把输入尺寸从 224 降到 192 试试如果还不行检查是不是验证集也把梯度打开了。验证阶段忘了with torch.no_grad():的话验证集同样会占大量显存。另外训练脚本里如果有model model.to(device)对应的输入图片也要.to(device)否则数据一直在 CPU 和 GPU 之间搬运显存不会涨但训练速度会慢到让人以为卡死了。4.4 现象模型训练完了界面识别结果全是同一类这个问题很隐蔽常见原因是训练脚本里在 Dataset 层做了数据增强但推理脚本没有对齐 transform。训练时用了RandomHorizontalFlip和旋转推理时只用了Resize模型的输入分布和训练时不一致输出就偏向某一类。解决方法是把推理 transform 单独定义保证和训练时的验证 transform 完全一致。另一个元凶是模型保存和加载之间的类顺序不一致。训练时classes [normal, pothole]加载后如果代码里重新写了classes [pothole, normal]预测结果就会完全反转。所以保存模型时把 classes 一起存进去加载时原样读出来是最稳妥的做法。4.5 现象训练日志显示准确率一直不涨如果验证准确率始终在 50% 左右先别动网络结构先做两件事。第一检查 train.txt 和 val.txt 里的标签是否真的对应图片内容随机抽十张图看图与标签是否匹配。第二用很小的子集跑一个 epoch比如只拿 20 张图训练如果 loss 能降下去说明代码链路没问题问题出在数据量或数据分布上。还有一种可能是数据增强过强旋转 45 度、随机翻转叠加后训练样本和真实路况差异太大。这时候把增强强度降下来比如旋转角度从 45 度改成 15 度学习率从 0.001 改成 0.0005准确率往往会慢慢上来。这类玄学问题没有一个标准答案只能靠控制变量去试。5. 进阶让坑洼识别更稳的四个验证技巧模型训练完不是结束真正要交付时还得过验证这一关。我在这类二分类项目上吃过亏现在拿到训练好的模型会强制走一遍下面四个验证步骤。第一单独准备一组模型没见过的测试图不要用 val.txt 里出现过增强版本的图片。数据增强会导致同一张原图存在翻转和旋转版本如果这些版本被分到了训练集和验证集两边验证准确率会虚高。做法是手动挑 20 张和数据集里不完全重复的图片放在一个test_manual文件夹里单独跑一轮预测。第二计算混淆矩阵而不只看准确率。坑洼识别里漏检比误报更严重。漏检意味着路面有坑但系统说正常这个问题会影响行车安全。把预测结果统计成一个 2x2 矩阵看 false negative 的数量如果偏高宁可在界面上把判断阈值调低。比如模型输出 pothole 概率 0.6 就判定为坑洼而不是默认的 0.5。第三验证不同光照条件下的表现。可以写一个简单的亮度扰动脚本把测试图的亮度乘一个系数重新预测看结果是否稳定。如果亮度一降低预测结果就翻转说明模型对光照过拟合需要补充更丰富的训练数据或者加入颜色抖动增强。第四检查界面推理速度。PyQt5 界面里如果加载模型后每次预测都重新执行torch.load会很慢。正确做法是在界面初始化时加载一次模型后面只做前向传播。还可以把模型切到 eval 模式再用torch.jit.trace或torch.onnx.export导出成静态图推理速度能提升不少。虽然这个项目没提供导出脚本但自己加上很简单。从那次之后我每次跑完训练都会把模型加载、推理 transform、测试图片路径这三个点单独写成一个验证脚本先跑通再开界面。路径写错、transform 不一致、类顺序颠倒这类问题全都能在验证脚本里暴露出来等界面出问题再去排查就晚了。希望这些经验能帮你少走几步弯路。本文还有配套的精品资源点击获取

相关推荐

泉州防水补漏上门电话|本地师傅勘查漏水位置|欧米到家服务电话
泉州防水补漏上门电话|本地师傅勘查漏水位置|欧米到家服务电话

📝 文章简介泉州住宅、商铺和办公场所常见的漏水问题,包括卫生间渗水、阳台积水、屋顶漏水、外墙返潮、厨房墙面发霉、窗边渗水、地下室潮湿等。欧米到家提供泉州多区域防水补漏、漏水点排查、局部修补、卫浴及水电相关维修服务。遇到雨后渗水、墙顶水印… · 2026/9/23 2:42:29

Self-hosted LiveSync 贡献指南:从环境搭建、代码验证到翻译与发布的全流程实战
Self-hosted LiveSync 贡献指南:从环境搭建、代码验证到翻译与发布的全流程实战

数据同步 【免费下载链接】obsidian-livesync 项目地址: https://gitcode.com/gh_mirrors/ob/obsidian-livesync 点击查看 免费下载 本篇指南基于 obsidian-livesync 仓库的 CONTRIBUTING.md 与 devs.md 编写,系统讲解如何为 Self-hosted LiveSync&… · 2026/9/23 2:42:29

自研还是采购?一套可复制的BI选型决策框架与成本模型
自研还是采购?一套可复制的BI选型决策框架与成本模型

聊到BI选型,团队里几乎绕不开同一个争论:到底是自研一套BI,还是直接采购成熟产品。这个问题的答案远不是一句“看预算”就能打发的。过去几年我既带人从零搭过BI平台,也主导过Power BI、FineBI这类成熟产品的落地,两种… · 2026/9/23 2:42:29

神坛手写实现:图解原理助你避开配置死胡同
神坛手写实现:图解原理助你避开配置死胡同

神坛手写实现:图解原理助你避开配置死胡同 配置环境就卡半天?别慌,咱们今天把“神坛”这俩字掰开了揉碎了讲。很多转岗的哥们儿一上来就对着文档抓狂,装个依赖报错,改个配置崩溃,其实是因为没看懂底层的 图解原理 。… · 2026/9/23 3:35:40

生化分析仪原理面试必问:3个核心逻辑破解报错难题
生化分析仪原理面试必问:3个核心逻辑破解报错难题

生化分析仪原理面试必问:3个核心逻辑破解报错难题 盯着屏幕上一长串红色的 Error 和 StackTrace,是不是脑子瞬间宕机?别急,这不仅是代码… · 2026/9/23 3:35:40

Windows下Node.js安装与环境配置全攻略
Windows下Node.js安装与环境配置全攻略

每次看到新手问“Node.js下载安装”这类问题,我都挺感慨的。这个问题看着简单,真要一次配好,里面其实藏着不少坑:版本选错了、Path环境变量没生效、npm源慢到卡死、装完全局包却找不到命令……随便卡一步,后面写代码的… · 2026/9/23 3:35:34

【JAVA课程设计/毕业设计】基于 JavaScript 的音乐收藏分析智能推荐系统 网页端智能音乐推送与个性化推荐系统【附源码、数据库、万字文档】
【JAVA课程设计/毕业设计】基于 JavaScript 的音乐收藏分析智能推荐系统 网页端智能音乐推送与个性化推荐系统【附源码、数据库、万字文档】

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am… · 2026/9/23 3:35:34

3步搞定taskeng配置,2026最新原理详解
3步搞定taskeng配置,2026最新原理详解

3步搞定taskeng配置,2026最新原理详解 配置环境就卡半天,是不少开发者接手新项目时的噩梦。特别是涉及跨系统任务调度时,文档滞后、依赖冲突、参数晦涩,让人抓狂。2026最新版的 taskeng… · 2026/9/23 3:35:28

Visual Studio编码设置内部原理与中文乱码排查实战
Visual Studio编码设置内部原理与中文乱码排查实战

先从一个特别常见的场景说起:你在Visual Studio里写了一堆带中文注释的C代码,明明保存时选了“UTF-8”,结果上传到Git仓库,同事拉下来一打开,中文全部变成了锟斤拷或者一串带问号的乱码;或者反过来&#xf… · 2026/9/23 3:35:28

3招搞定手机怎么下载微信面试难题实战项目解析
3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧
Win7无线热点配置工具源码解析:解决API失效的3个实战技巧

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧 Win7无线热点配置工具在Win10/11上跑不动?不是你的问题,是版本升级后 API 全变了。很多老项目里的 netsh wlan… · 2026/9/23 0:00:36

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码