
当我在实际项目中接到“识别条形码并判断保质期”这个需求时第一反应是这不就是一个扫码枪加一个数据库就搞定的事情吗真正动手后才发现生产环境远没有这么简单条形码可能倾斜、模糊、反光包装上的保质期印刷位置不固定字体五花八门甚至有些日期是喷码、压印传统图像处理根本搞不定。后来我逐步验证了一套方案用 YOLOv8 或 YOLOv5 训练一个目标检测模型在画面中定位条形码区域和保质期文字区域再用 pyzbar 解析条形码用 OCR 配合正则提取保质期信息最后通过 PySide6 把整个流程封装成一个桌面应用。整套流程做下来识别稳定性、易用性和工程可维护性都达到了可交付的标准。本文将这套实践完整拆解出来适合正在做工业视觉识别、自动化录入、库存管理系统的开发者参考也适合想系统学习 YOLOv8 与 PySide6 结合开发的朋友从零开始搭建一套属于自己的检测识别系统。1. 背景与核心概念1.1 条形码保质期识别系统是什么条形码保质期识别检测系统指的是通过摄像头或图像输入自动完成以下任务的软件系统定位图像中的条形码区域解析条形码内容通常是商品编码定位包装上的保质期或生产日期区域识别日期文本并结构化输出将结果录入数据库或展示在交互界面中。听起来并不复杂但实际落地时难点集中在两个地方一是条形码和日期区域在复杂背景下的定位二是日期字符的准确识别。不同商品的包装材质、颜色、印刷工艺差异巨大如果只靠固定 ROI 截取几乎无法通用。这时目标检测模型就派上了用场。1.2 YOLOv8 和 YOLOv5 在系统中的角色YOLOYou Only Look Once是一种单阶段目标检测算法核心思想是通过一次前向传播同时预测目标的类别和位置。YOLOv5 和 YOLOv8 是当前工业落地中使用率非常高的两个版本。在本系统中YOLO 模型负责两件事条形码检测输出条形码的边界框使后续解析不需要在全图中扫描保质期文本检测定位包装上的日期区域避免 OCR 面对整个包装上的大量无关文字。YOLOv8 相比 YOLOv5在结构上引入了 C2f 模块和 Anchor-Free 检测头训练收敛更快小目标检测能力更强。但 YOLOv5 生态成熟部署资料多在部分硬件上推理速度更快。实际项目中两者都可以作为检测底座本文将以 YOLOv8 为主同时说明用 YOLOv5 时需要注意的差异。1.3 PySide6 为什么适合做桌面端外壳PySide6 是 Qt 6 的 Python 官方绑定常用于开发桌面 GUI 应用。相比 Tkinter 和 PyQtPySide6 的优势在于官方维护License 对开源项目友好信号槽机制非常适合多线程任务QThread 可以优雅地处理摄像头采集和模型推理QSS 支持样式定制界面可以做得比较美观。在本项目中PySide6 承担了以下职责显示摄像头实时画面或图片触发检测按钮并展示结果多线程管理避免模型推理阻塞界面提供条形码内容和保质期日期的可视化输出。1.4 辅助技术pyzbar、OpenCV、OCRpyzbar用于解析条形码和二维码底层基于 ZBar支持 Code128、EAN-13、UPC-A 等多种码制OpenCV负责图像读取、预处理、绘制检测框、摄像头调用OCR光学字符识别用于识别保质期文本常用方案有 PaddleOCR、Tesseract、RapidOCR。本文以 PaddleOCR 为例因为它对中文和印刷体日期支持较好。2. 系统整体架构与方案选型2.1 整体架构图整个系统可以用一句话概括采集图像 - YOLO 定位 - 条形码解析 OCR 日期识别 - 结构化输出 - PySide6 展示。用文字描述各模块职责如下图像采集模块支持摄像头实时流、单张图片、批量文件夹三种输入方式目标检测模块加载训练好的 YOLOv8/YOLOv5 模型检测条形码和保质期区域条形码解析模块对检测到的条形码区域做灰度化和解码日期识别模块对检测到的保质期区域做 OCR再通过正则提取日期业务逻辑模块判断保质期是否过期、是否临期界面展示模块基于 PySide6 实现。2.2 为什么不用传统图像处理方案传统方案通常依赖形态学操作、边缘检测、连通域分析来定位条形码例如通过计算梯度直方图或形态学闭运算提取条形码区域。这种方法在背景干净、光照均匀的场景下效果尚可但一旦遇到复杂纹理包装、条形码被遮挡或倾斜稳定性就会明显下降。保质期文本定位就更难了不同厂家的包装设计风格差异太大有些日期印在侧面有些印在封口处有些是喷码形式。基于规则的图像处理方法很难覆盖这么多变化。YOLO 模型只需要标注数据足够多、覆盖场景足够广就能学习到“条形码长什么样”“日期区域长什么样”的通用特征鲁棒性远高于传统方案。2.3 技术选型对比功能模块可选方案推荐理由目标检测YOLOv8 / YOLOv5成熟、部署简单、精度高条形码解析pyzbar支持码制多、接口简单日期识别PaddleOCR / Tesseract中文效果好、可离线部署GUI 框架PySide6 / PyQt5信号槽机制适合多线程图像处理OpenCV生态完善、资料丰富需要说明的是如果检测场景只有条形码没有保质期识别需求可以直接使用 OpenCV 的 barcode 模块不需要训练 YOLO 模型。但本项目要求同时检测两个目标并各自分流处理统一使用 YOLO 做定位是最省心的方案。3. 环境准备与版本说明3.1 开发环境一览本文示例环境如下具体版本请根据你的项目实际情况调整重点演示配置思路。操作系统Windows 10 / 11Linux 和 macOS 也可以摄像头调用方式略有不同Python3.9 / 3.10 / 3.11深度学习框架PyTorch 2.xYOLO 工具包ultralyticsGUI 框架PySide6图像处理opencv-python条形码解析pyzbarOCRPaddleOCR 或 RapidOCR。不同版本的依赖之间可能存在兼容性问题例如 Python 3.12 早期对部分库的 wheel 支持不完善建议优先使用 Python 3.10。3.2 安装核心依赖建议先创建虚拟环境再安装依赖。conda create -n barcode_yolo python3.10 -y conda activate barcode_yolo安装 PyTorch 时需要根据自己机器是否有 NVIDIA GPU 选择命令。CPU 环境下也可以运行但推理速度会慢一些。# GPU 版本需提前安装 CUDA 驱动具体命令参考 PyTorch 官网 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # CPU 版本 pip install torch torchvision安装其他依赖pip install ultralytics pyside6 opencv-python pyzbar paddleocr paddlepaddle如果 pyzbar 在 Windows 下安装失败通常是因为缺少 Visual C 运行库或者需要手动安装 ZBar。可以使用下面的命令尝试pip install pyzbar如果 import pyzbar 时提示找不到 libzbar-0.dll需要前往 ZBar 官网下载 Windows 动态库并将 DLL 所在目录加入系统 PATH。3.3 验证安装是否成功依次运行以下代码确认环境没有问题import torch import ultralytics import cv2 import PySide6 import pyzbar print(torch:, torch.__version__) print(ultralytics:, ultralytics.__version__) print(opencv:, cv2.__version__) print(pyzbar:, pyzbar.__version__ if hasattr(pyzbar, __version__) else ok)如果 PySide6 安装正常运行下面的代码会弹出一个空白窗口import sys from PySide6.QtWidgets import QApplication, QLabel app QApplication(sys.argv) label QLabel(PySide6 安装成功) label.show() app.exec()4. 训练 YOLOv8 模型用于条形码和保质期区域检测4.1 数据集准备YOLO 模型需要的数据集包含两部分图片和标注文件。标注文件是 txt 格式每一行代表一个目标格式如下class_id x_center y_center width height其中x_center、y_center、width、height都是相对于图片宽高的归一化值。标注两个类别类别 0barcode条形码类别 1expiry_date保质期/生产日期区域。建议使用 LabelImg 或 X-AnyLabeling 标注工具。标注时注意以下原则条形码区域尽量贴合边缘不要包含过多背景保质期区域完整框住印刷日期如果日期被遮挡建议放弃该样本收集的数据要覆盖不同光照、不同角度、不同包装材质每个类别至少准备 500 张以上图片数量越多、场景越丰富模型泛化能力越强。数据集目录结构如下datasets/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yamldata.yaml 内容path: datasets train: images/train val: images/val names: 0: barcode 1: expiry_date4.2 训练模型使用 ultralytics 训练 YOLOv8 模型非常简单from ultralytics import YOLO model YOLO(yolov8n.pt) results model.train( datadata.yaml, epochs100, imgsz640, batch16, device0, workers4, namebarcode_expiry_yolov8n, patience20, save_period10, )参数说明data数据集配置文件路径epochs训练轮数小数据集可先训练 100 轮观察收敛情况imgsz输入图片尺寸一般使用 640若条形码很小可以尝试 960batch批大小根据显存调整deviceGPU 编号CPU 训练时改为cpupatience早停轮数验证集指标连续多少次不提升就停止训练save_period每多少个 epoch 保存一次权重。训练完成后模型保存在runs/detect/barcode_expiry_yolov8n/weights/best.pt。4.3 使用 YOLOv5 训练的差异如果你更倾向于使用 YOLOv5可以从官方仓库拉取代码git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt训练命令python train.py --data data.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 100YOLOv5 和 YOLOv8 的模型文件不能直接互换但它们输出的检测结果格式是相同的因此后续的条形码解析和界面代码可以共用。4.4 模型导出训练完成后可以将模型导出为 ONNX 格式方便后续部署from ultralytics import YOLO model YOLO(runs/detect/barcode_expiry_yolov8n/weights/best.pt) model.export(formatonnx, imgsz640, simplifyTrue)导出后可以使用 onnxruntime 进行推理减少 PyTorch 环境依赖同时提升推理速度。如果项目只是学习演示直接用 PyTorch 加载也完全可以。5. 基于 PySide6 的界面开发5.1 界面功能拆解桌面应用需要包含以下功能区域顶部工具栏打开图片、打开摄像头、开始识别按钮左侧主显示区显示原图或摄像头画面并绘制检测框右侧信息面板显示条形码内容、有效期日期、当前状态正常/临期/过期底部状态栏显示模型推理耗时、当前帧率。界面布局使用 QVBoxLayout 和 QHBoxLayout 组合实现不引入 Qt Designer方便代码维护。5.2 主窗口框架# main_window.py import sys from PySide6.QtWidgets import ( QMainWindow, QApplication, QWidget, QLabel, QPushButton, QVBoxLayout, QHBoxLayout, QFileDialog, QMessageBox ) from PySide6.QtCore import Qt from PySide6.QtGui import QImage, QPixmap class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle(条形码保质期识别检测系统) self.resize(960, 640) self.init_ui() def init_ui(self): central_widget QWidget() self.setCentralWidget(central_widget) layout QHBoxLayout(central_widget) # 左侧显示区 left_widget QWidget() left_layout QVBoxLayout(left_widget) self.image_label QLabel() self.image_label.setAlignment(Qt.AlignCenter) self.image_label.setText(请打开图片或摄像头) self.image_label.setStyleSheet(background-color: #1e1e1e; color: #cccccc;) left_layout.addWidget(self.image_label) btn_layout QHBoxLayout() self.btn_open_image QPushButton(打开图片) self.btn_open_camera QPushButton(打开摄像头) self.btn_start QPushButton(开始识别) btn_layout.addWidget(self.btn_open_image) btn_layout.addWidget(self.btn_open_camera) btn_layout.addWidget(self.btn_start) left_layout.addLayout(btn_layout) # 右侧信息面板 right_widget QWidget() right_layout QVBoxLayout(right_widget) self.info_label QLabel(检测信息) self.info_label.setAlignment(Qt.AlignTop) self.info_label.setWordWrap(True) right_layout.addWidget(self.info_label) right_layout.addStretch() layout.addWidget(left_widget, stretch3) layout.addWidget(right_widget, stretch1) def show_image(self, cv_image): 将 OpenCV 的 BGR 图像转换为 QPixmap 并显示 rgb_image cv2.cvtColor(cv_image, cv2.COLOR_BGR2RGB) h, w, ch rgb_image.shape bytes_per_line ch * w q_img QImage(rgb_image.data, w, h, bytes_per_line, QImage.Format_RGB888) self.image_label.setPixmap(QPixmap.fromImage(q_img).scaled( self.image_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))5.3 多线程推理避免界面卡顿模型推理和条形码解析是耗时操作如果直接放在主线程中执行界面会卡死。因此需要将检测逻辑放到 QThread 中通过信号将结果传回主线程。# detector_thread.py from PySide6.QtCore import QThread, Signal import numpy as np class DetectorThread(QThread): result_ready Signal(dict) frame_ready Signal(object) def __init__(self, model, parentNone): super().__init__(parent) self.model model self.running True def run(self): while self.running: # 从摄像头读取帧或从队列获取图片 frame self.get_frame() if frame is None: continue results self.model.predict(frame, imgsz640, conf0.35, verboseFalse) # 解析检测结果 boxes results[0].boxes detections [] if boxes is not None: for box in boxes: x1, y1, x2, y2 box.xyxy[0].tolist() conf float(box.conf[0]) cls_id int(box.cls[0]) cls_name self.model.names[cls_id] detections.append({ bbox: [int(x1), int(y1), int(x2), int(y2)], conf: conf, class: cls_name, }) # 绘制结果并发送到界面 annotated_frame results[0].plot() self.frame_ready.emit(annotated_frame) result_data { detections: detections, barcode: None, expiry_date: None, } self.result_ready.emit(result_data) def get_frame(self): 需要根据实际输入源实现 pass6. 条形码解析与保质期识别6.1 条形码解析拿到 YOLO 检测到的条形码区域后先裁剪出该区域再交给 pyzbar 解码。需要预先调整图像尺寸和对比度提高解码成功率。import cv2 from pyzbar import pyzbar def decode_barcode(img, bbox): x1, y1, x2, y2 bbox roi img[y1:y2, x1:x2] if roi.size 0: return None # 灰度化 放大 二值化 gray cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY) gray cv2.resize(gray, None, fx2.0, fy2.0, interpolationcv2.INTER_CUBIC) _, thresh cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY cv2.THRESH_OTSU) decoded pyzbar.decode(thresh) if decoded: return decoded[0].data.decode(utf-8) return None如果识别失败可以尝试旋转多个角度再次识别def decode_with_rotation(img, bbox): angles [0, 90, 180, 270] x1, y1, x2, y2 bbox roi img[y1:y2, x1:x2] for angle in angles: rotated roi if angle ! 0: h, w rotated.shape[:2] center (w // 2, h // 2) matrix cv2.getRotationMatrix2D(center, angle, 1.0) rotated cv2.warpAffine(rotated, matrix, (w, h)) gray cv2.cvtColor(rotated, cv2.COLOR_BGR2GRAY) gray cv2.resize(gray, None, fx2.0, fy2.0) _, thresh cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY cv2.THRESH_OTSU) decoded pyzbar.decode(thresh) if decoded: return decoded[0].data.decode(utf-8) return None6.2 保质期日期识别保质期区域内的文本通常是印刷体数字、汉字和标点混合例如2025.08.15保质期至2025/12/31生产日期 20240820有效期至 2026年3月1日使用 PaddleOCR 识别该区域文本再通过正则提取日期信息。import re from paddleocr import PaddleOCR ocr PaddleOCR(use_angle_clsTrue, langch, show_logFalse) def extract_date_from_text(text): # 匹配 2024-08-15、2024/08/15、2024.08.15、2024年08月15日 patterns [ r(\d{4})[-/.](\d{1,2})[-/.](\d{1,2}), r(\d{4})年(\d{1,2})月(\d{1,2})日?, r(\d{4})(\d{2})(\d{2}), ] for pattern in patterns: match re.search(pattern, text) if match: groups match.groups() if len(groups) 3: year, month, day groups return f{year}-{int(month):02d}-{int(day):02d} return None def recognize_expiry_date(img, bbox): x1, y1, x2, y2 bbox roi img[y1:y2, x1:x2] if roi.size 0: return None # 放大 ROI提升 OCR 效果 roi cv2.resize(roi, None, fx2.0, fy2.0, interpolationcv2.INTER_CUBIC) result ocr.ocr(roi, clsTrue) if not result or not result[0]: return None all_text for line in result[0]: text line[1][0] all_text text return extract_date_from_text(all_text)6.3 保质期状态判断识别出保质期日期后还需要判断当前商品的状态。这里需要区分两种日期语义生产日期需要结合保质期时长计算过期时间有效期/过期日期直接与当前日期比较。业务逻辑建议在系统配置中指定日期语义避免硬编码。示例代码如下from datetime import datetime def judge_status(expiry_date_str, current_dateNone): if current_date is None: current_date datetime.now() try: expiry_date datetime.strptime(expiry_date_str, %Y-%m-%d) except ValueError: return 日期格式错误 if expiry_date current_date: return 已过期 elif (expiry_date - current_date).days 30: return 临期 else: return 正常7. 完整实战从图片识别到界面展示7.1 创建工作目录barcode_expiry_system/ ├── main.py ├── main_window.py ├── detector_thread.py ├── utils/ │ ├── __init__.py │ ├── barcode_utils.py │ ├── date_utils.py │ └── ocr_utils.py ├── models/ │ └── best.pt └── requirements.txt7.2 集成所有模块main.py是整个应用的入口# main.py import sys import cv2 from PySide6.QtWidgets import QApplication, QFileDialog, QMessageBox from PySide6.QtCore import Qt from ultralytics import YOLO from main_window import MainWindow from utils.barcode_utils import decode_barcode, decode_with_rotation from utils.ocr_utils import recognize_expiry_date from utils.date_utils import judge_status class BarcodeApp(MainWindow): def __init__(self): super().__init__() self.model YOLO(models/best.pt) self.current_image None # 绑定按钮事件 self.btn_open_image.clicked.connect(self.open_image) self.btn_start.clicked.connect(self.start_detect) def open_image(self): file_path, _ QFileDialog.getOpenFileName( self, 打开图片, , 图片文件 (*.jpg *.jpeg *.png *.bmp) ) if not file_path: return self.current_image cv2.imread(file_path) if self.current_image is None: QMessageBox.warning(self, 提示, 图片加载失败) return self.show_image(self.current_image) def start_detect(self): if self.current_image is None: QMessageBox.information(self, 提示, 请先打开图片) return # 目标检测 results self.model.predict( self.current_image, imgsz640, conf0.35, verboseFalse ) annotated results[0].plot() self.show_image(annotated) boxes results[0].boxes if boxes is None: self.info_label.setText(未检测到目标) return barcode_value None expiry_date None for box in boxes: x1, y1, x2, y2 box.xyxy[0].tolist() cls_id int(box.cls[0]) conf float(box.conf[0]) cls_name self.model.names[cls_id] bbox [int(x1), int(y1), int(x2), int(y2)] if cls_name barcode: barcode_value decode_with_rotation(self.current_image, bbox) elif cls_name expiry_date: expiry_date recognize_expiry_date(self.current_image, bbox) # 更新信息面板 status judge_status(expiry_date) if expiry_date else 未识别到日期 info_text f 检测结果 条形码{barcode_value if barcode_value else 未识别} 保质期日期{expiry_date if expiry_date else 未识别} 商品状态{status} self.info_label.setText(info_text) def main(): app QApplication(sys.argv) window BarcodeApp() window.show() sys.exit(app.exec()) if __name__ __main__: main()7.3 运行效果说明运行python main.py后点击“打开图片”选择一张包含条形码和保质期的商品图片再点击“开始识别”左侧画面会显示 YOLO 绘制的检测框右侧显示识别出的条形码内容和保质期日期。如果摄像头识别只需要在BarcodeApp中增加摄像头初始化逻辑将每一帧送入start_detect的检测部分即可。需要注意控制推理频率避免每帧都做模型推理导致界面卡顿通常可以设置为每隔 3 到 5 帧检测一次。7.4 使用 YOLOv5 模型时的代码适配如果使用的是 YOLOv5 训练的模型代码需要做以下调整import torch model torch.hub.load(ultralytics/yolov5, custom, pathmodels/best.pt) results model(self.current_image) # 结果格式不同需要转换 detections results.pandas().xyxy[0] for _, row in detections.iterrows(): x1, y1, x2, y2 int(row[xmin]), int(row[ymin]), int(row[xmax]), int(row[ymax]) cls_name row[name] conf row[confidence]其他模块可以共用因为条形码解析和日期识别只依赖边界框坐标。8. 常见问题与排查思路问题现象常见原因解决思路启动时 import pyzbar 报错缺少 ZBar 动态库安装 ZBar 并配置 PATH或重新安装 pyzbarPaddleOCR 首次运行下载模型慢网络原因手动下载模型放到~/.paddleocr目录YOLO 训练 loss 不下降学习率过高或数据集问题检查标注是否正确降低 lr增加 epochs条形码检测框正确但解码失败条形码区域模糊或反光增强图像预处理尝试多角度旋转解码日期区域检测正确但 OCR 输出乱码字体特殊或 ROI 过小放大 ROI调整 OCR 参数或使用专门训练的文字识别模型PySide6 界面卡顿推理阻塞主线程使用 QThread 将检测移出 UI 线程摄像头打开失败设备号错误或权限不足检查摄像头索引Windows 下确认相机权限YOLOv8 和 YOLOv5 权重无法互相加载模型结构不同使用各自对应的推理接口检测速度太慢输入尺寸过大或模型过重使用 nano 模型降低 imgsz开启 int8 量化8.1 条形码解码失败的排查清单先单独对裁剪区域做灰度化、放大、二值化观察条形码是否清晰检查条形码是否占满整个 ROI如果占比太小pyzbar 可能无法识别尝试旋转 90 度、180 度、270 度后再解码如果条形码有破损需要更复杂的修复算法建议重新采集数据并标注检查 pyzbar 支持的码制某些 CJK 条码需要使用pyzbar.pyzbar.decode(..., symbols[ZBarSymbol.CODE128])指定码制。8.2 保质期识别误判的预防保质期识别错误通常比条形码解码失败更隐蔽因为 OCR 可能把“2024.08.15”识别成“2024.08.1S”。建议在后处理中增加校验正则匹配后验证月份在 1 到 12 之间验证日期在 1 到 31 之间对年份做范围判断例如 2000 到 2100 之间如果置信度低宁可标记为“待人工确认”也不要输出错误日期。可以在extract_date_from_text中增加校验逻辑def is_valid_date(year, month, day): try: datetime(int(year), int(month), int(day)) return True except ValueError: return False9. 最佳实践与工程建议9.1 数据集与训练建议标注数据时不要只收集“好看”的图片。要把反光、倾斜、遮挡、模糊的样本都纳入训练集模型才能学到真正的鲁棒特征条形码和日期区域检测是两个难度不同的任务。如果其中一个类别数据量明显不足会拖累另一个类别的训练效果可以通过cls损失权重或者单独训练两个模型缓解训练时开启数据增强。YOLOv8 默认支持 Mosaic、MixUp 等增强但在条形码这类纹理密集的物体上Mosaic 可能会导致条形码纹理断裂必要时可以关闭 Mosaicmodel.train(..., mosaic0.5)如果部署设备性能有限优先使用 YOLOv8n 或 YOLOv5s再考虑蒸馏和量化。9.2 工程化建议系统中所有配置项模型路径、置信度阈值、摄像头编号、日期语义都放进配置文件不要硬编码在代码中日期解析逻辑需要单独抽离成模块方便单元测试使用try-except包裹条形码解码和 OCR 调用防止异常导致程序退出记录日志时可以输出每张图片的检测结果、耗时和置信度便于复盘识别失败原因对识别失败的样本做文件夹留存定期补充进训练集形成数据闭环如果需要在生产环境长期运行考虑将模型推理服务化PySide6 只做前端展示通过 HTTP 或 gRPC 调用推理接口。9.3 性能优化使用 ONNX Runtime 替代 PyTorch 推理可以减少内存占用并提升推理速度摄像头场景下不一定要每帧都推理。可以在检测线程中判断当前帧与上一帧的画面差异变化较大时才重新检测将 PaddleOCR 初始化为全局单例避免每次识别都重新加载模型如果只是做条形码识别不需要 YOLO 检测可以使用 OpenCV 的barcode_barcode接口但其定位能力较弱适合背景干净的场景。10. 总结与学习路线本文实现了一套完整的条形码保质期识别检测系统核心思路是先使用 YOLOv8 或 YOLOv5 训练目标检测模型定位条形码和保质期文本区域然后通过 pyzbar 解析条形码、PaddleOCR 结合正则解析日期最后用 PySide6 封装成桌面应用。如果要从零开始动手练习可以按照以下路线逐步推进先准备 100 张左右带有条形码的图片手动标注并训练一个只检测条形码的 YOLOv8 模型用 pyzbar 解析模型输出的条形码区域体会目标检测和图像处理模块的配合在此基础上增加保质期类别标注包装日期区域训练两类别模型最后把代码整理成 PySide6 界面加入多线程逻辑完成桌面应用。整个系统的核心难点不在模型结构而在于数据质量、业务逻辑的边界处理以及多模块的工程整合。建议在动手时先从最小可行版本开始逐步增加场景覆盖才能在实际项目中稳定落地。如果本文对你有帮助顺手点个收藏后续我会继续更新 YOLOv8 训练技巧和 PySide6 实战相关的内容。