MiroFish这个项目,最早是我在鱼缸前蹲了三个星期之后被逼出来的。家里几条观赏鱼状态一直不对,食欲越来越差,游动也懒懒散散,但表面看起来又没有明显病症,等我终于发现不对劲时,已经有一条救不回来了。后来复盘才发现,观赏鱼生病前期的信号其实很明显,比如游动节律改变、鳃盖呼吸频率异常、长时间贴底或者蹭缸,但人不可能24小时盯在鱼缸前面。
于是就有了MiroFish——一个用普通摄像头加边缘小主机,对鱼缸做全天候视觉监测的智能系统。它用AI模型识别鱼的位置和姿态,再通过连续性视频帧计算游动活跃度、摄食强度、呼吸频率这些健康相关指标,一旦出现异常就推消息到你手机。这套东西不是实验室里的Demo,而是我在家里跑了几个月的可用方案,从硬件选型到模型训练再到告警落地,踩了不少坑,这篇就把完整过程拆开讲清楚。适合养鱼爱好者、AIoT开发者,以及想用边缘设备做计算机视觉实践的人参考。
1. 项目概述与设计思路
1.1 为什么要做一个“盯着鱼看”的系统
观赏鱼的问题出在“信号延迟”。水族圈有句话叫“病鱼看不出病,看出病就晚了”,这句话是有实际依据的。鱼类是变温动物,新陈代谢会随着水温环境变化,很多致病过程在早期只是行为层面的细微改变:游动速度明显变慢、喜欢停留在出水口附近、鳃盖开合频率比平时急促、对投食反应迟钝。这些信号如果靠人眼观察,需要每天固定时间蹲在缸前,而且还得对每条鱼的个体习惯足够熟悉,才能发现“今天这条鱼有点不对劲”。
我一开始也考虑过纯传感器方案,比如用水质监测仪测氨氮、亚硝酸盐、pH和溶解氧,靠水质异常间接推断鱼的健康状态。但这套思路有个天然缺陷——水质指标是“环境代理指标”,它不直接反映鱼本身的状态。鱼已经出现应激反应了,水质数据可能还在正常范围内;反过来,水质短暂波动时鱼也不一定马上出问题。视觉监测的优势在于,它直接盯着监测对象本身,用鱼的行为数据做判断,响应速度比环境指标领先一拍。
MiroFish这个项目的定位很明确:用低成本的视觉硬件,在鱼缸旁边做一个常驻的边缘AI服务,把“鱼的行为数据”变成可以量化、可以回溯、可以设置告警阈值的时间序列信号。项目本身不追求用一套模型解决所有鱼类疾病诊断问题,而是先把“异常行为检测”这件事做到可靠、可落地。
1.2 技术路线对比:视觉AI为什么比单纯传感器更合理
在真正动手之前,我对比过三类方案。
第一类是传统图像处理方案,比如帧间差分、背景建模、光流法。这类方案的优势是无需训练数据,部署简单,但问题也很明显:鱼缸场景里水面波纹、气泡、玻璃反光、灯光变化都会干扰前景提取,很容易把非目标物体当成运动目标,误检率高到没法用。实测下来,单纯用背景减除法跟踪一条游动中的鱼,能连续跟踪超过十分钟都算不错,而异常行为判断恰恰需要分钟级以上的连续轨迹。
第二类是商业成品方案,市面上有专门的智能鱼缸,也有带摄像头的喂食器,但这些产品都是封闭系统,检测逻辑不透明,往往只会报水温、喂食记录,不给行为数据接口。对于想深入研究鱼类行为的用户来说,这类产品几乎没有扩展空间。
第三类就是MiroFish采用的方案:目标检测模型加多目标跟踪器,在边缘设备上做实时推理,再把轨迹数据转换成行为指标。深度学习模型能泛化到不同鱼种、不同缸体环境,不会被水面波纹这类静态干扰轻易骗过;跟踪器则负责维持鱼的身份,保证“这条轨迹是同一只鱼”的连续性。选这条路线的判断依据是:我需要的不是“画面里有没有东西在动”,而是“画面里这条鱼在做什么、状态怎么样”,这必须靠实例级别的识别和跟踪来实现。
1.3 系统整体架构:边缘推理、消息上行、终端通知
整个系统的数据流我拆成了三段:采集与推理、数据存储与分析、消息通知。
采集与推理放在鱼缸旁边的一个小主机上,我用的是带NPU的开发板,接一个普通USB摄像头。推理服务用YOLOv8n做鱼体检测,用ByteTrack做轨迹关联,每秒处理约5到10帧画面。这个帧率是权衡过的——观赏鱼尤其是中小型灯科鱼,游动速度不算快,常见异常行为在秒级尺度上就能体现,不需要跑到30帧每秒的实时视频分析,帧率太高反而徒增功耗和算力负担。
数据存储与分析层放在了同一台小主机的本地数据库里,用SQLite就够跑单缸场景。每隔一段时间,系统会把滑动窗口内的检测结果、轨迹数据汇总成一条行为指标记录,包括平均速度、静止占比、转向频率、摄食区逗留时长等。为什么要做这个汇总?因为单帧的检测结果和原始轨迹数据量太大,全量上报既不现实也没必要,真正有价值的是这些统计量。
消息通知层使用现成的Webhook渠道,对接企业微信或者钉钉机器人。告警触发逻辑分两级:单指标越界触发普通提醒,多个异常指标叠加时触发紧急告警。实测下来,这套通知链路从发现异常到推送到达,延迟控制在2到3秒内,远快于人眼发现问题的速度。
2. 核心细节与算法拆解
2.1 目标检测与跟踪:YOLOv8n与ByteTrack的实际搭配
MiroFish的感知核心是两个部分:检测器负责在画面中找到所有鱼,跟踪器负责把连续帧中属于同一条鱼的检测框连接起来。
检测器我选的是YOLOv8n,n代表nano,是YOLOv8系列中最轻量的版本,参数量大概3.2M,在RK3588这类边缘NPU上跑640分辨率的推理,单帧延迟能做到30毫秒以内。为什么不用更大、精度更高的模型?因为鱼缸检测任务的目标普遍很小,一条成年斑马鱼在1080P画面里所占区域往往只有几十乘几十个像素,模型再大,对小目标的提升也有限,反而会拖慢推理速度。真正提升小目标检测效果的是训练数据里小目标样本的占比,以及推理时是否开启合理的多尺度测试,我在训练时专门做过目标尺度分布统计。
跟踪器选ByteTrack而不是传统的DeepSORT,原因是它在处理低置信度检测框时更聪明。鱼缸场景里目标频繁被水草、装饰物或者其他鱼短暂遮挡,遮挡期间检测器给出的置信度会骤降,甚至出现断帧。DeepSORT会把低置信度框直接丢掉,导致轨迹断裂;ByteTrack会把高置信度和低置信度框分开关联,低置信度框也参与轨迹匹配,对遮挡场景的鲁棒性明显更好。实测在鱼缸这种遮挡频繁的场景下,ByteTrack的轨迹保续率比DeepSORT高出约18个百分点。
2.2 行为指标怎么算:活跃度、摄食强度与呼吸频率
检测和跟踪只是手段,真正对养鱼有参考价值的是行为指标。
活跃度用滑动窗口内的综合运动量来衡量。我对每条鱼维护一个持续20秒的轨迹队列,每一帧计算鱼的位移和转向角,然后统计窗口内的平均速度、最大速度、静止帧占比和方向变化频率。四个指标归一化后加权合成一个0到100的活跃度分数。正常状态下,多数小型观赏鱼的活跃度会稳定在一个区间段,比如我养的斑马鱼在白天活跃期分数基本在65到85之间浮动,夜间关灯后降到20以下,这是一种正常的昼夜节律。如果一条鱼在白天的活跃度持续低于30,那就要警惕了。
摄食强度指标依赖“喂食时间段”标记。每次人工投食时,通过Webhook或物理按钮给系统发送一个“投食事件”,系统会记录投食后5分钟内鱼在喂食区(预先标注的ROI区域)的出现频次、停留时长和游动路径密度。正常鱼在投食后摄食强度会有一个明显的脉冲上升,如果连续多次投食后脉冲幅度越来越低,说明鱼的食欲在下降,这往往是疾病前期的第一信号。
呼吸频率是另一个重要指标。鱼的呼吸活动体现为鳃盖或胸鳍的规律性往复运动,我用检测框内下部区域的像素时序变化来提取这个周期。具体做法是在鱼体检测框的下半部分放一个竖条ROI,逐帧记录该区域的平均像素强度,形成一维时序信号,再通过快速傅里叶变换找到主频,换算成每分钟呼吸次数。这个方法要求帧率稳定在10FPS以上,对摄像头的最低帧率有一个硬性要求。
2.3 视觉异常与水质数据的融合判断
MiroFish从第二版开始加入了水质传感器的数据,但这个融合方式不是简单的“所有数据画在一起看”,而是设计了一套基于规则的双通道告警逻辑。
视觉通道输出的是行为异常候选事件,水质通道输出的是环境异常候选事件,两个通道独立判断,再进入一个简单决策矩阵。比如水温超过30度且鱼的呼吸频率加快,这两个信号单独看都可能是正常生理反应,但叠加出现时,大概率是水体溶氧不足或者热应激,告警优先级就要上调。反过来,如果视觉通道监测到鱼有明显的蹭缸行为(鱼体反复在缸底或装饰物上摩擦),但水质数据全部正常,这时候我不会把告警降级,因为蹭缸在多数情况指向体表寄生虫或细菌感染,和常规水质指标相关性很弱。
这个融合逻辑背后的思路是:每个通道都有自己的盲区,传感器测的是环境,视觉测的是本体,只有把两个维度的信息都纳入判断,才能减少单一数据源造成的误判。我见过很多爱好者只装水质监测却不看鱼的行为,等发现鱼状态不对时,水质数据其实早就恢复正常了,单靠环境指标根本追溯不到问题。
2.4 时间线数据存储与展示逻辑
行为指标的价值不只在于实时告警,更在于长期趋势分析。我设计了一个以“小时”为最小分辨率的聚合存储结构。
每条鱼的原始轨迹不会全量保存,系统每隔5分钟把轨迹队列里的统计量压缩成一条记录,包含平均速度、速度标准差、静止占比、呼吸频率均值、摄食区CPD(count per duration)等信息。到了整点,再把12条5分钟记录聚合成小时级数据。这样数据库里既保留了足够精细的日内模式,又不会让数据量失控。一台单缸系统,跑一整年下来,SQLite数据库文件也就几MB,非常轻量。
展示端我用的是一个简单的Web页面,显示每条鱼最近24小时、7天、30天的活跃度曲线和呼吸频率曲线。曲线叠加投食时间点和告警事件标记,这样回溯问题的时候,一眼就能看出“鱼是在哪天开始出现行为异常的”,再联动回忆当天的水族操作(换水、加鱼、调整灯光),基本能锁定诱因。这套时间线回溯逻辑,后来成了整个项目里我自己用得最多的功能。
3. 实操过程与关键环节实现
3.1 硬件选型与安装布局:摄像头怎么摆是关键
硬件清单我需要明确一件事:MiroFish的核心不是算力,是稳定的图像输入。图像输入不稳定,后面所有算法都是空中楼阁。
摄像头我用的是普通免驱USB摄像头,1080P分辨率,支持红外夜视。之所以不选工业相机,是因为鱼缸监测需要长时间连续运行,工业相机的散热、供电和价格在这个场景下没有必要。但有一个参数不能妥协:必须支持手动关闭自动曝光和自动白平衡。鱼缸的灯光会定时开关,环境亮度变化很大,如果摄像头自动调整参数,画面亮度会在开灯关灯瞬间剧烈波动,导致检测器性能骤降。我在代码里固定了曝光时间和白平衡值,只在每天凌晨零点和中午十二点做一次自动校准,实测这样处理之后,目标检测的稳定性提升了一个档次。
摄像头安装位置直接决定了整个项目的成败。我踩过最大的坑是把摄像头架在鱼缸正前方偏高处,结果玻璃反光把客厅的窗户倒映得一清二楚,检测器频繁把窗框边缘当成鱼,误检率一度超过40%。后来换成两个办法:一是让摄像头以15度左右的俯角斜向下拍摄缸体正面,镜头尽量贴近玻璃,减少大角度反光;二是在画面里预先设置ROI掩膜,把水面上方、缸外区域全部屏蔽掉,只保留水体区域作为检测范围。ROI掩膜启用后,误检率直接降到了5%以下。
3.2 从采集标注到模型训练的完整流程
这套系统的检测模型是在自己采集的数据集上微调过的,整个流程可以拆成四步。
第一步是采集。我连续采集了大约两周的视频,覆盖白天自然光、夜间LED灯、夜间红外灯三个光照条件,以及鱼在摄食、追逐、休息等不同行为状态。采集到的原始视频按每秒抽2帧的方式切图,得到约4500张有效图片。为了让模型对不同缸体环境也有泛化能力,我还额外引入了公开鱼类数据集中的约1500张图片混合训练,包含不同水质、不同拍摄角度下的鱼。
第二步是标注。标注工具我用的是LabelImg,框的类别只有一类:fish。这里有一个细节,鱼的尾巴和身体经常呈现半透明状态,标注时如果只框不透明的躯干部分,会导致目标框过小,影响检测稳定性。我的做法是只要肉眼能分辨出是鱼身的一部分,就把整个可见鱼体框进去,宁可框得略大也不要漏掉尾巴边缘。
第三步是训练。我用YOLOv8n做基础模型,输入分辨率640乘640,batch size为16,训练150个epoch。优化器用SGD,初始学习率0.01,采用余弦退火调度。训练集和验证集按9比1划分,最终在验证集上的mAP50达到0.93,mAP50-95是0.67。这个精度对鱼缸检测来说已经足够用,毕竟目标类别只有一类,背景相对固定。
第四步是导出部署。训练好的模型导出为ONNX格式,再用NPU工具链转换成边缘设备专用的模型格式。转换后需要做精度对齐验证,一般会有微小掉点,但只要mAP50保持在0.85以上就不影响实际使用。
3.3 推理服务与报警推送的落地代码思路
服务端推理逻辑核心就是一个循环:读帧、检测、跟踪、更新指标、判断告警。我用Python加OpenCV实现,整体逻辑用伪代码描述大概是这样的:
import cv2 import numpy as np capture = cv2.VideoCapture(0) tracker = ByteTrack() window = SlidingWindow(seconds=20) while True: ok, frame = capture.read() if not ok: continue # 仅处理ROI区域,减少无效推理 roi_frame = apply_roi_mask(frame) detections = yolov8_infer(roi_frame, conf_threshold=0.35) # 更新轨迹 tracks = tracker.update(detections) for track in tracks: fish_id = track.id bbox = track.bbox velocity, turn_rate = calc_motion(track) window.push(fish_id, velocity, turn_rate, bbox) # 每5秒计算一次行为指标 if should_aggregate(): metrics = window.compute_metrics() save_to_sqlite(metrics) alert_list = check_alert_rules(metrics) for alert in alert_list: send_webhook(alert)这段代码看起来不长,但实际调试过程中有几个隐藏的坑。一个是推理频率管理。如果每帧都做检测,边缘设备CPU占用会冲到很高,我最后采用了隔帧推理的策略,视频读取保持15FPS,检测推理降到5FPS左右,行为指标计算基于全部帧的轨迹数据插值,效果一样稳定,CPU占用却降了约60%。
另一个坑是检测结果和轨迹数据的坐标系对齐。ROI掩膜会让部分画面区域失效,如果直接拿原始帧的坐标去匹配ROI外的轨迹,会出现幽灵目标,必须把坐标统一到ROI裁剪后的坐标系里。
3.4 几个关键参数的调试经验值
这部分参数是我经过多轮实验得到的具体数值,可以作为参考但不必照搬,因为不同鱼缸的光线和目标大小差异很大。
置信度阈值我调试的时候发现设成0.35到0.4之间最合适,太低的置信度会引入大量误检,尤其在有气泡和水草晃动时;太高又容易漏掉被遮挡的鱼。这个值比通用目标检测场景低一些,是因为鱼体目标小,模型输出置信度天然偏低。
NMS的IoU阈值保持默认的0.5即可,不需要动。真正需要调的是ByteTrack的match_threshold,也就是轨迹匹配时允许的最大距离。我按画面中鱼的体长比例来算,典型设置是鱼体宽的2.5倍。设太大的话,两条交叉游过的鱼会被串成一条轨迹;设太小,鱼转身时检测框轻微偏移就会断档。
鱼呼吸频率提取的FFT窗口我设成10秒,频率分辨率刚好是0.1Hz,对应每分钟6次呼吸的精度,能满足常见观赏鱼的呼吸频率范围(每分钟30到120次)的测量需求。窗口再短,频率分辨率不够,窗口再长,实时性又受影响。
4. 实测效果、常见问题与排查技巧
4.1 平稳期与异常期的检测效果:跑了一个季度的真实数据
MiroFish在我家的缸上连续运行了大约四个月,期间经历过斑马鱼、红绿灯鱼两个鱼种,出过两次真实异常事件,整个系统的表现可以分成两种情况来说。
平稳期,也就是鱼的健康状况正常时,系统的作用更像一个“行为记录仪”。活跃度曲线会呈现出非常规律的昼夜节律:白天开灯后上升,晚上关灯后下降,投食时间点附近出现短时脉冲。呼吸频率曲线同样稳定,同一种鱼在相同水温下,呼吸频率波动范围很窄,斑马鱼在26℃时基本稳定在每分钟70到95次。这段过程验证了系统输出的指标具有稳定性和可重复性,也为后续异常判断提供了基线数据。
真实异常事件发生在第三个月。一条斑马鱼逐渐脱离鱼群,活跃度从平时70多分连续三天下降到40分左右,呼吸频率从80次/分钟升到110次/分钟以上。系统在第2天就触发了普通告警,我没有处理,继续观察,到第3天紧急告警触发。随后我检查鱼体,发现腹部有轻微立鳞迹象,隔离处理后情况缓解。这个案例让我确信一件事:行为指标的异常确实早于外部可见症状出现,视觉监测完全能承担“早期预警”的角色。
4.2 家庭鱼缸场景的四大干扰源
真实环境不可能像实验室那样干净。我在调试过程中总结出四个最典型的干扰源,以及对应的处理方案。
第一个是玻璃反光。这是最初导致大量误检的元凶。除了调整摄像头角度和ROI掩膜,还有一个好用的技巧:贴偏振膜。在鱼缸外侧贴上手机屏幕防窥膜或者专用偏振膜,可以有效消除一部分玻璃反射偏振光,画面通透度提升明显。这个方法的缺点是会略微降低画面亮度,需要增加一点点补光。
第二个是水面的周期性波动。水泵出水口附近的水面会持续波动,产生规律的亮度变化,检测器偶尔会把波动的高光区域识别为目标。我的处理办法是把ROI上边界压到水位线下方约2到3厘米处,彻底避开水面交界区,既不损失有效水体范围,又能消除这类误检。
第三个是打氧产生的气泡串。气泡在上升过程中会形成连续的小目标区域,尤其当背景颜色较暗时,气泡很容易被当成小型鱼体。针对这个干扰,我在检测后增加了一个目标大小过滤器,面积小于正常鱼体30%的检测框直接丢弃,气泡目标基本都能被过滤掉。
第四个是缸体内壁的藻类和污渍。长期运行后缸壁会长出褐藻或绿斑,这些斑点在某些光照角度下会产生类似鱼体的边缘特征。这个问题的解决靠的不是算法优化,而是维护习惯——每周擦一遍缸壁内侧,系统误检率会随之下降。算法解决不了保养问题。
4.3 误报与漏报的经典处理案例
有一种漏报场景值得单独讲。一条鱼游到过滤器的出水口正下方,水流冲击让鱼的身体剧烈摆动,检测器虽然能稳定框住目标,但轨迹数据里的转向频率和速度明显异常,甚至超过了系统预设的“应激阈值”,触发了误报。这种误报不是检测失败,而是行为指标本身被环境因素扭曲了。我的处理方式是在active度计算中加入了“环境流场掩码”,出水口区域的速度和转向值以50%的权重参与最终指标合成。这样既不会完全忽略鱼在出水口区域的异常表现,又避免了水流干扰主导整体判断。
鱼缸里水草晃动也会带来类似的指标污染,但水草晃动的模式是低频摆动,和鱼的高频运动叠在一起后,频谱特征上能区分出来。我尝试过用高通滤波器对轨迹速度做预处理,把低于0.5Hz的低频分量滤除一部分,对减少水草干扰有一定帮助,但效果有限,后来还是靠ROI划分,把水草密集区单独出来监测。
4.4 降低系统负担的两种思路
边缘设备的算力始终是有限资源。运行一段时间后我发现,如果直接把推理频率提高到10FPS,设备温度会维持在65℃以上,长时间运行稳定性下降。解决思路有两个方向。
一是按需推理调度。夜间关灯后鱼的活动量本身很低,异常事件发生的概率也低,系统在夜间可以把推理频率降到2FPS,只记录基础指标,不跑高频率行为分析。白天开灯期间再恢复到5到8FPS的完整模式。这个逻辑简单粗暴,但对降低整体功耗和温度非常有效。
二是预筛选加精检测的两级架构。先用轻量级的背景差分算法做运动检测,只有画面运动量超过阈值时,才把这一帧送入完整的YOLO模型做检测。鱼缸场景里大部分时间是相对静止的,两级架构可以把有效推理次数减少将近一半。这个优化做下来,设备待机功耗从平均8W降到了5.5W左右。
5. 常见问题与排查技巧实录
5.1 目标频繁丢失怎么办
症状是鱼的轨迹经常中断,几秒后又重新出现,跟踪ID频繁变化。这种情况多半不是模型问题,而是检测阈值和跟踪参数不匹配。先看置信度阈值是否设得过高,其次看跟踪器的match_threshold是否过紧。还有一个容易被忽略的点是检测框的稳定性,鱼体边缘带有半透明鳍条,检测框会在几帧内出现微小抖动,如果跟踪器对框的抖动敏感,就会导致匹配失败。我的处理方式是在送入跟踪器之前对检测框做一次时域平滑,用当前帧和上一帧的检测框取加权平均,减少抖动带来的轨迹断裂。
5.2 CPU占用过高
先检查是不是推理频率设置得太高,或者模型没有真正跑在NPU上。很多人把模型转到NPU平台后,代码里还是走CPU推理路径,等于白转。排查方法是看设备运行时的进程资源占用,如果NPU负载正常但CPU占用率仍然很高,问题可能出在OpenCV的帧读取或者颜色空间转换上,这两步在CPU上的开销其实也不小。可以尝试降低读取分辨率或者在读取时直接设置色彩格式。
5.3 夜间红外模式下检测效果变差
可见光模式下模型表现很好,切到夜间红外模式后漏检变多,这很正常,因为模型在训练时红外图占比不够。解决办法是在训练数据里提高红外图像的比重,我最终把红外图的比例控制在四分之一左右后才稳定。另外一个技巧是启用红外补光灯时,注意画面里不要出现局部过曝区域,鱼游过高亮区域时检测框会丢失,调整补光灯角度和强度可以缓解。
5.4 告警频繁触发但鱼状态正常
这是误报率问题,优先查行为指标阈值是不是定得太紧。不同鱼种、不同大小的缸体,指标分布差异很大,不要直接套用默认阈值。先在平稳期跑一周系统,统计各项指标的正常分布范围,再按“均值加减2.5倍标准差”这个经验公式设置告警线,误报率能大幅下降。如果个别指标仍然频繁越界,需要回到数据里看是否存在环境干扰源。
5.5 常见问题速查表
| 问题现象 | 排查方向 | 处理建议 |
|---|---|---|
| 轨迹频繁断裂 | 跟踪参数、置信度阈值 | 调低置信度至0.3-0.35,放宽match_threshold |
| 白天误检多 | 玻璃反光、ROI未设置 | 调整摄像头角度,粘贴偏振膜,开启ROI掩膜 |
| 夜间漏检多 | 红外训练样本不足 | 增加红外图片比例到25%以上,调整补光角度 |
| 自助关灯后指标无节律 | 采集时间与空间 | 确认系统时钟准确,检查灯控设备是否成功联动 |
| 设备温度过高 | 推理频率、散热 | 降低夜间推理频率,加装主动散热风扇 |
| 数据库增长过快 | 聚合周期太短 | 延长聚合周期至5-10分钟,压缩原始数据保留策略 |
6. 想清楚这些事再做,能省一半的功夫
最后聊点项目之外但比项目更有价值的体会。MiroFish做到后半程,我最深的感受不是“AI很强大”,而是“养鱼的核心问题其实是观察意识”。很多人买智能设备是为了省心,但真正的价值是帮你建立起对生物状态的敏感度。系统把一个模糊的担忧变成了一条条可回溯的数据曲线,养鱼从“凭感觉”变成了“看数据”,这是这个项目最让我满意的地方。
技术上的收获同样不少。边缘设备的资源限制逼着你重新审视每一行代码的开销,从模型大小到推理频率再到数据存储策略,每一步都需要做取舍。这种在资源约束下做平衡的能力,和单纯在服务器上跑通一个模型是完全不同的经验。
如果你也想做一个类似的监测系统,我的建议是不要一开始就堆功能。先把“持续稳定的目标检测和轨迹跟踪”跑通,老老实实记录一周的正常数据,再考虑加告警、加水质融合、加Web展示。系统只有先稳定,才有资格谈智能。MiroFish目前还在持续迭代,后续我计划加入自动喂食联动的闭环:检测到摄食强度下降时自动暂缓下一餐投喂量,减少因过度喂食导致的水质恶化。鱼不会说话,但它的每一帧游动都在传递信息,我们要做的只是把这些信号翻译成看得懂的语言。