
简介这份资源是2023届合肥工业大学电子信息科学与技术专业的毕业设计完整项目题目为基于机器视觉技术的液晶屏切割缺陷辅助检测系统主要面向计算机、人工智能、通信工程、自动化、电子信息等专业的在校学生与教师也适合作为课程设计、作业或项目初期立项的参考案例。项目基于Python 3.11与OpenCV实现代码经过实际运行测试答辩评审平均分达到96分。压缩包共34个文件约13.49MB其中包含25个Python源码文件覆盖图像预处理、缺陷检测、模型训练与预测、界面交互等模块另有pth模型权重、png示例图片、ttf字体、html模板及md说明文档等辅助文件。目前已有251人浏览学习。读者可从中获得一套完整的液晶屏切割缺陷检测实现方案包括图像处理流程、深度学习模型结构、训练与推理脚本、可视化界面代码以及项目配置说明便于理解机器视觉在工业质检中的落地思路也可在此基础上修改扩展以实现其他功能。1. 从一张切割后的液晶屏照片说起这套毕设到底在做什么液晶屏切割是面板产线里最容易被低估的一道工序。玻璃基板按尺寸划切、裂片之后边缘会出现崩边、微裂、缺角、毛刺这类缺陷人眼在强光下盯着看一天下来眼睛基本报废而且漏检率随疲劳直线上升。这套合肥工业大学2023届电子信息科学与技术专业的毕设做的就是把这件苦力活交给机器视觉用 Python 3.11 加 OpenCV 搭一套辅助检测系统把切割后的屏体图像读进来做预处理、缺陷定位、分类判定最后在界面上把结果标出来还能导出报告。它不是一个跑在产线上的工业级软件而是一份结构完整、能跑通、能讲清楚原理的毕业设计工程。适合三类人正在做机器视觉方向毕设、需要一份可参考的完整工程骨架的学生想学 OpenCV 图像处理但缺一个真实场景练手的初学者以及需要快速搭一个缺陷检测 demo 做立项演示的从业者。答辩评审平均分96分这个信息说明它的完成度和文档质量是过关的但你要清楚它的边界——它是辅助检测不是替代人工的产线系统。整份资源里main.py是入口check/放检测逻辑img_process/放图像处理network/放模型定义和训练ui/是界面source/存权重和素材log/记日志。下面按「这东西怎么跑起来 → 每个模块在干什么 → 哪里会翻车」的顺序拆开讲。2. 环境搭建与工程结构把这份源码跑起来的第一步拿到一个毕设压缩包最怕的是解压完一脸懵不知道从哪下手。这一章先把运行环境和目录职责理清楚让你能在自己机器上把它跑起来而不是卡在第一步。2.1 Python 3.11 环境与依赖安装项目明确写了 Python 3.11这个版本号不要随便改。OpenCV 和 PyTorch 在不同 Python 版本下的 wheel 兼容性差异很大尤其是 Windows 上3.11 是个相对稳的甜点版本。依赖清单在requirements.txt里常见做法是先建虚拟环境再装避免污染全局。# 创建虚拟环境名字随意这里用 venv python3.11 -m venv venv # 激活Linux/macOS source venv/bin/activate # 激活Windows venv\Scripts\activate # 安装依赖建议加国内镜像加速 pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple这里几个参数值得说清楚。-m venv是标准库自带的虚拟环境模块不需要额外装 virtualenv。镜像地址只是加速下载装不上时可以先去掉镜像用默认源试一次排除是镜像同步延迟导致的包缺失。如果requirements.txt里某个包版本锁得很死装不上先看报错是编译失败还是找不到版本——编译失败通常是缺 C 构建工具找不到版本多半是 Python 版本不对。提示装完先跑python -c import cv2, torch; print(cv2.__version__, torch.__version__)两个都能打印出版本号环境这关就算过了。2.2 目录职责拆解每个文件夹对应哪一步这份工程的目录划分是典型的「按职责分层」理解了这个分层后面读代码就不会迷路。下面这张表是我按实际文件推断出的职责映射你对照着看。目录/文件职责关键文件main.py程序入口串联检测流程main.pycheck/缺陷检测核心逻辑check_defect.pyimg_process/图像预处理与格式转换new_process.py、basic.py、cut_image.py、change_tiff.py、pre_process.pynetwork/模型定义、训练、推理model.py、train.py、predict.py、my_dataset.py、transformer.py、model_config.pyui/图形界面与结果展示cutting_error_app.py、ui_main.py、image_item.py、result_panel.py、manual_annotation.pysource/权重与素材xbest_model.pth、cut_icon.png、OPPOSans-M.ttf、template.htmllog/日志记录log.pyutils.py通用工具函数utils.pyxbest_model.pth是训练好的模型权重这是整个系统能直接出结果的关键——没有它你得自己从头训。template.html配合report/result.py用来生成检测报告OPPOSans-M.ttf是报告里的中文字体缺了它报告中文会变方块。manual_annotation.py说明这套东西还带了一个手动标注的小工具方便你补样本。2.3 启动流程与首次运行检查启动入口是main.py但直接双击运行大概率会报路径错误因为代码里读图片、读权重多半用的是相对路径。正确姿势是在项目根目录下用命令行启动。# 在项目根目录执行保证相对路径正确 python main.py如果界面能弹出来说明 UI 和依赖都没问题。如果报FileNotFoundError八成是权重或素材路径不对去source/确认xbest_model.pth在不在。如果报 CUDA 相关错误但你机器没显卡常见做法是在model_config.py或predict.py里把设备改成 CPU找cuda关键字改成cpu即可。第一次运行建议先用source/no_defect.png这种无缺陷图试确认流程通了再上真实缺陷图这样能把「流程问题」和「检测问题」分开排查。3. 图像预处理链路从原始图到模型能吃的输入机器视觉项目里预处理往往比模型本身更影响最终效果。液晶屏切割缺陷很多是微米级的崩边和细裂原始图直接喂给模型噪声和光照不均会先把缺陷淹掉。这一章拆img_process/里的处理链路。3.1 灰度化、去噪与边缘增强的组合拳basic.py和pre_process.py承担的是基础处理。常见做法是先把彩色图转灰度再做高斯或中值去噪然后用 Canny 或 Sobel 提边缘。为什么先灰度因为切割缺陷主要靠亮度和梯度变化体现颜色信息在这里是干扰项转灰度既降计算量又降噪声维度。import cv2 import numpy as np def preprocess(img_path): # 读图保持原始通道顺序 img cv2.imread(img_path) # 转灰度缺陷检测主要看亮度梯度 gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 高斯去噪核大小取奇数5x5 适合中等噪声 blur cv2.GaussianBlur(gray, (5, 5), 0) # 自适应阈值应对光照不均比全局阈值稳 binary cv2.adaptiveThreshold( blur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2 ) return img, gray, binaryGaussianBlur的核大小(5, 5)是经验值噪声重就上(7, 7)但核越大边缘越糊缺陷细节会丢。adaptiveThreshold的两个关键参数blockSize11是邻域大小必须是奇数太小会把噪声当边缘太大对细小缺陷不敏感C2是从均值里减去的常数调大更保守、保留的前景更少。这两个参数是这套预处理里最需要按你的实际图像调的别照抄。3.2 切割区域定位与 TIFF 格式转换cut_image.py负责把屏体区域从整张图里裁出来change_tiff.py处理 TIFF 格式。工业相机很多输出 TIFF因为它是无损的但 OpenCV 读 TIFF 有时会遇到位深问题——16位 TIFF 直接读进来会被截断成 8 位细节就没了。import cv2 import numpy as np def read_tiff_safe(path): # 用 IMREAD_UNCHANGED 保留原始位深 img cv2.imread(path, cv2.IMREAD_UNCHANGED) if img is None: raise ValueError(f读不到图: {path}) # 16位图归一化到8位避免截断丢细节 if img.dtype np.uint16: img cv2.normalize(img, None, 0, 255, cv2.NORM_MINMAX) img img.astype(np.uint8) return imgIMREAD_UNCHANGED这个 flag 是关键默认的IMREAD_COLOR会强制转 8 位三通道16 位灰度图的动态范围直接损失掉。cv2.normalize用NORM_MINMAX把 16 位线性映射到 0-255这是保细节的常见做法。裁切区域定位一般靠轮廓检测找最大外接矩形cut_image.py里应该就是这个思路你可以顺着findContours去找。3.3 数据增强与数据集封装my_dataset.py是 PyTorch 的 Dataset 封装unfold_test.py看名字是做展开测试或数据展开。缺陷样本通常很少数据增强是必须的。常见做法是随机翻转、旋转小角度、亮度扰动但要注意——切割缺陷有方向性垂直翻转可能把「上边缘崩边」变成不存在的形态翻转策略要谨慎。from torch.utils.data import Dataset import cv2 import os class DefectDataset(Dataset): def __init__(self, root, transformNone): self.root root self.transform transform # 约定目录结构root/类别名/图片 self.samples [] for label, cls in enumerate(sorted(os.listdir(root))): cls_dir os.path.join(root, cls) if not os.path.isdir(cls_dir): continue for f in os.listdir(cls_dir): self.samples.append((os.path.join(cls_dir, f), label)) def __len__(self): return len(self.samples) def __getitem__(self, idx): path, label self.samples[idx] img cv2.imread(path) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) if self.transform: img self.transform(img) return img, label这个 Dataset 假设了「按类别分文件夹」的组织方式这是最省事的约定。sorted(os.listdir(root))保证类别索引稳定不然每次运行标签顺序变了训练就废了。transform传进来做增强训练时传增强、验证时传纯 resize这个区分别搞混否则验证指标会虚高。4. 模型训练与推理network 目录里的检测核心预处理把图洗干净了接下来是判定缺陷。这一章讲network/里的模型定义、训练和推理以及check/check_defect.py怎么把模型输出变成可读的检测结论。4.1 模型结构与配置文件解读model.py定义网络transformer.py说明用到了 Transformer 结构model_config.py是配置。用 Transformer 做缺陷检测在毕设里算是比较新的选择它相比纯 CNN 的优势在于能建模长距离依赖——液晶屏的裂纹往往是细长的跨越较大空间范围卷积核感受野有限注意力机制能补上这块。# model_config.py 里常见的配置项按实际文件对照 CONFIG { img_size: 224, # 输入尺寸需与预处理 resize 一致 num_classes: 2, # 二分类有缺陷/无缺陷多分类按实际改 backbone: transformer, pretrained: False, # 是否加载预训练权重 device: cuda, # 没显卡改成 cpu batch_size: 16, lr: 1e-4, # Transformer 常用小学习率 epochs: 50, }img_size必须和预处理里的 resize 对齐这是最常见的低级错误——训练用 224推理喂 256模型不会报错但结果会莫名其妙地差。lr1e-4是 Transformer 的常见起点比 CNN 常用的 1e-3 小一个量级因为注意力层对学习率更敏感大了容易震荡不收敛。num_classes按你的实际缺陷类别数改二分类就是 2。4.2 训练脚本参数与断点续训train.py是训练入口。毕设级别的训练脚本通常不复杂但有几个参数决定了你能不能训出东西。# 典型训练启动命令 python network/train.py \ --data_root ./dataset \ --epochs 50 \ --batch_size 16 \ --lr 1e-4 \ --device cuda \ --save_dir ./source--data_root指向数据集根目录结构要符合my_dataset.py的约定。--save_dir指向权重保存位置默认应该存成xbest_model.pth这种名字和source/里现成的权重对应。断点续训一般靠加载已有权重再训如果脚本支持--resume传上次的权重路径即可。训练时重点盯 loss 曲线训练 loss 降但验证 loss 升是过拟合加增强或加 dropout两个都不降是学习率太大或数据有问题。注意xbest_model.pth是别人训好的权重你直接用它推理没问题但如果你想改类别数或输入尺寸这个权重就对不上了必须自己重训。4.3 推理流程与检测结果输出predict.py做单张推理check_defect.py把推理结果转成检测结论。推理流程一般是读图 → 预处理 → 送模型 → 取 softmax → 阈值判定 → 输出类别和置信度。import torch import cv2 import numpy as np from network.model import build_model from network.model_config import CONFIG def predict_one(img_path, weight_path): device torch.device(CONFIG[device]) model build_model(CONFIG).to(device) # 加载权重map_location 保证 CPU 也能加载 GPU 训的权重 model.load_state_dict(torch.load(weight_path, map_locationdevice)) model.eval() img cv2.imread(img_path) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img cv2.resize(img, (CONFIG[img_size], CONFIG[img_size])) # 归一化到 [0,1] 并转 tensor维度顺序 HWC-CHW tensor torch.from_numpy(img / 255.0).float().permute(2, 0, 1).unsqueeze(0).to(device) with torch.no_grad(): logits model(tensor) prob torch.softmax(logits, dim1) conf, pred torch.max(prob, dim1) return pred.item(), conf.item()map_locationdevice这个参数是血泪经验——GPU 上训的权重直接load_state_dict到 CPU 环境会报错加上它就能跨设备加载。model.eval()必须调否则 dropout 和 batchnorm 还在训练模式推理结果不稳定。permute(2, 0, 1)是把 HWC 转成 CHWPyTorch 要的是通道在前这一步漏了模型直接报维度错误。torch.no_grad()省显存也提速推理阶段不需要梯度。5. 界面、报告与手动标注让检测结果能被人看懂模型输出一个类别和置信度对工程师够了但对使用者不够。这一章讲ui/和report/怎么把冷冰冰的数字变成能看的界面和报告。5.1 UI 框架与图像项渲染cutting_error_app.py是应用主类ui_main.py是主窗口image_item.py是图像列表项result_panel.py是结果面板。从文件命名看这套 UI 大概率是 PyQt 或 PySide 搭的因为image_item、result_panel这种命名是 Qt 的典型风格。# 伪代码示意按实际 ui_main.py 对照 from PyQt5.QtWidgets import QMainWindow, QListWidget, QListWidgetItem from PyQt5.QtGui import QIcon, QPixmap class MainWindow(QMainWindow): def __init__(self): super().__init__() self.list_widget QListWidget() self.setCentralWidget(self.list_widget) def add_image_item(self, img_path, result_text): # 缩略图做列表图标避免大图撑爆界面 pixmap QPixmap(img_path).scaled(80, 80) item QListWidgetItem(QIcon(pixmap), result_text) self.list_widget.addItem(item)scaled(80, 80)是必须的直接把原图当图标界面会卡到没法用。result_text一般拼上类别和置信度比如「崩边 0.93」让使用者一眼看到结论。manual_annotation.py是手动标注工具用来补样本或修正误检这在毕设里是个加分项说明作者考虑了数据闭环。5.2 报告生成与 HTML 模板填充report/result.py配合source/template.html生成检测报告。思路是把检测结果填进 HTML 模板再渲染成可打印或可保存的文档。OPPOSans-M.ttf是报告用的中文字体缺了它中文会变方块。from string import Template def render_report(template_path, results, out_path): with open(template_path, r, encodingutf-8) as f: tpl Template(f.read()) # results 是列表每项含图片路径、类别、置信度 rows .join( ftrtd{r[name]}/tdtd{r[cls]}/tdtd{r[conf]:.2f}/td/tr for r in results ) html tpl.safe_substitute(rowsrows) with open(out_path, w, encodingutf-8) as f: f.write(html)用string.Template而不是 f-string 拼 HTML是因为模板里有大量 CSS 花括号f-string 会把它们当占位符报错。safe_substitute比substitute宽容缺变量时不会直接抛异常适合模板字段可能不全的场景。{r[conf]:.2f}保留两位小数报告里置信度写一长串没意义。5.3 日志记录与结果追溯log/log.py负责日志。检测系统一定要有日志不然出了问题你连「当时喂的是哪张图、判成了什么」都查不到这就是黑匣子。import logging import os def setup_logger(log_dir./log, namedefect): os.makedirs(log_dir, exist_okTrue) logger logging.getLogger(name) logger.setLevel(logging.INFO) fh logging.FileHandler(os.path.join(log_dir, run.log), encodingutf-8) fh.setFormatter(logging.Formatter(%(asctime)s %(levelname)s %(message)s)) logger.addHandler(fh) return loggerencodingutf-8别省Windows 默认编码写中文日志会乱码。setLevel(logging.INFO)记录常规流程调试时临时改成DEBUG能看到更多细节。日志文件按天切分是更好的做法但毕设级别一个run.log追加也够用。6. 避坑与排查这份毕设跑不起来时先看这几条前面讲的是「怎么用」这一章讲「哪里会翻车」。下面五条是我拆这类毕设工程时最常遇到的每条按现象、原因、解决来写。6.1 权重加载报 size mismatch现象load_state_dict抛size mismatch for ...模型结构对不上权重。原因你改了num_classes或img_size但还在用xbest_model.pth权重形状和模型不匹配。解决要么把配置改回和权重一致要么删掉权重自己重训。改配置前先看model_config.py里的原始值别凭感觉改。6.2 界面能开但检测结果全是同一类现象不管喂什么图输出都是同一个类别置信度还很高。原因预处理和训练时不一致最常见的是归一化方式不同——训练用了 ImageNet 的 mean/std 归一化推理只除了 255。解决把推理的预处理对齐训练脚本逐行比对my_dataset.py里的 transform 和predict.py里的处理差一步都不行。6.3 中文报告显示成方块现象生成的 HTML 报告里中文全是方框。原因模板里引用的字体路径不对或者系统没装OPPOSans-M.ttf。解决确认source/OPPOSans-M.ttf存在模板 CSS 里的font-face路径指向它如果是在别的机器上打开报告把字体一起拷过去或改用系统自带中文字体。6.4 读 TIFF 图报错或图像全黑现象cv2.imread读 TIFF 返回 None 或读出来一片黑。原因TIFF 位深或压缩方式 OpenCV 不支持或者路径含中文。解决路径尽量用英文读图加cv2.IMREAD_UNCHANGED还不行就用tifffile库读进来再转成 numpy 数组喂给 OpenCV。6.5 训练 loss 不降反升现象训练几个 epoch 后 loss 开始震荡上升。原因学习率太大Transformer 对学习率尤其敏感。解决把lr从 1e-4 降到 1e-5 试或者加 warmup 和梯度裁剪。如果数据量很小毕设常见batch size 也别开太大16 甚至 8 更稳。提示排查顺序永远是「先确认环境 → 再确认路径 → 再确认预处理一致性 → 最后才怀疑模型」。绝大多数跑不起来的问题都出在前三步。7. 进阶玩法把这份毕设改成你自己的项目这份工程的价值不只在「能跑」更在「能改」。答辩拿它交差是一回事把它当骨架长出你自己的东西是另一回事。这一章讲几个我实际会用的改造方向以及怎么验证改完没改坏。第一个方向是换检测头。现在model.py里是分类结构输出「有缺陷/无缺陷」。如果你想做缺陷定位把分类头换成检测头比如加个简单的回归分支输出缺陷框损失函数从交叉熵换成分类加回归的联合损失。改完别急着训先用一张图过一遍前向确认输出维度对得上。第二个方向是加传统视觉兜底。深度学习模型对训练集里没见过的缺陷类型会漏检而切割缺陷里崩边、缺角这种形态规整的用传统方法反而稳。常见做法是在check_defect.py里做融合模型判无缺陷但传统边缘检测发现异常梯度的标记为「疑似」交人工复核。这个融合逻辑是这套系统从「demo」往「辅助检测」靠的关键一步。第三个方向是补数据闭环。manual_annotation.py已经给了手动标注的入口你可以把它和检测结果打通——检测置信度低的样本自动进待标注队列标完增量训练。这样系统用得越久越准而不是一直吃老本。验证改造是否成功我一般走三步先用source/no_defect.png确认无缺陷图不被误报再用几张已知缺陷图确认召回没掉最后跑一遍完整流程看报告生成是否正常。三步都过才算改完。改造方向改动文件验证重点换检测头model.py、train.py输出维度、损失收敛传统视觉融合check_defect.py误报率、疑似标记数据闭环manual_annotation.py、train.py增量训练后指标从那以后我每次动这类毕设工程的模型部分都强制先跑一遍无缺陷图做基线再动别的。这个习惯帮我省了无数次「改完不知道是改坏了还是本来就这样」的纠结。希望这份拆解能帮你少走点弯路把这份资源真正用起来。本文还有配套的精品资源点击获取