基于YOLOv11的美国硬币识别系统开发实践

1. 项目概述

这个基于YOLOv11的美国硬币识别系统是我最近完成的一个计算机视觉项目,它能够准确识别四种常见美国硬币:Dime(10美分)、Nickel(5美分)、Penny(1美分)和Quarter(25美分)。作为一个经常需要处理硬币分类问题的开发者,我发现市面上的通用识别方案往往在硬币这种小物体检测上表现不佳,特别是在复杂背景下。于是决定基于最新的YOLOv11算法开发这个专用解决方案。

系统最突出的特点是实现了95%以上的检测准确率,这得益于三个关键设计:首先采用了专门标注的硬币数据集;其次优化了YOLOv11对小物体的检测能力;最后通过多线程架构确保了实时性能。整个项目用Python实现,包含完整的训练代码、预训练模型和带登录功能的用户界面,非常适合需要硬币自动识别场景的开发者参考,比如自动售货机、银行清分系统等应用。

2. 技术架构解析

2.1 YOLOv11模型选型

选择YOLOv11作为基础模型主要基于以下考量:

  • 实时性需求:相比两阶段检测器(如Faster R-CNN),单阶段检测的YOLO系列更符合硬币检测对速度的要求。实测在RTX 3060显卡上,YOLOv11s模型能达到120FPS的处理速度。
  • 小物体检测优化:YOLOv11针对小目标新增了SPPFCSPC模块,通过扩大感受野提升对小硬币的检测能力。我们在neck部分保留了4个检测头(80x80到10x10),确保不同尺度硬币都能被有效捕捉。
  • 模型轻量化:项目提供了从nano到large五种预训练模型,其中yolov11s.pt在准确率(91.3%mAP)和速度(15ms/帧)间取得了最佳平衡。

2.2 数据处理管道

数据集构建是项目成功的关键。我们收集了2000张包含四种硬币的图像,涵盖以下场景:

  • 不同光照条件(自然光、室内灯光、低光照)
  • 复杂背景(桌面、手掌、包装袋)
  • 多硬币重叠情况
  • 不同拍摄角度(正面、侧面、倾斜)

标注采用YOLO格式,每个硬币标注为:

<class_id> <x_center> <y_center> <width> <height>

其中归一化坐标的计算公式为:

x_center = (x_min + x_max) / 2 / image_width y_center = (y_min + y_max) / 2 / image_height width = (x_max - x_min) / image_width height = (y_max - y_min) / image_height

2.3 多线程架构设计

系统采用生产者-消费者模式解决UI响应问题:

  1. 主线程:处理用户交互和界面更新,通过信号槽机制与检测线程通信
  2. 检测线程:继承QThread类,独立运行检测算法。关键代码段:
class DetectionThread(QThread): frame_received = pyqtSignal(np.ndarray, np.ndarray, list) def run(self): while self.running: ret, frame = self.cap.read() results = self.model(frame) self.frame_received.emit(original_frame, result_frame, detections)
  1. 视频写入线程:当启用视频保存时,通过OpenCV的VideoWriter异步写入文件

这种架构即使在处理1080p视频时,也能保持界面流畅响应,CPU占用率控制在30%以下。

3. 核心实现细节

3.1 模型训练优化

训练配置采用以下关键参数:

lr0: 0.01 # 初始学习率 lrf: 0.1 # 最终学习率=lr0*lrf momentum: 0.937 weight_decay: 0.0005 warmup_epochs: 3 batch: 8 # 根据GPU显存调整

我们通过两种策略提升小硬币检测效果:

  1. 自适应锚框计算:在data.yaml中预设硬币的典型尺寸:
anchors: - [4,5, 8,10, 13,16] # P3/8 - [23,29, 43,55, 73,105] # P4/16 - [146,217, 231,300, 335,433] # P5/32
  1. 马赛克增强:启用4图拼接增强,大幅提升小目标检测鲁棒性

3.2 界面交互实现

UI采用PyQt5实现,主要技术亮点包括:

  1. 双视图同步显示:通过QLabel+QPixmap实现实时画面更新
def update_image(self, q_img): pixmap = QPixmap.fromImage(q_img) self.label.setPixmap(pixmap.scaled( self.label.size(), Qt.KeepAspectRatio))
  1. 参数联动控制:置信度和IoU阈值使用QSlider与QDoubleSpinBox双向绑定
self.conf_slider.valueChanged.connect( lambda v: self.conf_spin.setValue(v/100)) self.conf_spin.valueChanged.connect( lambda v: self.conf_slider.setValue(int(v*100)))
  1. 科幻风格主题:通过QSS实现动态光影效果
QSlider::groove:horizontal { border: 1px solid #00ffff; height: 5px; background: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #003333, stop:1 #00aaaa); }

3.3 检测结果后处理

从YOLO输出提取检测信息的核心逻辑:

def parse_detection(results): detections = [] for box in results.boxes: cls = int(box.cls) conf = float(box.conf) xywh = box.xywh[0].tolist() detections.append({ 'class': model.names[cls], 'confidence': conf, 'position': xywh }) return detections

对于视频流处理,额外增加了基于IOU的去重算法,防止同一硬币在连续帧中被重复计数。

4. 部署与优化指南

4.1 环境配置要点

推荐使用conda创建隔离环境:

conda create -n coin_det python=3.9 conda activate coin_det pip install torch==1.13.1+cu117 torchvision==0.14.1+cu117 --extra-index-url https://download.pytorch.org/whl/cu117 pip install -r requirements.txt

常见问题解决方案:

  1. CUDA版本冲突:可通过nvcc --version查看CUDA版本,必须与PyTorch版本匹配
  2. DLL加载失败:安装对应版本的VC_redist运行时库
  3. 界面卡顿:检查是否启用了GPU加速,可通过torch.cuda.is_available()验证

4.2 模型压缩技巧

针对边缘设备部署,我们测试了三种优化方案:

  1. FP16量化:模型大小减少50%,速度提升20%,精度损失<1%
model.export(format='onnx', half=True)
  1. TensorRT加速:通过trtexec工具转换ONNX模型,可获得3-5倍速度提升
  2. Pruning剪枝:使用torch-pruner移除20%的冗余通道,模型体积减少35%

4.3 实际应用建议

根据落地经验,给出以下优化建议:

  1. 光照补偿:在低光环境下,建议先使用CLAHE算法增强对比度
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) enhanced = clahe.apply(gray)
  1. 多角度检测:对于叠放的硬币,建议从至少两个不同角度拍摄
  2. 动态阈值调整:根据环境光线自动调节置信度阈值
adaptive_conf = 0.5 - 0.3*(image_brightness/255)

5. 常见问题排查

5.1 检测精度问题

症状:漏检或误检率高

  • 检查数据集:确认标注是否准确,特别是边缘模糊的硬币
  • 调整锚框:使用k-means重新计算anchors
from utils.autoanchor import kmean_anchors kmean_anchors(dataset='data.yaml', n=9, img_size=640)
  • 增强策略:增加旋转、模糊等数据增强

5.2 性能问题

症状:检测速度慢

  1. 检查硬件加速:确认torch是否使用GPU
print(torch.cuda.current_device()) # 应返回0或以上
  1. 降低输入分辨率:将640x640调整为480x480
results = model(img, imgsz=480)
  1. 启用半精度:FP16模式可提升30%速度
model.half() # 转换模型权重为FP16

5.3 界面异常处理

典型错误

  1. 摄像头无法打开:检查设备索引号,多摄像头时可能需要尝试0-3
  2. 视频播放卡顿:降低解码分辨率或使用硬件加速
cap = cv2.VideoCapture(file_path, cv2.CAP_FFMPEG) cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*'H264'))
  1. 内存泄漏:定期清理Qt缓存对象
def clear_memory(self): for label in [self.orig_label, self.result_label]: if label.pixmap(): label.pixmap().detach()

6. 扩展开发方向

当前系统已经支持以下扩展接口:

  1. REST API集成:通过Flask添加HTTP接口
@app.route('/detect', methods=['POST']) def detect(): img = request.files['image'].read() results = model(img) return jsonify(results)
  1. 数量统计模块:扩展硬币计数功能
def count_coins(detections): counts = defaultdict(int) for det in detections: counts[det['class']] += 1 return counts
  1. 金额计算:根据硬币类型自动求和
VALUE_MAP = {'Penny':0.01, 'Nickel':0.05, 'Dime':0.10, 'Quarter':0.25} total = sum(VALUE_MAP[det['class']] for det in detections)

对于需要更高精度的场景,建议尝试以下改进:

  1. 增加红外成像模块处理反光硬币
  2. 集成重量传感器进行多模态验证
  3. 使用超分辨率网络预处理低质量图像