基于YOLO和边缘计算的居家药丸识别系统实现与部署
这个项目我对它的定位从一开始就很清楚不是做一个炫技的玩具而是解决一个非常具体、每天都在发生的生活难题——药盒里的药混在一起分不清哪颗是哪颗家里老人拿着药瓶却看不清说明书上的小字。我在做完需求调研和实际场景测试后把项目框架确定为三个核心词Smart Pill Identifier、药丸识别、居家用药识别。下面从需求拆解、技术选型、系统设计、实操细节到踩坑记录完整复盘一遍给想做类似方向的朋友一个可参考的样板。1. 项目到底在解决什么问题1.1 居家场景里最容易被忽视的用药风险先聊一个我自己的真实经历。去年我妈做了一次小手术术后要同时吃三种药其中两种是白色圆形小药片一种白色椭圆形还有个蓝色胶囊。出院时医生交代得清楚可回家之后过了两天药盒一混我妈自己都分不清哪个是降压的、哪个是消炎的。她又不愿意老打电话问医生就凭印象吃。我在旁边看着心里是真的发慌。其实这不是个别现象。国内老年人多重用药的情况非常普遍一项社区调查的数据显示同时服用5种及以上药物的老年人比例不低。而药物混淆、漏服、错服是居家用药安全里最高发的风险点。比起复杂的药物管理设备大多数人真正需要的是一个能“看一眼就知道是什么药”的工具。这个需求不是伪需求而是刚需。我当时就在想手机摄像头这么普及图像识别技术也已经很成熟了为什么不能做一个随手拍一下、自动识别药丸名称和用途的工具于是这个 Smart Pill Identifier 项目立项了。1.2 目标用户和核心使用场景拆解项目的核心使用场景我梳理了一下其实远不止“老人分不清药”这一种场景一多药混装。很多家庭习惯把药从原包装拆出来放在一周分装药盒里。时间一长混在一起认不出来。这是最典型的识别需求。场景二说明书丢失或字太小。不少OTC药品是散装或塑料袋包装标签模糊。用户想知道这是什么药、有什么用、怎么吃。场景三误吞风险。家里有小孩或宠物如果误食了不明药丸需要快速识别成分给医生提供参考信息。场景四旅行出差。出门在外把几种药混在一个小瓶子里临时认不出。场景五整理家庭药箱。很多人家里囤了一堆药过期没过期、都是些什么药自己都不清楚。基于这些场景我明确了项目的目标用户画像第一优先级是慢病管理的中老年人及其子女第二优先级是年轻家庭里的育儿人群第三才是喜欢尝鲜的技术爱好者。1.3 为什么不能直接用现有App解决立项初期我也调研过市面上已有的同类产品或功能。有几款健康管理App里带药盒扫描功能也有直接用通用搜索引擎“拍照识物”来识别药丸的偏方。但实际测试下来问题非常集中通用识物引擎对“小物体、相似形状、相似颜色”的区分能力很差。药丸不是日常物品直径通常只有5到15毫米通用模型会把它识别成“糖果”或“纽扣”。现有药品数据库不开放或数据不全。很多App的药品信息来自限制级数据库扫描出来只有名称没有准确的功能说明、用法用量、注意事项实用性大打折扣。没有针对“分割识别”做优化。一板药里有多个药片或桌面上一堆药混在一起时通用方案要么识别不了要么只能框选最大的那个。隐私顾虑。国内用户在用药这件事上对隐私非常敏感药盒拍照意味着暴露自己的疾病信息。一些云识别方案把照片直接传服务器这本身就是一个劝退点。所以这个项目要解决的核心问题不是“识别模型调得准不准”这一个技术问题而是一套针对药丸识别场景的完整闭环拍照 → 分割/定位 → 识别 → 查询信息 → 给出用药提示。这比单纯做一个图像分类模型要复杂得多但也正是它的价值所在。2. 技术方案选型为什么用边缘智能而不是纯云端2.1 药丸识别到底属于哪一类计算机视觉任务先说一个很多初学者容易搞混的点。药丸识别不是单纯的“图像分类”它实际上横跨三个子任务目标检测Object Detection找到画面里药丸的位置输出边界框。这一步解决“药在哪”的问题。图像分类/细粒度识别Fine-grained Classification对框选出的药丸区域判断“是什么药”。这一步解决“是哪颗”的问题。可选实例分割Instance Segmentation把药丸的精确轮廓抠出来用于后续成像分析如颜色、刻痕。如果一板药里只有一颗药背景干净那确实可以退化成纯分类问题。但居家场景比这个复杂得多——背景五花八门可能有桌面纹理、手指、药盒印刷字药丸之间还可能互相重叠。如果只用一个分类模型直接对整张图预测效果必然很差。核心思路是“先检测/分割再识别”的两段式或端到端方案。我最终选择了YOLO 系列的检测模型 轻量级分类头的组合路线。原因是检测和分类可以共享主干网络整体计算量可控适合在手机端跑。药丸检测对实时性要求不算高拍一张照1秒内出结果即可但对精度要求高YOLO的精度在中小物体上的表现比较成熟。社区生态好无论是PyTorch还是ONNX Runtime都有大量现成工具链。2.2 为什么不首选纯云端识别很多类似项目习惯性地把识别丢给云端API理由无非是“模型可以更大更准”。但我在药丸识别这个特定场景里反而坚持“边缘优先云端可选”的双轨架构。这个思考是基于以下实际因素的隐私保护。药品信息等于健康信息让用户的药盒照片传到第三方服务器很多用户心理上就过不去。尤其在当前数据合规要求越来越严格的背景下本地推理可以大大降低合规风险。离线可用。居家场景经常遇到信号不好、Wi-Fi不稳定的情况。如果老人晚上在卧室里想确认一颗药还要跑到客厅连Wi-Fi这个工具的价值就大打折扣了。本地推理可以做到离线可用。成本控制。云识别按每次调用收费日活1000的场景每个月就是一笔不小的账单。本地推理的成本基本为零。当然本地推理的代价是模型不能做得无限大。所以我在模型选型上做了个平衡检测模型用 YOLOv8nnano版本分类头用 MobileNetV3-Large 的轻量版整个模型压缩后大约20MB在iPhone 11级别的中端手机上单张图推理时间约0.6秒。这个速度对“拍照识别”场景来说完全够用。2.3 数据集是最大的工程难题没有之一药丸识别领域有一个非常尴尬的现状公开数据集极其匮乏。不像ImageNet有上千万张通用图片药丸图片因为涉及隐私和监管很难大规模采集和共享。国外有几个学术数据集比如NIH的Pill Image Recognition Dataset但它们的图片背景干净、拍摄条件标准和“手机随手拍”的真实场景差距非常大。我的应对方案是三条腿走路自建采集台用三种不同色温的光源暖白光、冷白光、混合光在五种背景纯白纸、木桌、白色桌面、黑色绒布、浅灰色塑料板下对市面常见的100种药丸各拍摄10到20张。每种药丸控制不同角度和距离总计约15000张原始图片。数据增强要“狠”除了常规的翻转、旋转、色域抖动我还加了随机模糊模拟手抖、随机亮度扰动模拟不同环境光、随机裁剪缩放模拟远近拍摄。增强后的数据集约60000张。程序化合图用Python脚本把单颗药丸的抠图随机粘贴到复杂背景上生成多目标混合场景。这样等于用合成方式凭空多出了几万张“多药丸共处一图”的训练数据对检测模型的训练非常关键。注意数据增强不是做得越多越好特别是不能对药丸本身做“仿射扭曲”否则会破坏药丸形状的真实分布让模型学到不真实的特征。3. 系统架构与功能模块设计3.1 整体技术栈和项目结构硬件层面其实没什么特别的一台普通的Android开发手机和一部iPhone交替测试。软件层面的完整技术栈如下供参考模型训练与实验Python PyTorch 2.x Ultralytics YOLO端侧推理引擎Android端用NCNNiOS端用Core ML同时用ONNX Runtime做交叉验证App主体Android用Kotlin Jetpack ComposeiOS用SwiftUI本地数据库SQLite存储药品信息缓存和识别记录云端补盲备用方案AWS Lambda 自建API仅在全球药丸数据库查询时使用整个App的功能模块划分为三层拍照与预处理模块负责相机调用、自动对焦提示、图像裁剪、光照增强。识别引擎模块负责检测、分类、置信度过滤以及“未知药丸”的兜底策略。信息展示与用药提示模块负责把识别结果映射到本地药品信息库展示用法、用量、注意事项并生成识别历史。3.2 识别流程的工程化设计整个识别流程如果画成流程图会非常清晰但为了帖子阅读方便我用文字串一遍。Step 1拍照辅助用户在App里点拍摄这不同于普通拍照——我们会实时检测取景框里的运动模糊太模糊就提示“稳住手机”。理想的情况是药丸放在纯色背景上比如白纸距离镜头8到15厘米尽量单颗或少量多颗。Step 2图像预处理拍完的照片不会直接进模型。先统一缩放到640x640的分辨率保证输入尺度一致。同时做一个简单的白平衡矫正取图像四个角附近的像素估算环境色温做颜色校正。这一步很小但很重要因为不同灯光下药丸颜色会有肉眼可见的偏差会直接影响分类准确率。Step 3目标检测将预处理后的图片输入YOLO检测模型输出若干边界框。检测结果里会有置信度分数我会过滤掉置信度低于0.45的框。如果检测到多个目标但都是在同一个药盒内还会做一个聚类合并防止把一颗药丸的多个局部碎片当成多个目标。Step 4细粒度分类对每个检测框区域做透视矫正单独裁剪再送进分类模型。分类模型输出的是药品ID和置信度。这里有个很关键的点如果分类置信度低于0.7我不会硬选排名第一的类别而是输出“可能是A或B建议人工核对”避免误导用户。Step 5信息检索与反馈拿到药品ID后查本地SQLite药品库。如果命中展示药品名称、适应症、用法用量、副作用、特别注意事项。如果没命中自动上报云端API尝试全球数据库查询并在UI里明确标注“信息来源为公共数据库仅供参考请遵医嘱”。3.3 药品信息库怎么搭建识别模型只解决“这是什么药”的问题但用户真正关心的是“这个药怎么吃”。所以药品信息库是整个产品体验的另一半。我没有直接购买商业药品数据库而是用开源方案 人工校验基础数据来自公开的国药准字药品说明书数据库抓取非官方源只做展示必须标注“AI整理仅供参考”。本地用SQLite存了两种表结构一个是药品主表编号、通用名、商品名、规格、药盒图案特征颜色一个是说明书信息表适应症、用法、副作用、禁忌、储存条件。每次识别成功后会在“识别历史”里留下记录方便用户追溯。同时我预留了“家庭药箱管理”的扩展接口后续可以把识别结果自动归纳进药箱库存。这里要特别说明任何药品信息展示都必须带一句“请以医生建议和说明书原文为准”。这不是敷衍是产品的基本责任感。3.4 UI/UX设计上针对老年用户做的妥协做这类应用界面设计绝不能按年轻人的审美来。我的几个核心决策字号要大所有药品名称、用法用量这些核心信息最小字号设在17sp以上。字号调节按钮直接放在主界面不藏在设置里。色块区分识别结果用高对比度色块显示。绿色表示“信息完整可直接查看”橙色表示“需人工核对”红色表示“识别失败”。语音播报集成了TTS文本转语音识别出结果后可以一键语音播报用法用量。实测下来这功能对老年用户简直是“真香”级别的存在。操作路径极短整个识别流程从点开App到看到结果不超过两次点击。不需要登录不需要注册打开就是快门。这些设计不是因为我想做关怀而是因为目标用户真的需要。我在试用了几个竞品后发现很多产品做了复杂的数据看板、社交功能、积分系统但用户连“识别一颗药”都要经历三四步跳转这已经违背了工具类产品的初衷。4. 实操过程从零到一的关键实现细节4.1 环境准备和依赖安装这个项目最核心的复现环境建议如下。我本地用的是Windows RTX 4070 (12G显存)有条件上集群当然更快但12G显存训练YOLOv8n完全够用。# 创建虚拟环境 conda create -n pill_recognition python3.10 -y conda activate pill_recognition # 安装依赖 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics opencv-python onnx onnxruntime pip install pillow numpy pandas matplotlib建议不要用最新版torch就图新鲜实测2.0.1或2.1.x的稳定性和兼容性都很好。ultralytics库版本建议锁在8.0.x因为新版API变动频繁网上教程和第三方工具链不一定及时跟进。4.2 数据标注比想象中更痛苦但更重要的环节我用LabelImg标注检测框标注字段就一个类别“pill”药丸。但有个细节药盒上的药名文字、阴影、桌面纹理我会额外标注为“background”背景强迫模型学会区分“药丸物体”和“非药丸物体”。标注规范上我踩过坑整理了三条铁律模糊的硬边界药丸在图片边缘、模糊得连人眼都看不清的直接不标不要硬标。重叠药丸两颗药紧贴甚至重叠时各自标各自的框允许框之间有重叠不能只标一个。刻痕药丸中间有凹线的药片边界要包含整个药片实体不要把凹线当成分割线。这些规则定下来之后中间标注返工少了很多。前前后后约15000张自采图两个人标了三天配合半自动预标注先用一个粗模型预测人工修正效率明显提升。4.3 YOLOv8n的模型训练全流程数据集准备好之后目录结构按Ultralytics的规范整理dataset/ ├── images/ │ ├── train/ # 约12000张 │ └── val/ # 约3000张 ├── labels/ │ ├── train/ │ └── val/ └── data.yamldata.yaml内容如下train: ./images/train val: ./images/val nc: 1 names: [pill]训练命令非常直接不过有几个关键参数需要解释一下yolo detect train \ modelyolov8n.pt \ datadataset/data.yaml \ epochs120 \ imgsz640 \ batch16 \ device0 \ patience20 \ projectruns/trainepochs120针对小数据集和单类别目标120轮足够更多反而容易过拟合。patience20早停机制连续20轮验证集mAP不提升就停止。我这个数据集实测在第80轮左右就不再明显提升了。imgsz640YOLOv8的默认训练尺寸就是640分辨率再大对药丸检测小目标有帮助但对算力要求高得多。640和768我都试过640的mAP约0.93768能到0.95但推理速度掉了30%最终权衡下了线上用640。训练完成后看metrics里的关键指标mAP50-95在0.85以上基本可用mAP50到0.95以上属于优秀。我这份模型训练日志记录到mAP50-950.89mAP500.96符合预期。4.4 分类模型的蒸馏策略检测模型拿到边界框后真正决定“是哪颗药”的是分类头。药丸分类是典型的细粒度图像分类可能同一杀菌药有不同厂家、形状几乎一样但颜色略有差异这对模型是极大考验。我采用了一种简单有效的方案用训练好的检测模型主干 自定义全连接分类头做联合微调。具体来说对检测到的每个边界框区域做裁剪和大小归一化64x64。共享卷积主干提取特征。分类头输出100个类别的softmax概率。这个联合微调的效果比单独用MobileNetV3训练分类模型高了约4个百分点的准确率从90.2%升到94.5%。原因是检测主干已经在真实药丸图像上做了大量表征学习分类头能依托更合适的底层特征。这里的关键技巧是在微调分类头时冻结主干的前三层——因为前几层学习到的边缘、纹理、颜色基本是通用性很强的底层视觉特征不需要因为分类任务而改变这样能有效避免过拟合而且训练速度更快。4.5 模型导出与移动端集成训练完的PyTorch模型要部署到移动端我最先试了ONNX Runtime统一路线但是因为跨平台包的体积和某一层算子兼容性问题最终采用“各端独立优化”的路线。Android端NCNN# 先把PyTorch模型导出为ONNX yolo export modelbest.pt formatonnx opset12 simplifyTrue # 再用NCNN工具链转成ncnn格式 onnx2ncnn yolov8n.onnx yolov8n.param yolov8n.binNCNN转换有个坑YOLOv8的检测头结构里包含一些动态尺寸的操作onnx2ncnn转换时会报“未支持的算子”。解决办法是写好一个算子注册文件或者用ncnnoptimize先处理实在不行就用openvivo工具链转换但这个帖子不做展开。iOS端Core MLCore ML的转换相对省心直接用Ultralytics提供的脚本或者用coremltools自定义转换注意要把模型的输入输出固定为640x640 Tensor。两种方案部署后的实测数据对比我放在下面平台框架推理耗时iPhone 11模型大小备注Core ML约0.6秒约20MB初始化快兼容性好NCNN约0.8秒约20MBAndroid中端机4.6 “未知药丸”兜底策略没有任何模型能覆盖所有药丸。现实情况是用户可能拍到海外买的药、新上市的药、或者我们没收录的药。所以我设计了一个“未知药丸”的循环优化机制当分类置信度低于0.6时App会弹出“未能识别”页面同时引导用户填写药品名称或扫描药盒条形码。用户填写的有效信息会匿名回传到后端的待确认池。每周我从待确认池里抽取新增药丸补充采集数据加入训练集。这个闭环两三个月以后的效果非常明显最初产品上线第1个月未知药丸率约12%到第4个月降到了4%。很大程度上就是靠真实用户反馈在喂数据。5. 实测记录真实场景里的成与败5.1 一次识别失败的完整复盘上线后的第2周收到用户反馈“识别蓝色胶囊有盐酸什么什么但App显示是阿莫西林。”这个case我拉出来单独复盘。排查后发现两个问题用户拍摄时光线偏黄。用户是在室内暖黄色灯光下拍的背景是深色桌子胶囊颜色从蓝色偏成了蓝绿。但我们的白平衡估计器只取图像四角像素深色背景导致估计色温完全错误。数据库里有多个近似药丸。蓝色胶囊有很多种我们的训练集里蓝白色胶囊样本不够多模型只能给出概率最高的猜测。解决动作有两个在白平衡预处理环节改成“自适应高光白平衡”优先选取图像高亮区域颜色作为参考而不是角落像素。增加蓝白色系胶囊的采集规模把这类样本量翻倍刻意加入低色温光照的增强样本。这个case让我意识到视觉识别项目的测试不能只在标准环境里做。我后来专门搭建了一个“家庭环境模拟箱”用40瓦暖光灯泡、台灯侧光、LED冷光等不同光源组合把测试集从标准光照扩展到了7种光照环境。5.2 检测模型对反光药丸的误判有一类药丸表面有糖衣或胶囊壳反光很强。在白色背景下拍摄反光区域会过曝导致模型把药丸的高光部分识别成两半或漏检。针对这个问题的解法比较取巧在检测阶段不做任何处理把重担完全交给数据增强。我在增强管线里加入随机“高光模拟”对图像局部区域叠加高斯白斑模拟反光效果。这样训练出来的模型对反光不太敏感了。实测检测漏检率从4.1%降到了2.2%效果非常显著。5.3 性能与耗电的权衡识别过程中我发现大量耗时不在模型推理而在于相机的实时预览。如果相机预览保持30fpsCPU和GPU占用会一直居高不下导致手机发热。我把相机预览帧率降到15fps只有按下快门后才恢复30fps录制1秒钟。这个改动对识别结果毫无影响但整机CPU占用降低约20%。同时把模型推理放到后台线程避免阻塞UI导致ANR应用无响应这个是Android开发的经典教训但很多人还是会忘。另外当识别完一张图后我会立即可视化边界框并跳转到结果页后续的药品信息查询异步加载。用户的心理感知是“秒出结果”实际上后端的数据库查询又花了0.2秒。5.4 隐私保护离线优先如何做到合规合规问题在整个项目里都很重要。我有几条硬性原则拍照图片默认不离开设备。识别过程完全本地完成只有用户主动触发“云端补充查询”时才会上传图片或文字信息。匿名化处理上传待确认池的数据会先剥离图片里的Exif信息GPS、设备型号、拍摄时间只保留药丸图片本身和用户填写的药名。用户可全量删除App设置里提供“清空所有历史记录”的入口一键删除本地SQLite里的所有识别痕迹。关于数据合规我的建议是如果你的应用涉及医疗或健康数据不要等到产品上线才请人做合规审查在产品设计阶段就要把“数据最小化”和“本地优先”写进需求文档里。这不是为了应付检查而是因为这个产品的用户本来就是敏感人群一旦出现隐私口碑问题技术做得再好也会全部归零。6. 这个项目的价值与可扩展空间6.1 从药丸识别扩展到智能药箱药丸识别只是整个居家智能健康管理的一个子模块。我在设计数据模型时特意把“识别记录”和“药箱库存”做了关联设计。这意味着后续我可以做智能药箱管理扫一次药盒自动归类到期时间临近过期时推送提醒。用药日历根据说明书里的用法用量自动生成每日服药计划和提醒。多成员健康管理一个家庭里多个成员不同药单通过识别结果自动归属对应成员。这些扩展说起来很简单但核心难点都在于识别结果和用药者之间的准确关联。如果识别错了后续的提醒和用药日历也会跟着错所以识别准确率是整个产品的地基。6.2 与家用智能硬件的联动单纯手机App可以解决“看到就想识别”的即时需求但如果要做更“无感”的体验和智能硬件联动是必然方向——比如在智能药箱里内置微型摄像头药物放入时自动识别并记录。这正好用到了我训练出的模型因为端侧推理天然适配硬件功耗受限的场景。6.3 数据闭环带来的长期竞争力说实话任何一个药丸识别模型用公开的小数据集训练出来都是“玩具级”的。真正的核心竞争力是在持续运营中积累的高质量药丸图像数据和用户反馈修正数据。这个数据飞轮一旦转起来会让产品的识别能力越来越好后来者即便拿到相同算法也没有这样丰富且更新及时的真实场景数据集。我的个人体会是做这种细分领域的AI应用算法模型只是起点真正决定产品天花板的是你对场景的理解深度、数据闭环的运营能力以及对用户安全的责任感。目前版本虽然已经能处理绝大多数家庭场景但每当看到识别置信度低的提醒我依然会紧张因为我知道那可能与一次用药安全有关。最后再分享一个小技巧如果你也想复现这个项目不要一上来就追求“最先进”的模型架构先用YOLOv8n 自采小数据集把完整流程跑通再逐步增加数据量、优化网络结构。一次端到端的“识别一张真实药丸照片”的体验比一万行理论推演都更能帮你找准方向。做医疗健康工具先握住“能用”的底线再谈“好用”的追求。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →