每年毕设季节,都有学弟学妹来问我:想做一个图像方向的计算机毕设项目,最好能和医疗场景沾点边,听起来有应用价值,工作量又不能大到做不完,答辩时还能讲出几个技术点。我一般都会推荐“静脉输液液位检测系统”这个方向。题目标签里有大数据深度学习,有计算机毕设答辩,核心其实就是把深度学习模型用在一个非常具体的医疗场景里:监测输液过程中滴壶或输液瓶的液位变化,低于阈值时自动报警。这个题目看起来很“垂直”,但拆开看,它涵盖了数据采集、标注、模型选型、训练调参、上位机部署、报警逻辑设计,再到答辩讲解的完整链路,非常适合作为计算机专业的毕业设计。
这篇文章我就围绕这个毕设项目,把我自己做产品原型时的完整思路、选型原因、踩坑过程和技术细节全部写出来。无论你是正在选毕设题目的大四学生,还是想快速上手一个视觉检测落地项目,都可以把这套流程拿过去参考。
1. 为什么我把液位检测做成了视觉问题:三种技术路线的取舍
1.1 先搞清输液场景真正要解决什么
一提到输液液位检测,很多人第一反应就是“液没了,提醒护士换瓶”。但如果只是做这个,那用最便宜的红外对管传感器就够了,根本不需要深度学习。真正让这个题目变得有价值的是下面几个需求:
第一是连续监测。护士不可能一直盯着每一瓶液体的剩余量,尤其是夜间病房,灯光昏暗,值班护士需要快速知道“哪一床快输完了”“大概还能撑几分钟”。这时候只靠“有没有液”是完全不够的,需要计算出液面的连续高度或者剩余量。
第二是滴速估算。有时候液面还有,但滴壶里很久没有液滴落下,说明管路可能堵塞、针头移位或者输液泵故障,这比“没液了”更危险。
第三是异常状态报警。回血、气泡进入管路、液面过低,这些都属于异常情况,报警要足够及时,还要避免误报。
如果你去看实际医院里的输液管理,就会发现护工和护士最头疼的不是换瓶,而是信息不对称。做完需求分析之后我确定了系统的核心指标:液位高度实时估算、剩余时间预测、低于阈值声光报警,同时要能在普通笔记本电脑上流畅运行。正是这套需求,让我放弃了最简单廉价的传感器方案,转向了视觉检测。
1.2 红外对管、称重传感器、摄像头方案对比
我一开始并没有直接上深度学习,而是把市面上的方案都捋了一遍。这个环节在毕设答辩里也很重要,因为老师一定会问“你为什么不用某某方案”,你需要给出有理有据的回答。
| 对比维度 | 红外对管 | 称重传感器 | 摄像头加深度学习 |
|---|---|---|---|
| 硬件成本 | 很低 | 中等 | 较高,需要摄像头和算力设备 |
| 能否连续测液位 | 不能,只能测固定位置 | 能,但精度受振动影响大 | 能,可计算连续液面高度 |
| 抗干扰能力 | 一般,药液颜色、气泡都会干扰 | 较差,患者移动和管路晃动会产生噪声 | 较好,数据增强后泛化能力强 |
| 可扩展性 | 差,改一个位置就要重新装传感器 | 差,称重机构不好布置 | 好,可做多床位、Web端远程报警 |
| 毕设工作量 | 偏小,代码量很少 | 偏小,偏硬件 | 中等偏上,但技术点丰富 |
| 答辩表现力 | 弱 | 弱 | 强,能讲检测模型、部署、优化 |
红外对管方案的原理很简单:发光管和接收管卡在滴壶两侧,当液面低于某个位置时光路发生改变,输出一个电平跳变。优点是真的便宜,十几块钱就能做出来,但它只能告诉你“到这里了”,不能告诉你“还剩多少”,更算不出剩余时间。而且药液颜色深、液体浑浊、滴壶壁有气泡或者水珠时,误报率很高。
称重传感器方案是用拉力传感器挂住输液瓶,通过重量变化反推剩余液量。理论上很直接,但实际做过的人都知道,输液管的牵拉、患者手臂移动造成的管路晃动、甚至瓶内液体晃动都会让重量读数漂移。要在实验室环境下稳定工作,需要用滤波算法反复调参,工作量全耗在了信号处理上,整个项目学不到太多视觉内容。
摄像头视觉方案最大的优势是非接触、信息量大。一帧画面里同时包含滴壶液位、输液瓶瓶身、管路气泡等信息,通过深度学习模型可以一次性提取这些状态。我的结论是:如果只是应付毕设,红外对管最简单;但如果你想让项目在答辩时站得住脚,有东西可讲,视觉方案是性价比最高的选择。
1.3 传统图像处理输在哪里:阈值分割的鲁棒性陷阱
确定了视觉方案之后,还有一条分支路:用传统OpenCV图像处理,还是用深度学习模型?我做过对比实验,最终才下定决心走深度学习路线。
传统做法通常是这样的:把摄像头画面转成HSV颜色空间,用颜色范围阈值把液体区域从背景中“抠”出来,再数白色像素的高度,除以滴壶区域的总高度,得到液位百分比。这套流程在理想光照下确实能跑通,我第一次试验时只写了不到100行代码,就能在实验室台灯照明下输出准确的液位。
但问题出在“换一个环境就失效”。日光灯下液体反光,瓶身有标签、塑料褶皱、水滴附着,这些都会让颜色阈值瞬间崩掉。我在测试集里加了逆光场景和深色药液之后,传统方案的准确率直接从90%掉到了40%左右。这时候我才意识到:传统方法是在“手动定义什么叫液体”,而深度学习是在“从大量样本里学液体在各种光照下长什么样”,后者的泛化能力完全不同。
另外还有一层考虑:题目标签里写了“大数据深度学习”,那项目就该匹配这个技术方向。我不建议毕设里强行堆一个百万级数据集去“证明大数据”,而应该利用深度学习领域已有的预训练权重,在自采的小规模数据集上做微调。几百张图、训练一晚上,就能得到一个在真实场景里可用的模型,这也是目前工业视觉落地最常见的方式。
2. 检测目标与模型选型:先想清楚再动手
2.1 检测滴壶、输液瓶还是滴速:目标决定难度
在做模型之前,我花了整整一个晚上想“到底要检测什么对象”。这个决策直接决定了后面的数据标注量和模型复杂度。我列了三种候选:
第一种是检测滴壶里的液滴下落。滴壶是输液管中间那个透明的葫芦形观察窗,液体一滴一滴地落下去。如果能检测到每一滴,就能算滴速,进而判断输液是否通畅。这个目标做起来不难,用目标检测框出“正在落下的小液滴”就可以了,但它只能测滴速,测不出剩余液量,系统价值少了一大块。
第二种是检测输液瓶里的液面高度。输液瓶通常是半透明塑料材质,液面线相对清晰,理论上可以直接检测。但实际上,瓶身有刻度线、标签纸、褶皱和反光,液面特征非常不稳定,标注成本高,模型训练难度也大。
第三种是检测滴壶内的液柱或液面位置。滴壶的上半部分是空气,下半部分是液体,液面在透明腔体内非常清晰。当滴壶内液面低于某个高度时,说明药液基本耗尽,哪怕输液瓶还有一点底液,管路也随时可能进空气。这个目标视觉特征稳定,标注简单,而且和临床最关心的“回血”“进空气”风险直接相关。
最终我选定滴壶作为主检测区域。从视觉角度讲,滴壶是一个“干净的背景加清晰的液面”,模型学起来容易;从临床逻辑讲,滴壶液位低,是全局最值得报警的指标。这个取舍后来在答辩时被老师追问过,我的回答是“检测目标应该选择场景中最稳定、最能反映系统状态的特征区域,而不是想当然地检测最大的目标”,这个回答帮我拿了不少印象分。
2.2 检测器、分割网络还是“检测+分割”二合一
检测目标确定之后,接下来是模型选型。这里有一个很多毕设新手容易犯的错误:一上来就直接用目标检测网络,框一个目标框就当作交付。实际上,针对液位检测这个任务,单纯的目标框只能告诉你“滴壶在哪”“液体大概在哪个区域”,没法精确算出一个百分比数值,因为方框里还混着很多非液体的背景像素。
我当时对比了几类模型的适用场景:
- 目标检测模型(YOLO系列):速度快,能输出物体边界框和类别,适合“定位物体”的场景,比如行人、车辆、缺陷框选。用在液位检测上,只能做粗略判断。
- 语义分割模型(U-Net、DeepLabV3+):对每个像素分类,能把液面区域精确“抠”出来,计算液位高度很方便,但边界框信息弱一些。
- 带分割头的检测模型(YOLO系列的分割版本):一个模型同时输出边界框和像素级掩码,兼顾定位和精细分割。
我最后选的是带分割头的检测模型。这么做有三个原因:一是输出的信息量足够,界面上既能画出滴壶区域框,又能把液体区域用带色掩码标记出来,演示效果直观;二是液位百分比的计算非常方便,用液体掩码面积除以滴壶矩形区域面积就能得到连续比例;三是模型规模不大,班里的普通笔记本也能跑。
选型时我还考虑了推理速度。用语义分割网络对整幅图做像素分类,在CPU上很容易跑到几百毫秒一帧,而带分割头的检测模型只对候选区域做掩码预测,速度要快得多。优先级排序应当是:先保证实时性,再追求更精细的分割效果。毕竟在输液监测场景里,画面卡顿会导致报警延迟,这是系统不能接受的。
2.3 600张图的数据集怎么做:采集、标注与增强
数据集是整个项目里最“脏活累活”的部分,但也是答辩时最有说服力的环节。我的采集方式很简单:在宿舍搭了一个简易输液架,挂上输液瓶,用手机和USB摄像头在不同时段采集视频,然后抽帧成图片。
采集时要尽量覆盖真实场景的变化:白天自然光、晚上日光灯、逆光、侧光,药液用透明液体、淡黄色液体和深色液体各录几段;滴壶状态从满液到空液逐步变化,中间状态多录一些。最终我从视频里抽出了约600张有效图片,按7比2比1分成训练集、验证集、测试集。
标注工具用的是开源标注工具LabelMe,我只需要标注两类目标:滴壶区域和液体区域。这里有一个容易出错的地方:液体区域不能只标滴壶下半部分的大块液体,还要把附着在滴壶壁上的细水滴也简单标上。一开始我只标大块液体,结果模型把细水滴全部漏掉了,在测试集上液位计算结果偏低。后来补标了细水滴,准确率明显上升。
数据增强是这个项目提升鲁棒性的关键。我用的是随机亮度、对比度、饱和度抖动、水平翻转、小角度旋转、随机裁剪和轻微模糊。尤其是亮度抖动,我把范围调得很大,相当于模拟了从强日光灯到昏暗夜间的各种光照。分割模型对光照特别敏感,如果增强参数太保守,换一个房间就掉精度。
我个人的经验是:数据量不需要太大,但要保证状态覆盖度。600张图如果全是“满液”和“空液”两个极端,模型看起来指标很好,一到中间液位状态就乱猜;相反,如果把30%的数据放在中间状态,模型对“液面从高到低变化”的过程会学得更扎实。这个思路不仅适用于输液,其他视觉检测项目也一样。
2.4 标注时最容易忽略的细节
标注过程看起来机械,但有几个细节直接影响模型效果。第一个是“遮挡关系”,当输液管从滴壶上方垂下时,会在滴壶区域形成一条黑色管状阴影,如果标注时不把这个阴影区域也纳入液体掩码的上下文理解中,模型容易把阴影误判为液体,导致液位虚高。
第二个是“反光”,透明滴壶在灯光下会出现一个高亮区域,这段高光区域的像素值非常接近背景。需要人为把高光区域补标成液体,哪怕肉眼看起来它“不太像液体的颜色”。因为模型学的是液体的形状和上下文,而不是纯颜色。如果光伏区域漏标了,训练时它会被当成背景噪声,推理时就会在液体中间“开洞”。
第三个是“类别不平衡”。滴壶空液状态在真实采集视频里占比很少,如果训练集里空液样本只有十几个,模型会倾向于把空液也预测成有液。我当时的做法是把空液状态单独多采集几段视频,并且用随机裁剪增强让模型见过更多空壶纹理。标注这个环节,实际上决定了模型能力的上限,后面调参只能弥补小部分问题。
3. 训练调参与部署:让模型真正跑在输液场景里
3.1 一个实际的训练参数配置与loss观察
训练参数这块,网上很多教程给的是默认值,我建议不要盲目照搬。我的实验环境是普通笔记本加一块入门级GPU,模型参数量在7M左右,属于轻量级,训练一个晚上就能收敛。
我用的关键参数如下:
| 配置项 | 数值 |
|---|---|
| 训练集 | 480张 |
| 验证集 | 120张 |
| 输入分辨率 | 512×512 |
| Batch size | 8 |
| 优化器 | AdamW |
| 初始学习率 | 0.0001 |
| 训练轮数 | 120轮 |
| 学习率调整 | 余弦退火,最后30轮降到最低 |
| 验证集IoU | 0.84 |
| 检测mAP | 0.92 |
| GPU单帧推理 | 约15ms |
| CPU单帧推理 | 约120ms |
有几个细节我想重点提醒。
输入分辨率不是越高越好。输液滴壶在整个画面中的占比并不小,512×512已经足够,再提高到1024会明显拖慢推理速度,IoU却只提高不到1个百分点。对于实时监测系统,帧率优先。
早停法一定要用。我在80轮左右时验证集IoU已经到了0.83,后面继续训练训练集loss继续下降,但验证集指标开始波动,说明开始过拟合。设置patience为20轮,观察到验证集不再提升就停止,最终模型停在102轮,比完整跑完120轮效果好。
观察训练曲线时不要只看总loss。对分割任务要同时看验证集IoU和mAP,如果两者走势不一致,说明模型在不同类别上的能力不平衡。我发现一个现象:当IoU持续上升但mAP停滞时,往往是边界框回归还不够准,这时候需要调高边界框回归损失的权重,而不是继续盲目降学习率。
3.2 报警逻辑别只靠单帧判断:阈值与防抖
模型训练好之后,下一步就是把它接进完整的检测循环里。很多人以为“做出来了模型就完事”,实际上报警逻辑才是让系统看起来智能的关键。
我设计的流程是这样的:读取一帧画面,模型输出滴壶框和分割掩码,然后计算“液位百分比”等于液体掩码面积除以滴壶框面积。当百分比低于20%时,判定为低液位;低于10%时,判定为紧急低液位。但这里有个问题:单帧预测存在抖动,偶尔某一帧没有检测到液体,百分比突然掉到0,如果不加处理就直接触发报警,系统会经常误报。
解决办法是加了一个状态机式的防抖窗口。连续5帧都低于20%才触发低液位报警,连续3帧都低于10%才触发紧急报警;一旦某帧液位回到阈值以上,计数器立即清零。这样做之后,误报次数从一天十几次降到了几乎为零。在毕设演示时,这个设计完全可以作为一个小亮点讲给老师听,它说明你不只是会调用模型,还考虑了系统的工程稳定性。
置信度阈值也要单独调试。模型对每一帧会输出一个置信度,我一开始把阈值设成0.6,结果遇到稍微模糊的画面,滴壶框直接被过滤掉,液位检测全部失效。后来根据验证集上的置信度分布,把阈值降到0.35,漏检率才恢复正常。原则是:宁可多输出一些候选框,再靠空间位置过滤,也不能让置信度阈值过滤掉真实目标。
3.3 上位机界面与摄像头调用要点
一个完整的毕设系统不能只有模型推理脚本,还需要一个让用户看得懂的操作界面。我用的是PyQt5,主窗口左边放实时摄像头画面,画面里叠加滴壶框和液体掩码,右边显示当前液位百分比、剩余时间估算、报警状态和运行日志。
核心循环的逻辑可以参考下面这段伪代码:
# 核心检测循环伪代码 cap = cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) alarm_frame_count = 0 while True: ret, frame = cap.read() if not ret: continue result = model.predict(frame) # 检测滴壶+分割液面 drop_box = result.detect_drip_chamber() # 获取滴壶区域 liquid_percent = result.calc_liquid_ratio() # 液面面积占滴壶框比例 if liquid_percent < 0.20: alarm_frame_count += 1 else: alarm_frame_count = 0 if alarm_frame_count >= 5: # 连续5帧触发报警 trigger_alarm(liquid_percent) ui.update_frame(frame, drop_box, liquid_mask) ui.update_percent(liquid_percent)摄像头分辨率一定要手动固定。默认分辨率在笔记本上往往是1280×720甚至更高,模型推理根本跟不上。把分辨率固定到640×480后,CPU推理可以稳定跑到接近实时,GPU下更是毫无压力。如果使用的是USB摄像头,还可以设置曝光模式为固定值,避免自动曝光导致画面明暗频繁跳动,这对模型预测稳定性影响很大。很多新手在演示时画面一抖一抖的,拉出来看就是自动曝光和自动白平衡在作怪。
界面上的“剩余时间估算”我用了一个很简单的公式:先测量过去60秒内液位百分比下降了多少,再用剩余百分比除以下降速率得到剩余时间。这个方法很粗糙,但在演示场景里完全够用,比做复杂数学模型更实用。如果液位不下降或者上升(比如换瓶),界面要提示“液位无变化,请检查输液状态”,这也是一个隐藏的加分细节。
3.4 推理卡顿怎么办:输入尺寸与线程优化
如果你的笔记本性能比较弱,模型推理卡顿很常见。我踩过这个坑,最后总结出三个有效的优化手段,按成本从低到高排列。
第一个是缩小输入尺寸。从512降到416或者384,推理速度能提升30%到50%,代价是IoU下降一到两个点。如果输液滴壶在画面中占比本来就不小,这个代价可以接受。
第二个是限制检测类别数量。检测模型如果在全类别数据集上预训练,推理时仍然会对所有类别做语义评估。微调时可以只保留需要的类别,或者干脆在导出模型时把类别数压缩到1到2类,能省下一部分计算量。
第三个是用多线程把采集和推理分开。摄像头读取用单独的线程,推理在主循环里独立进行,即使某帧推理稍微慢了,也不会阻塞画面显示。这个优化可以让用户体验提升一大截,代码复杂度的增加却很小。
如果这些手段都用上了仍然卡,那就说明这台设备确实不适合跑视觉模型,建议换一台带GPU的电脑。实验环境里卡顿不算问题,但答辩现场卡成PPT就非常影响效果,所以提前在演示设备上做压力测试是必须的。
4. 答辩环节的准备与避坑:把项目讲成亮点
4.1 高频提问和能加分的应答思路
答辩环节最怕的是“项目做了很多,但讲不出来”或者“老师一问就露怯”。我后来把老师最可能问的问题整理成了一张清单,每个问题都配了应答思路:
“为什么不用传感器,非要上摄像头?”回答要点是:传感器只能测固定点位的“有无”,无法连续估算液位高度;视觉方案能同时输出液位百分比、滴速、异常状态,扩展性更强,多床位联网报警也更容易。同时要诚实说明视觉方案的缺点:对光照敏感、需要算力,但通过数据增强和模型轻量化可以缓解。
“光照变化怎么办?晚上还能用吗?”回答要点是:训练阶段加入了大幅度亮度抖动,测试集里专门包含逆光和弱光场景,模型IoU几乎不下降。如果条件允许,可以现场切换一帧弱光测试图演示,比任何口头解释都有力。要注意不能把话说满,要承认在完全无光的环境下需要红外补光,这是后续改进点。
“模型参数量多大?推理速度多少?”这个一定要背熟自己项目的真实数字,我当时回答的是约7M参数,GPU下15毫秒一帧,CPU下120毫秒一帧。如果连自己项目的参数量都说不出来,老师会觉得你没有真正参与训练。
“和其他方法比过没有?”事先准备一个对比结果表,比如传统阈值分割在弱光下失效、纯检测器无法精确计算液位、带分割头的检测模型综合效果最好。这个对比实验可以现场展示,是很大的加分项。
还有一个提问是“数据量只有600张,凭什么说大数据深度学习”。应对思路是:深度学习的泛化能力不简单等同于数据量,本项目直接利用大型公开数据集的预训练权重做迁移学习,自采数据用于场景微调,这是工业界常见做法。同时强调“数据质量优先于数量”,项目覆盖了多种光照和液位状态,比盲目堆几千张无差异图片更有效。
4.2 现场演示最容易翻车的三个场景
我第一次模拟答辩演示时,当着几个同学的面翻车了,整个过程非常尴尬,好在后面总结出了原因。毕设答辩的现场环境和实验室完全不同,以下三个问题最容易出现。
第一是光线变化。演示教室的窗户朝向、灯光色温都和你录制数据集的环境不一样,模型的预测结果可能出现明显偏移。我的解决方法是:演示前先在现场跑一遍离线测试视频,观察液位百分比是否稳定;如果发现偏差,把报警阈值适当放宽。绝不能拿着训练时最好的模型参数直接上现场。
第二是报警阈值设置不当。演示时为了追求“准确”,把阈值设得过于严格,结果模型出现一点波动就报警,或者该报的时候不报。我的经验是,演示环境的目的是展示系统本身,而不是展示“极限指标”,把低液位报警阈值从20%下调到15%,置信度阈值从0.35降到0.3,能明显减少演示过程中的意外报警。
第三是摄像头没那么可靠。实验室里USB摄像头随手就能用,到了答辩教室可能端口占用、驱动不兼容、分辨率突然变化。最稳妥的方法是在本地保存两三段不同状态的测试视频,当摄像头出问题时直接播放视频作为输入源。这个方案不需要任何额外硬件,却能保证演示绝不中断,我称之为“离线视频备用方案”,你现在就可以把这个写到项目README里,答辩时主动提出来也是加分项。
4.3 别把毕设Demo说成可用的医疗设备
最后一个要提醒的,是答辩和项目介绍时的表述边界。静脉输液液位检测系统听起来很医疗,但毕设项目的本质是一个教学科研演示原型,不是可以拿进病房直接使用的医疗器械。如果老师问“这个系统能直接用于医院吗”,我的建议是诚实回答:目前还不能。
原因是真实的临床场景比实验室复杂得多:需要医疗器械注册认证,需要和医院信息系统对接,需要处理多床位并发,需要冗余设计防止单点故障,夜间还需要红外补光,关键是要保证极低的误报率,否则护士会产生“狼来了”效应。这些不是一句“后续可以加”就能糊弄过去的,所以我建议你在项目文档里专门写一节“从原型到产品的差距”,列出上述每一个差异点,并给出合理的改进方向。
这样回答反而会让答辩老师觉得你考虑问题周全,比不懂装懂说“可以”要强得多。有同学担心承认不足会影响成绩,但实际上,老师更在意的是你是否对自己的项目有清醒的认知。你能主动讲出限定条件和不足,说明你是真的理解这个系统的边界和代价。后面在展望未来时,再提一嘴红外补光、多床位管理、Web远程报警、通过异常检测算法进一步降低误报率,整个项目的完整度就很可观了,答辩的分数自然也不会低。
做完这套静脉输液液位检测系统,我最大的体会是:视觉检测项目看着复杂,但一旦把任务拆成数据、模型、报警、部署、答辩应对这几个独立模块,每一块的难度都完全可控。真正消耗我最多时间的不是训练模型,而是采集数据、调阈值和排雷,这种“看起来慢但其实在积累项目壁垒”的环节,反而成了答辩时最吸引老师的地方。
最后分享一个非常实用的技巧:项目完成后多录几段不同光线、不同药液颜色、不同液位状态的视频,存成离线测试集。我后面每次改进模型、或者答辩前检查模型状态,都会先在这套离线测试集上跑一遍,效果比临时架摄像头稳定得多,也能帮你快速发现“换了环境模型就开始漂移”这类隐藏问题。如果你的时间有限,就用这个思路把离线测试集先建好,再去纠结模型结构,绝对能少走不少弯路。