1. 项目概述
这个基于YOLOv11的硬币识别系统是我最近完成的一个很有意思的计算机视觉项目。作为一个经常需要处理零钱的便利店店主,我一直在寻找能自动识别和统计硬币的解决方案。市面上的商用设备要么太贵,要么识别准确率不够理想。于是我用最新的YOLOv11目标检测算法,开发了这个高精度的硬币识别系统。
系统能够准确识别四种常见美国硬币:Dime(10美分)、Nickel(5美分)、Penny(1美分)和Quarter(25美分)。在实际测试中,即使在复杂背景下(如杂乱的桌面或钱包内),识别准确率也能达到95%以上。除了核心的识别功能外,我还为系统开发了完整的用户界面,包括登录注册、参数配置和多种检测模式,使其成为一个真正可用的工具而非单纯的算法demo。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术选型与架构设计
2.1 为什么选择YOLOv11
在目标检测领域,YOLO系列一直以速度和精度的平衡著称。我选择最新的YOLOv11主要基于以下几个考虑:
-
实时性需求:硬币识别可能需要处理视频流或摄像头实时画面,YOLOv11的推理速度能满足实时性要求。在我的测试中,在RTX 3060显卡上能达到45FPS的处理速度。
-
小目标检测能力:硬币相对于整个画面来说属于小目标,YOLOv11针对小目标检测做了专门优化,其多尺度特征融合机制能更好地捕捉硬币特征。
-
模型轻量化:YOLOv11提供了从nano到x不同规模的预训练模型,可以根据硬件条件灵活选择。我最终选择了yolov11s模型,在精度和速度间取得了良好平衡。
2.2 系统架构设计
整个系统采用模块化设计,主要分为以下几个组件:
code复制├── 核心检测引擎
│ ├── YOLOv11模型
│ ├── 图像预处理模块
│ └── 后处理模块
├── 用户界面
│ ├── 登录/注册系统
│ ├── 主控制面板
│ └── 结果显示区域
├── 数据管理
│ ├── 账户存储
│ └── 结果保存
└── 工具链
├── 数据集准备工具
└── 模型训练脚本
这种架构使得各个功能模块相对独立,便于后期维护和功能扩展。例如,如果想增加新的硬币种类,只需要更新数据集并重新训练模型,其他模块几乎不需要改动。
3. 数据集准备与模型训练
3.1 硬币数据集的构建
高质量的数据集是模型准确性的基础。我收集了约5000张包含各种美国硬币的图像,涵盖了不同场景:
- 单一硬币特写
- 多硬币堆叠
- 复杂背景下的硬币
- 不同光照条件下的硬币
- 各种角度的硬币图像
使用LabelImg工具手动标注了所有图像,生成YOLO格式的标注文件。标注时特别注意了几个要点:
- 确保标注框紧密贴合硬币边缘
- 对于部分遮挡的硬币也进行标注
- 标注了一定数量的负样本(不含硬币的图像)
数据集按7:2:1的比例划分为训练集、验证集和测试集。目录结构如下:
code复制dataset/
├── train/
│ ├── images/
│ └── labels/
├── val/
│ ├── images/
│ └── labels/
└── test/
├── images/
└── labels/
3.2 数据增强策略
为了提高模型的泛化能力,训练时采用了多种数据增强技术:
python复制# 数据增强配置示例
augmentations = {
'hsv_h': 0.015, # 色相增强
'hsv_s': 0.7, # 饱和度增强
'hsv_v': 0.4, # 明度增强
'rotate': 10, # 旋转角度
'translate': 0.1, # 平移
'scale': 0.5, # 缩放
'shear': 0.0, # 剪切
'perspective': 0.0005, # 透视变换
'flipud': 0.0, # 上下翻转
'fliplr': 0.5, # 左右翻转
'mosaic': 1.0, # 马赛克增强
'mixup': 0.1 # MixUp增强
}
特别针对硬币识别任务,我增加了旋转和明度增强的比例,因为硬币在实际场景中可能以各种角度出现,且反光情况各异。
3.3 模型训练过程
使用Ultralytics框架进行模型训练,主要参数配置如下:
python复制model = YOLO('yolov11s.pt') # 加载预训练模型
results = model.train(
data='data.yaml',
epochs=100,
batch=8,
imgsz=640,
device='0', # 使用GPU 0
workers=4,
patience=10, # 早停机制
lr0=0.01, # 初始学习率
lrf=0.01, # 最终学习率
momentum=0.937,
weight_decay=0.0005,
warmup_epochs=3,
warmup_momentum=0.8,
box=7.5, # box损失权重
cls=0.5, # 分类损失权重
dfl=1.
