news 2026/4/3 6:51:41

YOLOv5实战:血细胞检测与定位

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
YOLOv5实战:血细胞检测与定位

YOLOv5实战:血细胞检测与定位

在显微镜下,一滴血液中可能包含数以千计的红细胞、白细胞和血小板。传统临床检验依赖人工计数,不仅效率低,还容易因视觉疲劳导致误差。如今,随着深度学习技术的成熟,我们完全可以用一个轻量级AI模型,在几秒钟内完成对整张血涂片图像的精准分析。

这正是目标检测算法真正闪光的地方——它不只是“识别”某个物体存在,而是能精确定位每一个细胞的位置,并区分其类型。而在这类任务中,YOLOv5凭借其端到端的设计、快速收敛的能力以及出色的精度-速度平衡,成为医疗影像自动化处理的理想选择。

本文将带你从零开始构建一个完整的血细胞检测系统:从原始XML标注数据的清洗转换,到模型训练调优,再到推理部署上线。整个过程不依赖复杂框架,只需标准工具链即可完成,适合科研、教学或实际项目快速验证。


数据预处理:让医学图像适配AI模型

YOLO系列模型要求输入标签为特定格式的文本文件(.txt),每行表示一个归一化的边界框:

<class_id> <x_center_norm> <y_center_norm> <width_norm> <height_norm>

但大多数公开医学数据集,如BCCD (Blood Cell Count Dataset),使用的是PASCAL VOC标准的XML格式。因此第一步就是做数据转换。

原始结构与解析逻辑

BCCD的数据组织如下:

BCCD_Dataset/ ├── Annotations/ # XML标注 │ ├── BloodImage_00000.xml │ └── ... ├── JPEGImages/ # 图像文件 │ ├── BloodImage_00000.jpg │ └── ...

每个XML中记录了多个对象(RBC、WBC、Platelets)及其坐标(xmin, ymin, xmax, ymax)。我们需要提取这些信息并转换为YOLO所需格式。

import os import xml.etree.ElementTree as ET from glob import glob import pandas as pd annotations = sorted(glob('BCCD_Dataset/BCCD/Annotations/*.xml')) data = [] for file in annotations: filename = os.path.basename(file).replace('.xml', '.jpg') tree = ET.parse(file) root = tree.getroot() for obj in root.findall('object'): cls_name = obj.find('name').text.lower().strip() bbox = obj.find('bndbox') xmin = int(bbox.find('xmin').text) ymin = int(bbox.find('ymin').text) xmax = int(bbox.find('xmax').text) ymax = int(bbox.find('ymax').text) data.append([filename, cls_name, xmin, ymin, xmax, ymax]) df = pd.DataFrame(data, columns=['filename', 'class', 'xmin', 'ymin', 'xmax', 'ymax']) print(df.head())

这段代码会生成一个统一的数据表,便于后续批量处理。

坐标归一化:关键一步

YOLO要求所有坐标相对于图像尺寸进行归一化。假设图像宽高为640x480,则转换函数如下:

def convert_to_yolo(row, img_w=640, img_h=480): x_center = (row['xmin'] + row['xmax']) / 2.0 y_center = (row['ymin'] + row['ymax']) / 2.0 width = row['xmax'] - row['xmin'] height = row['ymax'] - row['ymin'] return [ class_mapping[row['class']], x_center / img_w, y_center / img_h, width / img_w, height / img_h ] class_names = ['platelets', 'rbc', 'wbc'] class_mapping = {cls: idx for idx, cls in enumerate(class_names)}

注意:虽然BCCD图像的实际分辨率是640x480,但在训练时可通过--img参数动态调整大小,不影响模型泛化能力。

构建标准目录结构

YOLOv5 推荐使用以下路径布局:

dataset/ ├── images/ │ ├── train/ │ └── val/ └── labels/ ├── train/ └── val/

通过简单划分训练集和验证集(8:2),我们可以自动化复制图像并写入对应.txt文件:

from sklearn.model_selection import train_test_split import shutil train_files, val_files = train_test_split(df['filename'].unique(), test_size=0.2, random_state=42) os.makedirs('dataset/images/train', exist_ok=True) os.makedirs('dataset/images/val', exist_ok=True) os.makedirs('dataset/labels/train', exist_ok=True) os.makedirs('dataset/labels/val', exist_ok=True) def save_dataset(files, phase='train'): for fname in files: src_img = f'BCCD_Dataset/BCCD/JPEGImages/{fname}' dst_img = f'dataset/images/{phase}/{fname}' shutil.copy(src_img, dst_img) label_file = f'dataset/labels/{phase}/{fname.replace(".jpg", ".txt")}' with open(label_file, 'w') as f: rows = df[df['filename'] == fname] for _, row in rows.iterrows(): yolo_row = convert_to_yolo(row) f.write(' '.join(map(str, yolo_row)) + '\n') save_dataset(train_files, 'train') save_dataset(val_files, 'val')

至此,数据已完全准备好,可以直接接入YOLOv5训练流程。


模型训练:高效利用预训练权重

克隆仓库与安装依赖

YOLOv5由Ultralytics官方维护,代码清晰且文档完善:

git clone https://github.com/ultralytics/yolov5.git pip install -r yolov5/requirements.txt

无需额外配置环境,PyTorch + CUDA支持开箱即用。

定义数据配置文件bcc.yaml

将该文件放入yolov5/data/目录下:

# bcc.yaml train: ../dataset/images/train val: ../dataset/images/val nc: 3 names: ['Platelets', 'RBC', 'WBC']

路径使用相对引用,确保跨平台兼容性。

选择合适模型版本

YOLOv5提供多种规模模型:
-yolov5s: 小型,速度快,适合边缘设备
-yolov5m: 中型,精度更高,推荐用于小目标密集场景
-yolov5l/x: 更大模型,资源消耗高,提升有限

对于血细胞这类小而密集的目标,建议优先尝试yolov5syolov5m。实测表明,yolov5s在保持实时性的同时仍能达到良好mAP。

启动训练命令

python yolov5/train.py \ --img 640 \ --batch 16 \ --epochs 150 \ --data bcc.yaml \ --weights yolov5s.pt \ --cfg yolov5s.yaml \ --name blood_cell_detection \ --cache
关键参数说明:
参数作用
--img输入图像尺寸,影响感受野和细节保留
--batch批次大小,根据GPU显存调整(16适用于12GB显卡)
--epochs训练轮数,BCCD较小,100~150足够
--weights加载COCO预训练权重,显著加快收敛
--cache缓存图像至内存,提速约30%

💡 实践建议:首次训练可设为50轮观察趋势;若loss持续下降,则延长至150轮以上。

监控训练过程

启用TensorBoard查看指标变化:

%load_ext tensorboard %tensorboard --logdir runs/train

典型输出日志:

Epoch gpu_mem box obj cls total targets img_size 100/150 4.71G 0.0521 0.0392 0.0183 0.1096 489 640 Class Images Instances P R mAP@.5 mAP@.5:.95 all 270 489 0.912 0.887 0.901 0.673

解释几个核心指标:
-Precision (P):预测正确的阳性样本比例 → 避免误检
-Recall (R):真实阳性能被检出的比例 → 避免漏检
-mAP@.5:IoU阈值0.5下的平均精度,主流评价标准
-mAP@.5:.95:多IoU阈值下的综合表现,更严格

mAP@.5 > 0.9时,说明模型已具备较强泛化能力,可用于实际测试。


推理与可视化:看见AI“看”到了什么

训练完成后,最佳权重保存在:

runs/train/blood_cell_detection/weights/best.pt

单图推理示例

python yolov5/detect.py \ --source dataset/images/val/BloodImage_00000.jpg \ --weights runs/train/blood_cell_detection/weights/best.pt \ --conf-thres 0.5 \ --iou-thres 0.45 \ --device 0

参数说明:
---conf-thres: 置信度阈值,过滤弱预测(默认0.25)
---iou-thres: NMS阈值,控制重叠框合并(推荐0.45~0.5)

批量推理与结果导出

python yolov5/detect.py \ --source dataset/images/val/ \ --weights runs/train/blood_cell_detection/weights/best.pt \ --output inference_output \ --save-txt \ --save-conf

输出目录包含:
- 带边框标记的图像
- 每个图像对应的.txt文件(含类别、置信度)

自定义可视化函数

如果你想进一步处理检测结果(例如裁剪单个细胞送入分类网络),可以编写解析脚本:

import matplotlib.pyplot as plt import cv2 from matplotlib import patches def plot_predictions(image_path, label_path, class_names=['Platelets','RBC','WBC']): img = plt.imread(image_path) fig, ax = plt.subplots(1, figsize=(12, 9)) ax.imshow(img) colors = {'Platelets': 'green', 'RBC': 'red', 'WBC': 'blue'} if os.path.exists(label_path): with open(label_path, 'r') as f: lines = f.readlines() for line in lines: parts = list(map(float, line.strip().split())) cls_id, x_c, y_c, w, h, conf = int(parts[0]), *parts[1:6] H, W, _ = img.shape x_c *= W; y_c *= H; w *= W; h *= H x1 = x_c - w / 2; y1 = y_c - h / 2 rect = patches.Rectangle((x1, y1), w, h, linewidth=2, edgecolor=colors[class_names[cls_id]], facecolor='none') ax.add_patch(rect) ax.text(x1, y1, f"{class_names[cls_id]} {conf:.2f}", color='white', fontsize=12, bbox=dict(facecolor=colors[class_names[cls_id]], alpha=0.7)) plt.axis('off') plt.show() # 调用示例 plot_predictions( 'dataset/images/val/BloodImage_00000.jpg', 'inference_output/BloodImage_00000.txt' )

这个函数不仅能显示位置,还能叠加置信度,帮助判断模型不确定性区域。


部署落地:从Jupyter Notebook走向生产服务

模型训练只是起点,真正的价值在于集成进实际系统。为了实现轻量化部署,我们可以剥离冗余组件,仅保留必要模块。

最小化部署包结构

production_model/ ├── best.pt # 导出的权重 ├── detect.py # 精简推理脚本 ├── utils/ │ ├── general.py │ ├── datasets.py │ └── torch_utils.py ├── requirements.txt # torch, torchvision, numpy, opencv-python └── app.py # REST API封装

这样打包后体积通常小于100MB,适合嵌入式设备或容器化部署。

快速搭建REST API服务

使用Flask构建一个简单的HTTP接口:

from flask import Flask, request, jsonify import torch import cv2 import numpy as np app = Flask(__name__) model = torch.hub.load('ultralytics/yolov5', 'custom', path='best.pt') @app.route('/detect', methods=['POST']) def detect_cells(): file = request.files['image'] img_bytes = file.read() nparr = np.frombuffer(img_bytes, np.uint8) img = cv2.imdecode(nparr, cv2.IMREAD_COLOR) results = model(img) detections = results.pandas().xyxy[0].to_dict(orient='records') return jsonify(detections) if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)

启动服务后即可通过curl发送请求:

curl -X POST -F "image=@BloodImage_00000.jpg" http://localhost:5000/detect

返回JSON格式结果,易于前端、移动端或其他系统调用。

⚠️ 注意事项:
- 生产环境中应增加异常处理、图像校验和限流机制
- 可结合Redis缓存高频请求结果
- 对延迟敏感场景建议使用FastAPI替代Flask


写在最后:不止于“检测”

本次实战展示了如何用YOLOv5解决一个典型的医学图像分析问题。但它的潜力远不止于此:

  • 扩展方向1:引入更大模型
    如切换至YOLOv8YOLOv10,它们在Anchor-Free设计、损失函数优化等方面有显著改进,尤其适合小目标检测。

  • 扩展方向2:融合分割能力
    结合Segment Anything Model (SAM)YOLACT,不仅可以定位细胞,还能提取精确轮廓,用于形态学分析(如镰状红细胞识别)。

  • 扩展方向3:边缘部署
    使用ONNXTensorRT将模型导出为高效推理格式,部署至 Jetson Nano、树莓派等低成本硬件,实现实验室本地化运行。

更重要的是,这种端到端的AI解决方案正在改变基层医疗的工作方式。过去需要专业技师花半小时完成的任务,现在一台智能显微镜就能自动完成,极大提升了诊断效率与一致性。

技术的价值,不在于多么先进,而在于能否真正解决问题。YOLOv5或许不是最前沿的模型,但它足够稳定、易用、可复现,正适合推动AI在医疗领域的普惠落地。

🔧 开源精神,造福社会 —— 每一次代码提交,都可能是未来某位医生手中拯救生命的工具。

HAPPY CODING ✨

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/22 16:14:33

《高质量 C++/C 编程指南》注释规范 + VS2022 模板

本文简单整理了一下《高质量 C/C 编程指南》注释规范&#xff0c;并非原创且作者在书中已明确准许引用一、核心注释规则&#xff08;原文引用 极简解读&#xff09;1. 位置要求【规则 2-7-6】注释应与其描述的代码相近&#xff0c;放上方&#xff08;长注&#xff09;或右方&a…

作者头像 李华
网站建设 2026/4/3 6:07:11

ComfyUI节点手动安装与更新完整指南

ComfyUI节点手动安装与更新完整指南 在使用 ComfyUI 构建复杂AI图像生成工作流时&#xff0c;自定义节点是扩展功能、提升效率的核心手段。无论是接入ControlNet控制生成姿态&#xff0c;还是集成LoRA微调模型&#xff0c;亦或是引入高级采样逻辑&#xff0c;绝大多数高级功能都…

作者头像 李华
网站建设 2026/3/28 9:28:45

Elsa工作流版本管理终极指南:从混乱到有序的简单解决方案

Elsa工作流版本管理终极指南&#xff1a;从混乱到有序的简单解决方案 【免费下载链接】elsa-core A .NET workflows library 项目地址: https://gitcode.com/gh_mirrors/el/elsa-core 你是否曾因工作流版本混乱而头疼&#xff1f;当团队多人协作时&#xff0c;版本冲突、…

作者头像 李华
网站建设 2026/3/27 17:46:47

vxe-table 升级到最新版本后虚拟滚动没有老版本流畅的解决方法

vxe-table 升级到最新版本后虚拟滚动没有老版本流畅的解决方法&#xff0c; https://vxetable.cn import { VxeUI } from vxe-tableVxeUI.setConfig({table: {virtualYConfig: {mode: scroll // 老版本默认 default | scroll &#xff0c;新版本默认 wheel}} })两种模式各有优…

作者头像 李华
网站建设 2026/4/1 1:56:48

Vue.js 报错:Expecting a value with a valid format

Vue.js 报错&#xff1a;Expecting a value with a valid format —— 3 分钟搞定「格式不符」警告 正文目录 报错含义&#xff1a;Vue 在挑剔什么格式&#xff1f;4 大高频翻车场景 & 修复代码万能兜底工具&#xff1a;校验器与默认值预防 checklist&#xff08;不再踩坑…

作者头像 李华
网站建设 2026/3/27 18:17:19

105-Spark之Standalone HA环境搭建过程

一、高可用的HA 单点故障的问题是无法避免的问题&#xff0c;如何解决这个单点故障的问题&#xff0c;Spark提供了两种方案&#xff1a; 1.基于文件系统的单点恢复(Single-Node Recovery with Local File System)-只能用于开发或测试环境。 2.基于zookeeper的Standby Masters(S…

作者头像 李华