1. 毕设选题定调:为什么是口罩佩戴检测,以及它的真实难度
每年到了毕业设计选题的季节,总有一批同学在“做点什么有意思的”和“能顺利毕业就行”之间反复横跳。口罩佩戴检测这个方向,恰好卡在了一个非常微妙的位置——它既有足够的技术含量,能让答辩评委觉得你确实做了东西,又不像目标检测新算法研究那样动辄需要折腾几个月还未必有结果。
先说清楚这个东西到底是干什么的。口罩佩戴检测,本质上就是一个目标检测任务:给定一张图片或者一帧视频画面,让模型判断画面里每个人是否戴了口罩,并且把人的位置框出来。如果细分一下,还可以分成两类任务:一类只判断“戴了还是没戴”,输出一个分类结果;另一类需要同时输出人脸位置和口罩状态,也就是检测加分类的联合任务。绝大多数毕设要求的是后者,因为单纯做分类太简单,撑不起一篇论文的体量。
很多同学一听“深度学习”就觉得门槛很高,其实这个选题的友好之处在于,它的技术栈非常成熟。主流的做法无非就是用一个目标检测网络,比如YOLO系列或者SSD,配上合适的骨干网络,在口罩数据集上做微调训练。整个过程不需要你从零发明任何算法,PyTorch框架、预训练权重、公开数据集全都是现成的。你的核心工作在于把整个流程跑通,理解每个环节为什么这么做,然后针对自己的场景做一些优化。
但话说回来,这个题目也绝对没有想象中那么轻松。我见过不少同学在选题时觉得“这不就是调个包吗”,结果卡在数据集清洗、模型训练收敛、以及最后的实时检测演示这三个环节上出不来。口罩检测和通用目标检测最大的不同在于,口罩遮挡了人脸下半部分,模型的注意力会被迫集中到眼睛和额头区域,这对特征提取的要求其实更高。再加上数据集里戴口罩和没戴口罩的样本数量往往不均衡,训练出来的模型很容易出现“戴着口罩的人检测到了,但没戴口罩的人漏检了”这种偏科问题。
所以,这篇博客想做的事情,就是把我自己在这个项目上从零到一的完整过程拆开来讲清楚。不管你是准备拿这个题目做毕设,还是纯粹想练手一个深度学习项目,我都建议你把注意力放在“为什么要这么做”上面,而不是仅仅复制粘贴代码。我踩过的坑、绕过的弯、以及最后总结出的可行方案,都会在后面的章节里逐步展开。
2. 数据集的选择与处理:这一步决定了你后面90%的体验
2.1 公开数据集怎么挑:MAFA之外还有哪些选择
很多人一上来就搜“口罩数据集”,搜到的第一个往往是MAFA数据集。MAFA确实是学术界比较早的口罩人脸数据集,但它有一个问题:标注质量参差不齐,而且很多图片是低分辨率的生活照,直接用的话你的模型会在训练阶段频繁出现loss震荡。我自己第一次用它训练YOLOv5的时候,跑了十几个epoch发现mAP始终在0.5上下徘徊,换成干净数据集之后才恢复正常。
更适合毕设体量的选择,其实是两个方向。第一个是Kaggle上的Face Mask Detection数据集,它包含大约数千张图片,每一张都标注了人脸边界框,并分成三类:with_mask、without_mask、mask_weared_incorrect(口罩佩戴不正确)。第二个选择是自己构造数据集,用公开的人脸数据集(比如WIDER Face)作为基础,然后程序化地给每张脸贴上口罩贴图。这种方式的好处是你能完全控制样本数量和标注质量,坏处是需要一些图像处理编码功底,而且程序生成的口罩和人脸之间的贴合度会影响模型泛化,答辩时容易被追问。
我最终的做法是混合策略:以Kaggle数据集为基础,再补充一部分WIDER Face里的无口罩人脸图片,手动标注或者半自动生成。这样既保证了数据集规模足够(大约一万张左右),又保证了正负样本的相对均衡。
2.2 标注格式转换:VOC、COCO、YOLO三种格式来回折腾的教训
数据集下载下来,第一个坑就是标注格式。Kaggle那个数据集给的标注是XML格式(VOC格式),而YOLOv5训练需要的是TXT格式,每行表示一个目标的类别和归一化坐标。转换脚本本身不难写,但有几个细节容易出错。
以VOC转YOLO为例,核心公式是:
x_center = (xmin + xmax) / 2 / img_width y_center = (ymin + ymax) / 2 / img_height width = (xmax - xmin) / img_width height = (ymax - ymin) / img_height听起来很简单,但如果你用的是某个第三方库解析XML,拿到的不一定是绝对的像素坐标,而是经过缩放的比例坐标,直接套公式就会出现边界框偏移。我的建议是,转换前先随机挑几张图,用可视化脚本把边界框画在图上检查一遍,这一步不要省——它能在一分钟内帮你发现90%的坐标错误。
另外,类别编号一定要先定好,并且和数据集的类别文件(class.txt)保持一致。比如约定0代表with_mask,1代表without_mask,2代表mask_weared_incorrect,那么在标注文件里就按这个编号写。中途改类别顺序是极其痛苦的体验,因为你需要把所有标注文件重新生成一遍。
2.3 数据清洗:删掉那些会让模型“精神分裂”的图片
很多人忽略了这一步,直接拿原始数据开训,结果模型性能上不去还找不到原因。我总结了一下,以下几类图片必须清理或修正:
- 图片里同时存在多个极小的人脸(比如小于图像面积2%的目标)。这类目标对检测器来说噪声远大于信号,要么删掉,要么在训练时用图像缩放强行拉大。
- 标注框明显偏移的图片。比如口罩在人脸上,但框只框住了嘴巴那一小块区域,这类标注会教坏模型。
- 完全被遮挡的极端样本。比如人脸只有三分之一露出来,人眼都难以判断是否戴口罩,这类样本对毕设没有太大价值。
- 分辨率极低的模糊图片。低分辨率图片会导致上下采样过程中特征丢失,尤其在MobileNet这类轻量骨干上表现更明显。
数据清洗完成后,一定要重新统计一下每个类别的样本数。如果发现某个类别特别少,就要做数据增强或者补充数据,不然后面训练出的模型会在那个类别上表现得很差。
3. 模型选型与训练配置:从YOLOv5到轻量化改造的完整对比
3.1 为什么选YOLOv5而不是Faster R-CNN或者SSD
毕设项目里,选目标检测框架时你最需要考虑的不是“哪个精度最高”,而是“哪个最容易调通、资料最多、部署最方便”。在这个前提下,YOLOv5几乎是当前的最优解。YOLOv5提供了从n到x的五个版本,n版本模型文件极小,非常适合CPU推理演示,而x版本精度较高但显存占用大。Faster R-CNN虽然是两阶段检测器里的经典,但它在端到端的训练和部署便利性上远不如YOLO系列,对新手不友好;SSD则相对老旧,公开的预训练权重和资料都不如YOLO系列丰富。
从精度指标上看,在标准的口罩检测数据集上,YOLOv5s的mAP可以做到0.89左右,YOLOv5m可以接近0.93,对于毕设场景已经足够。更关键的是,YOLOv5支持在训练过程中直接输出各类曲线图,包括PR曲线、混淆矩阵、以及各个类别的具体AP值,答辩展示非常直观。
3.2 骨干网络怎么选:从标准CSPDarknet到MobileNetV3的取舍
YOLOv5默认的骨干网络是CSPDarknet,它兼顾了速度和精度。但在毕设里,很多同学会遇到一个现实问题:实验室没有好显卡,或者答辩现场要用CPU跑实时检测。这时候就需要考虑更换轻量骨干网络。
我实际测试过三种方案:
| 骨干网络 | 模型大小 | 推理速度(CPU) | mAP@0.5 | 显存占用 |
|---|---|---|---|---|
| CSPDarknet (YOLOv5s) | 约14MB | 约60ms/帧 | 0.89 | 约4GB |
| MobileNetV3 替换骨干 | 约8MB | 约35ms/帧 | 0.82 | 约2GB |
| ShuffleNetV2 替换骨干 | 约6MB | 约30ms/帧 | 0.78 | 约2GB |
如果你的项目要求是“在普通笔记本上能流畅运行”,我建议直接用YOLOv5n或者将骨干换成MobileNetV3。精度下降确实存在,但换来的是流畅的演示体验,这在答辩现场的价值远高于那零点几个点的mAP提升。毕竟评委看到的是你屏幕上的实时画面,而不是一张事后打印出来的精度表。
3.3 训练超参配置:批量大小、学习率、训练轮数的实践经验
训练超参这一块,很多教程会给一套默认配置,但实际训练时一定要根据你的显卡显存做调整。以下是我用单张显卡(8GB显存)训练YOLOv5s时的参数配置:
epochs: 100 batch_size: 32 img_size: 640 optimizer: SGD lr0: 0.01 momentum: 0.937 weight_decay: 0.0005batch_size为32在8GB显存下可能会显存溢出,如果爆显存,直接减半到16就可以了。关于学习率,YOLOv5内置了余弦退火调度器,即使初始学习率设置得稍微激进一点,训练后期也会自动调小,所以不用太担心。我建议先跑20个epoch热身,观察loss曲线如果稳定下降,再继续训练;如果loss震荡剧烈,优先考虑减小学习率而不是增大batch。
另外,数据增强默认是开启的,包括马赛克增强(mosaic)、随机翻转、色调变化等。对于口罩检测来说,马赛克增强的作用很大,它能让模型对小目标更鲁棒,所以不建议关闭。但如果数据集中人脸尺寸普遍较大(占比超过图像面积的10%),马赛克增强反而会让小目标样本变多、训练变慢,这时候可以将mosaic概率从1.0降到0.5。
3.4 训练过程中的隐性问题:过拟合、偏置与类别不平衡
口罩检测最典型的偏置问题,是模型倾向于把所有没戴口罩的人识别为“戴着口罩”。原因很简单:训练数据里戴口罩的样本数量占多数,模型学会了“偷懒”——一律预测with_mask就能获得很高的准确率。这就是类别不平衡的典型表现。
解决这个问题有几个可行手段。最简单的是调整类别权重,在损失函数中给样本数量少的类别更高的权重。YOLOv5的cls_loss中可以通过参数来控制,但更直接的方式是重新划分训练集,人工将正负样本比例控制在一定范围内,比如1.2:1到1.5:1之间,而不是让网络自己去适应严重倾斜的数据分布。我在实践过程中,把数据重采样到大致均衡之后,without_mask类别的AP提升了约13个百分点。
过拟合问题相对隐蔽。由于毕设数据量通常只有几千张到一万张,训练到后期(80个epoch以后)会出现训练loss继续下降但验证loss开始反弹的迹象。这时候有两种选择:一种是在loss曲线出现拐点的地方提前终止训练;另一种是增加正则化强度,比如增大weight_decay到0.001。我的经验是,对于一个小型数据集,训练60到80个epoch通常已经足够,盲目追求100个epoch以上反而容易过拟合。
4. 推理端的鲁棒性处理:遮挡、光线和真实场景下的翻车实录
4.1 最小人脸尺寸与置信度阈值的联调
训练好模型之后,大家最喜欢做的一件事是拿自己手机里的自拍照测试。这时候模型往往会给人一个惊喜——识别是能识别,但置信度忽高忽低,甚至会把一张侧脸照片里的耳朵当成人脸。原因在于推理端的输入尺寸和置信度阈值没有针对你的使用场景校准。
YOLOv5推理时默认的置信度阈值是0.25,对于毕设演示这种追求少漏检的场景,建议提高一点,比如0.35到0.4。这样做会牺牲一部分对低质量人脸的召回率,但能显著减少误报。同时,输入图像的缩放尺寸(imgsz参数)也直接影响到小脸检测效果。如果你在演示时用手机摄像头拍摄,人脸在画面中占的比例可能只有百分之十几,此时把imgsz从640提高到768,小脸的召回率会有明显提升,代价是推理速度变慢。
我整理了一组不同条件下的实测数据,供大家参考:
| 测试条件 | imgsz=640, conf=0.25 | imgsz=640, conf=0.4 | imgsz=768, conf=0.4 |
|---|---|---|---|
| 正脸清晰、距离3米 | 1.0 | 1.0 | 1.0 |
| 侧脸、光线较暗 | 0.81 | 0.72 | 0.86 |
| 低头玩手机、口罩遮住半张脸 | 0.68 | 0.55 | 0.74 |
| 多人场景、后排小脸 | 0.58 | 0.46 | 0.69 |
可以看到,提高输入尺寸带来的收益比降低置信度阈值更明显。但768的输入尺寸在CPU上推理会吃紧,如果你用的是GPU,则完全无压力。
4.2 光线与肤色干扰:模型没你想的那么坚强
一个非常容易被忽略的现实问题是,模型在室内正常光线下训练出来后,拿到室外强光或昏暗环境测试,性能会出现明显下跌。口罩检测器的特征很大程度上依赖边缘和纹理信息,强光下人脸区域容易过曝,口罩边缘的轮廓会被光线“吃掉”,这时候检测框就会漂移甚至完全丢失。
针对光线变化,我的做法是做一个简单的图像预处理模块,在送入模型前进行自适应直方图均衡化(CLAHE)。这个操作在OpenCV里面只需要几行代码:
import cv2 def preprocess_frame(frame): lab = cv2.cvtColor(frame, cv2.COLOR_BGR2LAB) l, a, b = cv2.split(lab) clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) l = clahe.apply(l) lab = cv2.merge((l, a, b)) return cv2.cvtColor(lab, cv2.COLOR_LAB2BGR)需要注意的是,预处理会增加每帧几毫秒的耗时,但换来的是对光照变化的适应能力,在答辩现场用手机投屏演示时效果非常明显。当然,我并不是建议把图片处理得完美再丢给模型——如果原始画面的光照本身正常,直接推理就行;只有检测结果不稳定的时候才需要启动这个预处理分支。
4.3 视频流检测的掉帧问题:从单帧检测到跟踪器的进化
做实时演示是毕设里的高光时刻,但也是翻车现场重灾区。最常见的翻车是画面卡顿,原因在于每一帧都运行完整的检测网络,哪怕是GPU推理也有几十毫秒延迟,CPU推理更是要达到上百毫秒一帧。
一个实用的优化思路是:不必要对每一帧都做检测,而是引入一个轻量级跟踪器。当某一帧检测到人脸后,下一帧直接在上一帧目标框附近的小区域内搜索,只有目标丢失或者新目标出现时才重新全局检测。具体做法可以使用OpenCV内置的Tracker或者更轻量的排序算法。我用的是简单的IOU匹配加卡尔曼滤波,将检测频率降到每5帧一次,中间4帧通过跟踪结果补全位置,整体流畅度提升了大约两倍。
当然,跟踪器会引入新的问题——当检测结果暂时丢失时,跟踪框的漂移。这时候需要设置一个跟踪失效时间(比如0.5秒),超过这个时间没有重新检测到目标,就认为目标真正消失了,而不是继续输出一个不可靠的预测框。
5. 项目背景与原创性的包装思路:让答辩评委觉得你“真的懂”
5.1 从“应用型检测”到“针对特定场景的优化”:一个可复用的叙事框架
毕设论文和项目本身是两回事。项目代码可能只用了现成的算法框架,但论文必须讲清楚“你的工作为什么有价值、你的创新点在哪里”。对于口罩佩戴检测,直接写“我用了YOLOv5训练了一个检测器”是拿不到高分的,但如果你把叙事角度聚焦在“特定场景下的性能优化”,就有了可挖掘的空间。
我选择的角度是“面向低分辨率监控画面中多人脸口罩佩戴检测的优化”。具体来说,原始YOLOv5在大尺寸人脸检测上效果很好,但在低分辨率监控场景下对小脸的检测能力不足。我的工作重点变成了:
- 在数据层面,模拟低分辨率监控画面的退化过程(模糊、缩放、压缩噪声),制作了一个低分辨率增强数据集。
- 在网络层面,针对小目标检测设计了额外的检测层,也就是在原本的三个检测尺度基础上增加一个用于小目标的检测头,并在对应的特征图上加深浅层特征的融合。
- 在损失函数层面,调整了不同尺度预测框的损失权重,让模型更关注小目标的分类和回归精度。
这样一来,整个工作的叙事逻辑就很清晰:问题定义非常明确、技术路线层层递进、实验结果有对比有提升。而这一切并不需要你真的去发明新算法,只需在现有框架内做合理调整。
5.2 对比实验怎么设计才够说服力
答辩评委最看重的,除了你的系统演示,就是实验对比的严谨性。很多同学只是给出最终模型的mAP,然后画一条loss曲线,这样的实验设计是远远不够的。
一套有说服力的对比实验应该包含:
- 基线模型(YOLOv5s原版)与你的改进模型的性能对比,指标至少包括mAP、精确率、召回率、推理时间。
- 消融实验。比如你的改进包含A、B、C三个点,那么要分别训练出“无A”“无B”“无C”和“全包含”的模型,通过对比说明每个改进点的贡献。
- 不同骨干网络的横向对比,至少给出轻量骨干与标准骨干在精度和速度上的取舍关系。
- 在测试集上进行鲁棒性测试,比如加入不同噪声级别、不同模糊程度后的性能变化曲线。
做这些实验的数据量并不大,但能显著提升论文的工作量观感。关键是实验记录的细节要完整,比如训练轮数、数据集划分比例、随机种子都要写清楚,这样才能让评委觉得你的实验是可靠的。
5.3 源码组织的建议:可读性比炫技重要
最后说一个不那么学术但非常实际的话题——代码结构。毕设的代码仓库不要求你写成工业级的项目,但至少要让人能看懂。我的建议是分成以下几个目录:
- src/data/:数据集预制与增强相关代码。
- src/models/:模型定义与修改的代码。
- src/train/:训练入口、训练参数配置文件。
- src/inference/:单图推理、视频流推理、摄像头实时演示代码。
- src/utils/:通用工具,比如标注格式转换、可视化工具、统计脚本。
- experiments/:不同配置下的训练输出,包括权重文件和日志。
README文件里写清楚环境依赖、数据集下载地址、运行步骤。不要小看这一步,答辩前如果你需要临时在另一台电脑上跑演示,一个好的README能帮你节省大量时间。
6. 从训练到部署:把模型真正跑起来的完整链路
6.1 硬件环境不理想时的应对策略
我知道很多同学手头只有一台普通的笔记本,没有独立显卡或者只有集显,训练跑不动怎么办。这里提供几条实际可走的路线:
- 用云GPU平台的免费额度。很多云服务商会给新用户提供一定时长的免费GPU实例,虽然只有几个小时,但对于微调一个预训练模型来说可能也够跑几十个epoch。需要注意的是,数据要先上传到云平台,这也可能花不少时间,建议先把数据集压缩成单个文件再上传。
- 使用Colab。如果你能稳定连接服务,Colab的免费GPU(通常是Tesla T4)足够训练YOLOv5s模型。代价是session会超时断开,需要定期保存模型权重到云盘。
- 降低模型复杂度和输入尺寸。例如使用YOLOv5n,图像尺寸从640降到480,在一个中等CPU上训练40个epoch也是可行的,只是时间稍长一些。
无论哪种方式,训练过程中的重要节点都要保存模型权重。我习惯每10个epoch保存一次,最后再保留一个best.pt,这样即使中途出现意外,也不需要从零开始。
6.2 ONNX导出与CPU加速推理
训练完成后,如果希望在答辩现场不依赖GPU也能跑实时检测,ONNX Runtime是一个稳定成熟的方案。把PyTorch模型导出为ONNX格式的代码很简单:
import torch model = torch.load('best.pt', map_location='cpu')['model'].float() model.eval() dummy_input = torch.randn(1, 3, 640, 640) torch.onnx.export( model, dummy_input, 'mask_yolov5n.onnx', opset_version=12, input_names=['images'], output_names=['outputs'] )导出后可以用ONNX Runtime加载,推理速度比PyTorch的CPU模式快不少。如果机器上有集成显卡且支持OpenVINO,那么用OpenVINO的IR格式推理还能进一步提速。就我实测,在一台普通轻薄本上,YOLOv5n配合ONNX Runtime可以达到大约30毫秒每帧,也就是接近实时。
6.3 摄像头实时监控系统的几个细节设计
做一个完整的摄像头检测系统,除了模型本身,还有几个很影响体验的细节:
- 画面中的检测提示区域扣板。很多人一拿到检测结果,就直接把框画在原始视频上,这样的视觉效果非常干瘪。稍微改进一下,可以在检测框上方加一个半透明的浮层,显示“已佩戴口罩”或“未佩戴口罩”的文字和图标,看起来立刻专业不少。
- 连续帧的决策缓存机制。如果某一帧检测到未佩戴口罩,不要立刻弹窗报警,而是等待连续3到5帧都检测到未戴口罩才触发告警。这样可以大幅减少因为帧间检测抖动造成的误报。
- 视频保存功能。答辩系统演示完,把过程中的检测结果视频保存下来,作为论文附录的补充材料,比口头描述要有说服力得多。
7. 常见错题集:链路的坑,每一条都是我流量过的流量
7.1 训练数据与验证数据同源导致的“95分假象”
很多同学在划分数据集时随意使用随机切割,没有考虑同一张图片可能在训练集和验证集中都出现过的情况。尤其当数据集来源本身就是同一拍摄批次时,模型会对这批图片产生记忆,验证集上指标虚高,一旦换一批真实环境图片就原形毕露。
正确的做法是按照拍摄场景或者时间段划分数据。比如某个视频序列被切分成多帧图片,那么整个序列都应该放在同一个集合里,不能让训练期间看到同一动作序列的“未来帧”。这一点在答辩时如果被问到,也是体现你数据处理能力的一个细节。
7.2 Loss值不下降时的排查顺序
如果训练过程中loss长期不下降,通常不是模型结构的问题,而是数据或超参的问题。我的排查顺序是:
- 检查数据加载器,可视化一批训练图片和对应的标注框,确认标注没有错乱。
- 检查损失值数量级。如果初始loss异常高,可能是在模型加载预训练权重时,类别数不匹配导致最后的检测头被随机初始化。
- 降低学习率到原来的十分之一,重新跑几十个迭代,观察loss是否有下降趋势。
- 尝试关闭数据增强,纯粹用原始数据跑少量迭代,验证模型本身能否在干净数据上过拟合。
这套排查流程是定型的,90%的问题都能在这四步之内定位出来。
7.3 一个很反常但实际常见的坑:提前终止训练导致的“最低验证loss不是最好模型”
你可能会发现在某个epoch验证loss达到最低点,但用这个checkpoint做推理时,检测效果反而没有后面的某个checkpoint好。原因是验证loss是在验证集上按像素比例计算的指标,它和实际目标检测的mAP指标之间并不完全等价。所以建议在训练结束后做一次多checkpoint的mAP测试,挑选在测试集mAP上表现最好的权重,而不是只看验证loss曲线。这个经验在训练后期尤其重要。
7.4 不同类别的AP差异过大的处理建议
训练完第一次模型,打印出每个类别的AP值,最常见的情况是“正确佩戴口罩”类AP很高,而“未佩戴口罩”类AP偏低。这背后是两个原因:一是未佩戴口罩时人脸特征更复杂(嘴型、胡须、肤色、遮挡物等变化大),二是样本数量不足。处理方法是增加该类别的样本占比到40%以上,同时可以考虑对未佩戴口罩的人脸做更强的平移缩放增强,让模型见识更多变化。
8. 最后分享一个提分细节:如何准备一个让人眼前一亮的Demo
答辩现场最加分的环节不是论文本身,而是你的实时演示。一个让人舒服的Demo,通常会有以下几类设计:
首先,准备一个三级场景切换:清晰正脸视频、多人画面、以及低光照或侧脸场景。每个场景切换时,页面上的检测指标(当前fps、置信度、漏检率)要能实时变化,这样评委才能直观感受到你的模型在不同条件下的表现差异。
其次,设置一个“翻车按钮”是禁忌,但准备一个“挑战案例”是加分项。你可以事先准备一两张你模型识别效果最差的图片(比如戴着口罩但露出鼻子的照片、或者极暗光线下的人脸),在演示的最后阶段展示出来,并解释为什么这类样本困难、你做了哪些尝试来缓解。这种诚实而专业的处理方式,往往比一路完美的识别效果更让评委印象深刻。
最后,Demo代码里一定要有一段关键逻辑的注释,用于应对评委的“这里是怎么实现的”追问。不用长篇大论,而是在核心函数附近写上一两句话,说明输入输出是什么、用了什么策略。这能让你在紧张的答辩氛围下迅速找回思路,不至于被评委问得一问三不知。
口罩佩戴检测这个毕设题目,说难确实有一定技术深度,说简单也确实是现有工具箱就能完成的工程任务。关键在于你要把每一个环节的原理吃透,遇到问题时不慌不忙地按逻辑排查,最后把过程完整地沉淀在论文和代码里。做到这些,你收获的不仅是一个能通过的毕设,更是一套可以迁移到任何视觉任务上的完整问题解决思路。