智慧巡检-基于深度学习的柑橘叶病害检测系统,支持黑点病、溃疡病、绿霉病、健康叶片、褐斑病五类目标检测,模型已训练好,直接可用。
技术栈:yolov8s主干,支持目标检测,数据集包含5类病害和健康叶片,标注齐全,图片清晰,适合科研、农业病害监测、智能诊断等场景。
训练效果:mAP50达0.989,精度召回均在0.95以上,支持多类目标,模型性能稳定,图片检测框清晰,识别准确。
文件内容:模型权重、数据集、训练日志、可视化结果、代码注释。
使用说明:模型已优化,直接导入即可,可根据需求调整参数,代码注释详细,适合自用或二次开发。
系统基于YOLOv8算法,能够精准识别柑橘叶片的 5 种状态(黑点病、溃疡病、绿霉病、健康、褐斑病),mAP50 高达 0.989,效果非常出色。
模型训练脚本(复现你的高精度结果)和PyQt5 可视化检测系统(对应你的界面截图)。
第一步:环境配置
同学你需要安装 PyTorch、Ultralytics(YOLOv8)和 PyQt5。在终端中运行以下命令:
# 安装 PyTorch (请根据你的 CUDA 版本选择,这里以 CPU 版本为例,推荐安装 CUDA 版以加速)pipinstalltorch torchvision torchaudio# 安装 YOLOv8pipinstallultralytics# 安装 PyQt5 用于构建界面pipinstallPyQt5# 安装 OpenCV 用于图像处理pipinstallopencv-python# 安装 Pandas 和 Matplotlib 用于数据处理和绘图pipinstallpandas matplotlib第二步:数据集准备
创建dataset文件夹,并建立data.yaml文件。,类别配置如下:
# data.yamlpath:./dataset# 数据集根目录train:images/train# 训练集图片路径val:images/val# 验证集图片路径test:images/test# 测试集图片路径# 类别数量和名称nc:5names:['blackspot','canker','greening','healthy','melanose']第三步:模型训练代码 (train.py)
这段代码用于训练模型,以达到你截图中 mAP50 0.989 的效果。
fromultralyticsimportYOLOdeftrain_model():# 1. 加载预训练模型 (YOLOv8s)model=YOLO('yolov8s.pt')# 2. 开始训练# 参数解释:# data: 数据集配置文件路径# epochs: 训练轮数 (根据你的Loss图,大约200轮收敛)# imgsz: 输入图片尺寸# batch: 批大小 (根据显存调整, -1为自动)# name: 实验名称results=model.train(data='dataset/data.yaml',epochs=200,imgsz=640,batch=16,name='citrus_exp_v1',patience=50,# 早停机制device=0# 使用GPU 0,若无GPU则设为 'cpu')if__name__=='__main__':train_model()第四步:可视化检测系统代码 (main.py)
这是系统的核心,实现了你截图中的左侧控制面板、中间图像显示和底部数据表格。
importsysimporttimeimportcv2importtorchimportnumpyasnpimportpandasaspdfromPyQt5.QtWidgetsimport(QApplication,QMainWindow,QLabel,QPushButton,QVBoxLayout,QHBoxLayout,QWidget,QFileDialog,QTableWidget,QTableWidgetItem,QMessageBox,QHeaderView)fromPyQt5.QtGuiimportQImage,QPixmap,QFont,QColorfromPyQt5.QtCoreimportQt,QThread,pyqtSignal,QTimerfromultralyticsimportYOLO# --- 配置参数 ---MODEL_PATH='runs/detect/citrus_exp_v1/weights/best.pt'# 训练好的模型路径CLASSES=['blackspot','canker','greening','healthy','melanose']COLORS=[(255,0,0),(0,255,0),(0,0,255),(255,255,0),(255,0,255)]# 各类别的框颜色classDetectThread(QThread):# 自定义信号,用于发送处理后的图像和检测结果change_pixmap_signal=pyqtSignal(np.ndarray)update_table_signal=pyqtSignal(list)def__init__(self):super().__init__()self.running=Trueself.source=0# 0为摄像头,或文件路径self.model=YOLO(MODEL_PATH)self.conf_threshold=0.5defrun(self):cap=cv2.VideoCapture(self.source)whileself.running:ret,frame=cap.read()ifret:# YOLOv8 推理results=self.model(frame,conf=self.conf_threshold)result=results[0]# 解析结果boxes=result.boxes.xyxy.cpu().numpy()classes=result.boxes.cls.cpu().numpy()confs=result.boxes.conf.cpu().numpy()# 绘制检测框det_frame=frame.copy()detections=[]forbox,cls,confinzip(boxes,classes,confs):x1,y1,x2,y2=map(int,box)label=f"{CLASSES[int(cls)]}{conf:.2f}"color=COLORS[int(cls)]# 画框cv2.rectangle(det_frame,(x1,y1),(x2,y2),color,2)# 画标签背景cv2.rectangle(det_frame,(x1,y1-20),(x1+len(label)*10,y1),color,-1)# 画文字cv2.putText(det_frame,label,(x1,y1-5),cv2.FONT_HERSHEY_SIMPLEX,0.5,(255,255,255),2)detections.append({"class":CLASSES[int(cls)],"conf":f"{conf:.2f}","box":f"[{x1},{y1},{x2},{y2}]"})# 发送信号self.change_pixmap_signal.emit(det_frame)self.update_table_signal.emit(detections)else:# 如果是视频或图片,播放完后重置ifisinstance(self.source,str):cap.set(cv2.CAP_PROP_POS_FRAMES,0)time.sleep(0.03)cap.release()defstop(self):self.running=Falseself.wait()classMainWindow(QMainWindow):def__init__(self):super().__init__()self.setWindowTitle("柑橘常见病害识别系统")self.setGeometry(100,100,1200,800)# 初始化线程self.thread=None# --- UI 布局 ---main_layout=QHBoxLayout()# 左侧控制面板left_panel=self.create_left_panel()main_layout.addLayout(left_panel,1)# 右侧显示区域right_panel=self.create_right_panel()main_layout.addLayout(right_panel,3)container=QWidget()container.setLayout(main_layout)self.setCentralWidget(container)defcreate_left_panel(self):layout=QVBoxLayout()# 标题title=QLabel("柑橘病害检测")title.setFont(QFont("Microsoft YaHei",16,QFont.Bold))title.setAlignment(Qt.AlignCenter)layout.addWidget(title)# 按钮组btn_open_img=QPushButton("打开图片")btn_open_vid=QPushButton("打开视频")btn_camera=QPushButton("打开摄像头")btn_run=QPushButton("开始运行")btn_export=QPushButton("导出数据")forbtnin[btn_open_img,btn_open_vid,btn_camera,btn_run,btn_export]:btn.setFixedHeight(40)btn.setFont(QFont("Microsoft YaHei",10))layout.addWidget(btn)# 绑定事件btn_open_img.clicked.connect(lambda:self.load_source(is_img=True))btn_open_vid.clicked.connect(lambda:self.load_source(is_img=False))btn_camera.clicked.connect(lambda:self.start_detection(0))btn_run.clicked.connect(self.start_detection)layout.addStretch()returnlayoutdefcreate_right_panel(self):layout=QVBoxLayout()# 视频显示标签self.image_label=QLabel()self.image_label.setFixedSize(800,600)self.image_label.setStyleSheet("background-color: #000000;")layout.addWidget(self.image_label,alignment=Qt.AlignCenter)# 结果表格self.table=QTableWidget()self.table.setColumnCount(4)self.table.setHorizontalHeaderLabels(["类别","置信度","坐标位置","时间"])self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)layout.addWidget(self.table)returnlayoutdefload_source(self,is_img):# 文件选择逻辑ifis_img:path,_=QFileDialog.getOpenFileName(self,"选择图片","","Image Files (*.png *.jpg *.bmp)")else:path,_=QFileDialog.getOpenFileName(self,"选择视频","","Video Files (*.mp4 *.avi)")ifpath:self.start_detection(path)defstart_detection(self,source=None):ifself.threadandself.thread.isRunning():self.thread.stop()ifsourceisNone:# 默认摄像头source=0self.thread=DetectThread()self.thread.source=source self.thread.change_pixmap_signal.connect(self.update_image)self.thread.update_table_signal.connect(self.update_table)self.thread.start()defupdate_image(self,cv_img):# OpenCV图像转Qt图像rgb_image=cv2.cvtColor(cv_img,cv2.COLOR_BGR2RGB)h,w,ch=rgb_image.shape bytes_per_line=ch*w convert_to_Qt_format=QImage(rgb_image.data,w,h,bytes_per_line,QImage.Format_RGB888)p=convert_to_Qt_format.scaled(800,600,Qt.KeepAspectRatio)self.image_label.setPixmap(QPixmap.fromImage(p))defupdate_table(self,detections):self.table.setRowCount(0)# 清空表格fordetindetections:row_pos=self.table.rowCount()self.table.insertRow(row_pos)self.table.setItem(row_pos,0,QTableWidgetItem(det['class']))self.table.setItem(row_pos,1,QTableWidgetItem(det['conf']))self.table.setItem(row_pos,2,QTableWidgetItem(det['box']))self.table.setItem(row_pos,3,QTableWidgetItem(time.strftime("%H:%M:%S")))defcloseEvent(self,event):ifself.threadandself.thread.isRunning():self.thread.stop()event.accept()if__name__=="__main__":app=QApplication(sys.argv)window=MainWindow()window.show()sys.exit(app.exec_())代码说明
- DetectThread 类:
- 这是一个独立线程,用于处理耗时的视频读取和 YOLO 推理,防止界面卡顿。
self.model(frame)执行推理。- 使用
cv2.rectangle和cv2.putText在图像上绘制边界框和标签。 - 通过
pyqtSignal将处理后的图像和检测数据发送回主界面。
- MainWindow 类:
create_left_panel:构建左侧的按钮区域(打开图片、视频、摄像头等)。create_right_panel:构建右侧的图像显示区域和下方的QTableWidget。update_image:将 OpenCV 的numpy数组转换为 Qt 可以显示的QImage。update_table:动态更新底部的表格数据。
- 样式调整:
- 你可以使用
setStyleSheet方法进一步美化界面,使其更接近你截图中的风格(例如圆角按钮、特定背景色)。
- 你可以使用
运行方法
- 确保你已经训练好了模型,并将
best.pt的路径填入MODEL_PATH。 - 运行
python main.py。 - 点击“打开图片”或“打开摄像头”即可开始检测柑橘病害。