news 2026/4/18 6:56:36

Yolo-v5血细胞检测实战:训练与部署

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Yolo-v5血细胞检测实战:训练与部署

Yolo-v5血细胞检测实战:训练与部署

在医学影像分析的前沿战场上,自动化血细胞计数正逐步取代传统显微镜下的人工观察。这不仅关乎效率——更直接影响诊断的准确性与一致性。尤其是在急诊、大规模筛查等时间敏感场景中,一个能快速识别红细胞(RBC)、白细胞(WBC)和血小板(Platelets)的AI系统,可能就是医生做出关键决策的关键助力。

而在这类任务中,YOLOv5凭借其“快准稳”的特性脱颖而出。它不像某些模型那样只擅长速度或精度之一,而是巧妙地在两者之间找到了工业级应用所需的平衡点。更重要的是,它的PyTorch实现简洁明了,工程化程度高,从训练到部署几乎无缝衔接。

本文不走理论堆砌的老路,而是带你亲手打造一套完整的血细胞检测流水线:从原始XML标注处理开始,到模型训练、结果可视化,最后落地为可调用的API服务。我们将使用公开的BCCD 数据集作为实战样本,一步步构建属于你的第一个医疗视觉AI产品原型。


整个流程可以分为三个核心阶段:

  • 如何把杂乱的PASCAL VOC格式数据喂给YOLOv5?
  • 怎么用最少的代码跑通一次高质量的训练,并解读关键指标?
  • 模型训完之后,怎么让它走出实验室,在真实环境中“干活”?

别担心没有GPU,也无需成为深度学习专家——只要你会写Python,就能跟下来。


我们先来看一眼手头的数据。BCCD是一个典型的医学图像小数据集,结构清晰但格式不兼容现代目标检测框架:

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

每个XML记录了图像中所有细胞的位置和类别,形式如下:

<object> <name>RBC</name> <bndbox> <xmin>100</xmin> <ymin>80</ymin> <xmax>150</xmax> <ymax>130</ymax> </bndbox> </object>

但YOLOv5不吃这套。它要求标签是.txt文件,内容必须是归一化的xywh格式,也就是:

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

所以第一步,我们必须做一次“翻译”。

!git clone https://github.com/Shenggan/BCCD_Dataset.git

接下来用几行Python读取所有XML并转成DataFrame:

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.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())

输出长这样:

filenameclassxminyminxmaxymax
BloodImage_00000.jpgRBC10080150130

看着整齐多了。

下一步就是坐标转换。YOLO要求中心点+宽高的归一化值,这里我建议固定输入尺寸为640×480(大多数显微图像接近这个比例),避免后续resize带来的失真。

IMG_SIZE = (640, 480) def convert_bbox(xmin, ymin, xmax, ymax, img_w=640, img_h=480): x_center = ((xmin + xmax) / 2) / img_w y_center = ((ymin + ymax) / 2) / img_h width = (xmax - xmin) / img_w height = (ymax - ymin) / img_h return x_center, y_center, width, height from sklearn.preprocessing import LabelEncoder le = LabelEncoder() df['class_id'] = le.fit_transform(df['class']) # ['Platelets' 'RBC' 'WBC'] df[['x_c', 'y_c', 'w', 'h']] = df.apply( lambda row: convert_bbox(row['xmin'], row['ymin'], row['xmax'], row['ymax']), axis=1, result_type='expand' )

现在每条记录都已准备好写入.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) src_img_dir = 'BCCD_Dataset/BCCD/JPEGImages/' def save_labels_and_images(file_list, phase='train'): for fname in file_list: src = os.path.join(src_img_dir, fname) dst_img = f'dataset/images/{phase}/{fname}' shutil.copy(src, dst_img) label_path = f'dataset/labels/{phase}/{fname.replace(".jpg", ".txt")}' rows = df[df.filename == fname] with open(label_path, 'w') as f: for _, row in rows.iterrows(): line = f"{row['class_id']} {row['x_c']:.6f} {row['y_c']:.6f} {row['w']:.6f} {row['h']:.6f}\n" f.write(line) save_labels_and_images(train_files, 'train') save_labels_and_images(val_files, 'val')

搞定!现在数据已经完全符合YOLOv5的要求。


接下来进入训练环节。这一步其实异常简单,因为Ultralytics团队早已把一切都封装好了。

首先克隆官方仓库并安装依赖:

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

然后创建配置文件bcc.yaml,告诉模型你要检测什么:

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

复制过去即可:

cp bcc.yaml yolov5/data/

YOLOv5提供了多个预设模型,你可以根据硬件条件选择:

  • yolov5s:轻量级,适合边缘设备
  • yolov5m:均衡型,推荐默认选择
  • yolov5l/x:重型选手,追求极致精度时启用

我们先拿yolov5s试水:

cd yolov5 !python train.py \ --img 640 \ --batch 16 \ --epochs 100 \ --data bcc.yaml \ --cfg models/yolov5s.yaml \ --weights '' \ --name exp_bcc_s \ --cache

几个关键参数值得说说:

  • --img: 输入分辨率,保持与标注一致即可
  • --batch: 批次大小,如果你显存不够就调小点
  • --weights: 强烈建议加上yolov5s.pt预训练权重,收敛快得多
  • --cache: 如果内存充足,开启后能显著提升数据加载速度

训练过程中可以用TensorBoard实时监控:

%load_ext tensorboard %tensorboard --logdir runs/train

日志里你会看到类似这样的输出:

Epoch gpu_mem box_loss obj_loss cls_loss Instances Size 100/100 2.10G 0.0434 0.0312 0.0198 12 640 Class Images Instances P R mAP@.5 mAP@.5:.95 all 108 472 0.92 0.88 0.91 0.73

重点看这几个指标:

  • Precision (P):你标出来的框有多少是真的?越高越好。
  • Recall (R):真实存在的细胞被找出来多少?太低说明漏检严重。
  • mAP@.5:这是最常用的综合评价指标,>0.9算非常不错了。
  • mAP@.5:.95:跨IoU阈值的平均表现,反映模型鲁棒性。

我们的模型跑了100轮后达到mAP@.5 ≈ 0.91,对于一个小数据集来说已经相当理想。


训练完成后,下一步是看看它到底“看得怎么样”。

YOLOv5自带detect.py脚本,可以直接推理单张图:

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

结果会自动保存在runs/detect/exp/目录下,带边界框和置信度标签。

如果要批量处理整个验证集,只需改个路径:

!python detect.py \ --source ../dataset/images/val/ \ --weights runs/train/exp_bcc_s/weights/best.pt \ --output ../inference_results/ \ --save-txt \ --save-conf

启用--save-txt后,每张图像都会生成对应的.txt文件,格式如下:

0 0.718 0.829 0.143 0.193 0.92 1 0.345 0.612 0.087 0.101 0.87 ...

含义是:class_id x_c y_c w h confidence

如果你想进一步处理这些结果——比如裁剪出每个细胞区域送入分类网络做亚型判断——可以手动解析并绘制:

import matplotlib.pyplot as plt import matplotlib.patches as patches import cv2 def plot_detection(img_path, txt_path, class_names=['Platelets','RBC','WBC']): img = cv2.imread(img_path) img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) h, w, _ = img.shape fig, ax = plt.subplots(1, figsize=(12, 8)) ax.imshow(img_rgb) with open(txt_path, 'r') as f: for line in f.readlines(): parts = list(map(float, line.strip().split())) cls_id, xc, yc, bw, bh, conf = parts cls_id = int(cls_id) x1 = int((xc - bw/2) * w) y1 = int((yc - bh/2) * h) x2 = int((xc + bw/2) * w) y2 = int((yc + bh/2) * h) rect = patches.Rectangle((x1, y1), x2-x1, y2-y1, linewidth=2, edgecolor='r', facecolor='none') ax.add_patch(rect) ax.text(x1, y1, f'{class_names[cls_id]} {conf:.2f}', color='yellow', fontsize=12, backgroundcolor='red') plt.axis('off') plt.show() plot_detection( '../dataset/images/val/BloodImage_00001.jpg', '../inference_results/BloodImage_00001.txt' )

你会发现,即使在密集重叠区域,模型也能较准确地区分不同类型的细胞。这种能力对临床实际意义重大——毕竟真实的血液涂片从来不会规规矩矩排好队。


模型效果满意了,接下来才是真正的挑战:如何把它变成可用的服务?

很多项目止步于notebook里的detect.py,但在生产环境,你需要考虑更多:

  • 用户上传一张图怎么办?
  • 多并发请求会不会崩?
  • 能不能脱离完整YOLOv5仓库运行?

我们可以分三步走。

第一步:轻量化打包

不必携带整个YOLOv5项目,只需提取必要组件:

deploy/ ├── weights/ │ └── best.pt ├── models/ │ └── common.py ├── utils/ │ ├── general.py │ └── datasets.py ├── detect.py ├── requirements.txt └── inference.py

依赖也很精简:

# requirements.txt torch>=1.7.0 torchvision>=0.8.0 numpy opencv-python matplotlib

第二步:封装成函数接口

写一个简单的调用入口,支持CPU/GPU自动切换:

# inference.py import sys sys.path.insert(0, './deploy/') from deploy.detect import run def predict(image_source, output_dir='output'): run( weights='./deploy/weights/best.pt', source=image_source, project=output_dir, name='', exist_ok=True, device='cpu', conf_thres=0.5, iou_thres=0.45, save_txt=True, save_conf=True, view_img=False ) # 使用示例 predict('./input_samples/', './detection_results/')

这样任何外部程序都可以通过导入predict()来使用模型,就像调用普通函数一样自然。

第三步:发布为Web API

最实用的方式是封装成HTTP服务。这里用Flask举个例子:

from flask import Flask, request, jsonify, send_from_directory import os import uuid app = Flask(__name__) UPLOAD_FOLDER = 'uploads' RESULT_FOLDER = 'results' @app.route('/detect', methods=['POST']) def detect_cells(): if 'file' not in request.files: return jsonify({'error': 'No file uploaded'}), 400 file = request.files['file'] if file.filename == '': return jsonify({'error': 'Empty filename'}), 400 filename = str(uuid.uuid4()) + '.jpg' filepath = os.path.join(UPLOAD_FOLDER, filename) file.save(filepath) predict(filepath, RESULT_FOLDER) result_url = f'/results/{filename}' return jsonify({'result_image': result_url}) @app.route('/results/<path:filename>') def serve_result(filename): return send_from_directory(RESULT_FOLDER, filename) if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)

启动后,前端或移动端只需发个POST请求就能拿到检测结果。这种方式特别适合集成进医院LIS系统、远程诊疗平台或便携式检验设备。


回头看这一整套流程,你会发现YOLOv5的强大不仅在于模型本身,更在于它的工程友好性。从数据准备到部署上线,几乎没有断层。这种端到端的流畅体验,正是它能在工业界广泛落地的核心原因。

当然,这只是一个起点。如果你想进一步提升性能,这里有几点实战建议:

  • 换更大的模型:试试yolov5myolov5l,配合COCO预训练权重,精度还能再提几个点;
  • 加强数据增强:Mosaic、HSV颜色扰动、随机仿射变换,都能有效缓解小样本过拟合;
  • 视频追踪延伸:结合DeepSORT,可以在动态血流视频中跟踪单个细胞运动轨迹;
  • 模型导出优化:将.pt转为ONNX甚至TensorRT格式,可在Jetson Nano等嵌入式设备上实现实时推理。

最终的目标不是让AI炫技,而是真正帮医生减轻负担、提高诊断一致性。当你写的模型开始在真实世界中救人时,那种成就感远超任何论文发表。

🎯 让AI服务于临床一线,是我们每一个医疗视觉从业者的使命。

HAPPY CODING ✨

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

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

HunyuanVideo-Foley支持Docker部署,实现AI音效自动化

HunyuanVideo-Foley 支持 Docker 部署&#xff0c;实现 AI 音效自动化 &#x1f3a7;⚡ 你有没有经历过这样的窘境&#xff1a;视频剪辑已经进入尾声&#xff0c;画面节奏完美、转场丝滑&#xff0c;结果卡在了“缺个关门声”“少点风声氛围”这种细节上&#xff1f;找音效库翻…

作者头像 李华
网站建设 2026/4/17 8:56:00

LangFlow在CRM系统智能化升级中的价值

LangFlow在CRM系统智能化升级中的价值 在客户体验成为企业竞争核心的今天&#xff0c;如何让CRM系统真正“懂”客户&#xff0c;而不是仅仅记录客户信息&#xff0c;已成为数字化转型的关键命题。传统CRM依赖预设规则和人工介入处理客户请求&#xff0c;面对复杂多变的服务场景…

作者头像 李华
网站建设 2026/4/17 1:33:34

用Qwen3-VL-8B实现低成本视频理解

用Qwen3-VL-8B实现低成本视频理解 你有没有遇到过这种情况&#xff1a;用户上传了一段操作录屏&#xff0c;你想快速知道“他卡在哪个步骤了”&#xff1b;或者品牌方给了一条60秒的产品视频&#xff0c;你希望自动提炼出卖点文案&#xff0c;而不是逐帧看、手动记&#xff1f;…

作者头像 李华
网站建设 2026/4/17 8:55:59

Langchain-Chatchat 0.3.0保姆级部署指南

Langchain-Chatchat 0.3.0 部署实战&#xff1a;从零构建私有化知识问答系统 在企业级 AI 应用中&#xff0c;如何安全、高效地将大模型与内部知识库结合&#xff0c;已成为技术选型的关键。Langchain-Chatchat 自开源以来&#xff0c;凭借其对中文场景的深度优化和灵活的架构…

作者头像 李华
网站建设 2026/4/17 8:55:59

ComfyUI常用节点及安装避坑指南

ComfyUI常用节点及安装避坑指南 在AI图像生成的工具版图中&#xff0c;WebUI&#xff08;A1111&#xff09;像是一台功能齐全的“傻瓜相机”——点一下就能出图&#xff1b;而 ComfyUI 更像是专业摄影师手中的模块化单反系统&#xff1a;每一个组件都可拆卸、组合、精确调控。…

作者头像 李华
网站建设 2026/4/17 8:55:56

vLLM-Ascend部署Qwen3-Next大模型指南

vLLM-Ascend 部署 Qwen3-Next 大模型实战指南 在当前企业级大模型推理场景中&#xff0c;如何在保证高吞吐、低延迟的同时充分利用国产算力平台的性能潜力&#xff0c;已成为AI基础设施建设的关键挑战。华为 Ascend 910B&#xff08;Atlas A2/A3 系列&#xff09;凭借其强大的N…

作者头像 李华