深度学习目标检测中如何使用Yolov5训练变电站各种仪表数据集等共6000余张,并且都已打上标签,构建一个各种仪表数据集检测的项目。
图像信息清晰 yolo格式
yolov5目标检测 变电站各种仪表数据集等共6000余张,并且都已打上标签,图像信息清晰
以下所有代码仅供参考!
构建一个基于YOLOv5的变电站仪表检测系统来处理变电站各种仪表数据集。以下是详细的步骤和代码示例,包括环境部署、模型训练、指标可视化展示以及PyQt5界面设计。
数据集结构
假设你的数据集已经准备好,并且是以YOLO格式存储的。以下是数据集的标准结构:
dataset/
├── images/
│ ├── train/
│ │ ├── image1.jpg
│ │ ├── image2.jpg
│ │ └── ...
│ ├── val/
│ │ ├── image3.jpg
│ │ ├── image4.jpg
│ │ └── ...
│ └── test/
│ ├── image5.jpg
│ ├── image6.jpg
│ └── ...
├── labels/
│ ├── train/
│ │ ├── image1.txt
│ │ ├── image2.txt
│ │ └── ...
│ ├── val/
│ │ ├── image3.txt
│ │ ├── image4.txt
│ │ └── ...
│ └── test/
│ ├── image5.txt
│ ├── image6.txt
│ └── ...
└── classes.txt
classes.txt
内容如下:
meter1
meter2
meter3
...
# 假设有多种类型的仪表,这里列出几个示例
每个图像对应的标签文件是一个文本文件,每行表示一个边界框,格式为:
<class_id> <x_center> <y_center> <width> <height>
环境部署说明
首先,确保你已经安装了必要的库。以下是详细的环境部署步骤:
安装依赖
# 创建虚拟环境(可选)
conda create -n substation_meter_detection_env python=3.9
conda activate substation_meter_detection_env
# 安装PyTorch
pip install torch==1.9 torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu111
# 安装其他依赖
pip install opencv-python pyqt5 yolov5 scikit-learn pandas matplotlib seaborn
模型训练权重和指标可视化展示
我们将使用YOLOv5进行训练,并在训练过程中记录各种指标,如F1曲线、准确率、召回率、损失曲线和混淆矩阵。
训练脚本 train_yolov5.py
[<title="Training YOLOv5 on Substation Meter Detection Dataset">]
import os
from pathlib import Path
import yaml
from IPython.display import display, Image
import torch
from utils.plots import plot_results
from utils.general import increment_path
# Define paths
dataset_path = 'path/to/dataset'
weights_path = 'runs/train/exp/weights/best.pt'
# Create dataset.yaml
yaml_content = f"""
train: {os.path.join(dataset_path, 'images/train')}
val: {os.path.join(dataset_path, 'images/val')}
nc: 10 # 假设有10种不同类型的仪表,根据实际情况调整
names: ['meter1', 'meter2', 'meter3', 'meter4', 'meter5', 'meter6', 'meter7', 'meter8', 'meter9', 'meter10'] # 根据实际情况调整
"""
with open(os.path.join(dataset_path, 'dataset.yaml'), 'w') as f:
f.write(yaml_content)
# Clone YOLOv5 repository
!git clone https://github.com/ultralytics/yolov5
%cd yolov5
%pip install -r requirements.txt
# Train YOLOv5
!python train.py --img 640 --batch 16 --epochs 100 --data {os.path.join(dataset_path, 'dataset.yaml')} --cfg yolov5s.yaml --weights yolov5s.pt --cache
# Save the best weights
best_weights_path = Path('runs/train/exp/weights/best.pt')
shutil.copy(best_weights_path, weights_path)
请将 path/to/dataset
替换为实际的数据集路径,并根据实际的类别数量和名称调整 nc
和 names
字段。
指标可视化展示
我们将编写代码来可视化训练过程中的各项指标,包括F1曲线、准确率、召回率、损失曲线和混淆矩阵。
可视化脚本 visualize_metrics.py
[<title="Visualizing Training Metrics for YOLOv5">]
import os
import json
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
# Load metrics
results_dir = 'runs/train/exp'
metrics_path = os.path.join(results_dir, 'results.json')
with open(metrics_path, 'r') as f:
results = json.load(f)
# Extract metrics
loss = [entry['train_loss'] for entry in results if 'train_loss' in entry]
precision = [entry['metrics/precision(m)'] for entry in results if 'metrics/precision(m)' in entry]
recall = [entry['metrics/recall(m)'] for entry in results if 'metrics/recall(m)' in entry]
mAP_05 = [entry['metrics/mAP50(m)'] for entry in results if 'metrics/mAP50(m)' in entry]
# Plot loss curve
plt.figure(figsize=(15, 5))
plt.subplot(1, 3, 1)
plt.plot(loss, label='Loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.title('Training Loss Curve')
plt.legend()
# Plot precision and recall curves
plt.subplot(1, 3, 2)
plt.plot(precision, label='Precision')
plt.plot(recall, label='Recall')
plt.xlabel('Epochs')
plt.ylabel('Score')
plt.title('Precision and Recall Curves')
plt.legend()
# Plot mAP@0.5 curve
plt.subplot(1, 3, 3)
plt.plot(mAP_05, label='mAP@0.5')
plt.xlabel('Epochs')
plt.ylabel('mAP@0.5')
plt.title('mAP@0.5 Curve')
plt.legend()
plt.tight_layout()
plt.show()
# Confusion matrix
# Assuming you have predictions and true labels
# For demonstration, let's create some dummy data
true_labels = np.random.randint(0, 11, size=100) # 0 to 10 (background or one of the object types)
predictions = np.random.randint(0, 11, size=100) # 0 to 10 (background or one of the object types)
cm = confusion_matrix(true_labels, predictions, labels=list(range(11)))
labels = ['Background', 'meter1', 'meter2', 'meter3', 'meter4', 'meter5', 'meter6', 'meter7', 'meter8', 'meter9', 'meter10']
disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=labels)
disp.plot(cmap=plt.cm.Blues)
plt.title('Confusion Matrix')
plt.show()
PyQt5设计的界面
我们将使用PyQt5设计一个简单的GUI界面来进行模型预测。
GUI代码 gui_app.py
[<title="PyQt5 GUI for YOLOv5 Substation Meter Detection">]
import sys
import cv2
import numpy as np
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QPushButton, QVBoxLayout, QWidget, QFileDialog, QMessageBox, QProgressBar, QTextEdit
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.QtCore import QTimer
from models.experimental import attempt_load
from utils.torch_utils import select_device
from utils.general import non_max_suppression, scale_coords
from utils.datasets import letterbox
import torch
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Substation Meter Detection")
self.setGeometry(100, 100, 800, 600)
self.central_widget = QWidget(self)
self.setCentralWidget(self.central_widget)
self.layout = QVBoxLayout(self.central_widget)
self.label_display = QLabel(self)
self.layout.addWidget(self.label_display)
self.button_layout = QHBoxLayout()
self.pushButton_image = QPushButton("Open Image", self)
self.pushButton_image.clicked.connect(self.open_image)
self.button_layout.addWidget(self.pushButton_image)
self.pushButton_folder = QPushButton("Open Folder", self)
self.pushButton_folder.clicked.connect(self.open_folder)
self.button_layout.addWidget(self.pushButton_folder)
self.pushButton_video = QPushButton("Open Video", self)
self.pushButton_video.clicked.connect(self.open_video)
self.button_layout.addWidget(self.pushButton_video)
self.pushButton_camera = QPushButton("Start Camera", self)
self.pushButton_camera.clicked.connect(self.start_camera)
self.button_layout.addWidget(self.pushButton_camera)
self.pushButton_stop = QPushButton("Stop Camera", self)
self.pushButton_stop.clicked.connect(self.stop_camera)
self.button_layout.addWidget(self.pushButton_stop)
self.layout.addLayout(self.button_layout)
self.device = select_device('')
self.model = attempt_load('runs/train/exp/weights/best.pt', map_location=self.device)
self.cap = None
self.timer = QTimer()
self.timer.timeout.connect(self.process_frame)
def load_image(self, file_name):
img = cv2.imread(file_name) # BGR
assert img is not None, f'Image Not Found {file_name}'
return img
def process_image(self, img):
img0 = img.copy()
img = letterbox(img, new_shape=640)[0]
img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416
img = np.ascontiguousarray(img)
img = torch.from_numpy(img).to(self.device)
img = img.float() # uint8 to fp16/32
img /= 255.0 # 0 - 255 to 0.0 - 1.0
if img.ndimension() == 3:
img = img.unsqueeze(0)
pred = self.model(img, augment=False)[0]
pred = non_max_suppression(pred, 0.25, 0.45, classes=None, agnostic=False)
for i, det in enumerate(pred): # detections per image
if len(det):
det[:, :4] = scale_coords(img.shape[2:], det[:, :4], img0.shape).round()
for *xyxy, conf, cls in reversed(det):
label = f'{self.model.names[int(cls)]} {conf:.2f}'
color = (0, 255, 0) # Green
cv2.rectangle(img0, (int(xyxy[0]), int(xyxy[1])), (int(xyxy[2]), int(xyxy[3])), color, 2)
cv2.putText(img0, label, (int(xyxy[0]), int(xyxy[1]) - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, color, 2)
rgb_image = cv2.cvtColor(img0, cv2.COLOR_BGR2RGB)
h, w, ch = rgb_image.shape
bytes_per_line = ch * w
qt_image = QImage(rgb_image.data, w, h, bytes_per_line, QImage.Format_RGB888)
pixmap = QPixmap.fromImage(qt_image)
self.label_display.setPixmap(pixmap.scaled(800, 600))
def open_image(self):
options = QFileDialog.Options()
file_name, _ = QFileDialog.getOpenFileName(self, "QFileDialog.getOpenFileName()", "", "Images (*.jpeg *.jpg);;All Files (*)", options=options)
if file_name:
img = self.load_image(file_name)
self.process_image(img)
def open_folder(self):
folder_name = QFileDialog.getExistingDirectory(self, "Select Folder")
if folder_name:
for filename in os.listdir(folder_name):
if filename.lower().endswith(('.png', '.jpg', '.jpeg')):
file_path = os.path.join(folder_name, filename)
img = self.load_image(file_path)
self.process_image(img)
def open_video(self):
options = QFileDialog.Options()
file_name, _ = QFileDialog.getOpenFileName(self, "QFileDialog.getOpenFileName()", "", "Videos (*.mp4 *.avi);;All Files (*)", options=options)
if file_name:
self.cap = cv2.VideoCapture(file_name)
self.timer.start(30) # Process frame every 30 ms
def start_camera(self):
self.cap = cv2.VideoCapture(0)
self.timer.start(30) # Process frame every 30 ms
def stop_camera(self):
if self.cap is not None:
self.cap.release()
self.cap = None
self.timer.stop()
def process_frame(self):
if self.cap is not None:
ret, frame = self.cap.read()
if ret:
self.process_image(frame)
else:
self.cap.release()
self.cap = None
self.timer.stop()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
辅助工具文件 utils.py
这个文件可以用来存放一些辅助函数,比如保存结果等。
[<title="Utility Functions for Substation Meter Detection">]
import cv2
import os
def save_results(image, detections, output_dir, filename):
for det in detections:
r = det['bbox']
cls = det['class']
conf = det['confidence']
label = f'{cls} {conf:.2f}'
color = (0, 255, 0) # Green
cv2.rectangle(image, (int(r[0]), int(r[1])), (int(r[2]), int(r[3])), color, 2)
cv2.putText(image, label, (int(r[0]), int(r[1]) - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, color, 2)
output_path = os.path.join(output_dir, filename)
cv2.imwrite(output_path, image)
运行效果展示
假设你已经有了运行效果的图像,可以在 README.md
中添加这些图像以供参考。
# Substation Meter Detection System
## Overview
This project provides a deep learning-based system for detecting various types of meters in substations using thermal infrared images. The system can identify different types of meters in images, folders, videos, and live camera feeds.
## Environment Setup
- Software: PyCharm + Anaconda
- Environment: Python=3.9, OpenCV-Python, PyQt5, Torch=1.9
## Features
- Detects different types of meters.
- Supports detection on images, folders, videos, and live camera feed.
- Batch processing of images.
- Real-time display of detected meters with confidence scores and bounding boxes.
- Saving detection results.
## Usage
1. Run the program.
2. Choose an option to detect meters in images, folders, videos, or via the camera.
## Screenshots
![Example Screenshot](data/screenshots/example_screenshot.png)
总结
构建一个完整的基于YOLOv5的变电站仪表检测系统,包括数据集准备、环境部署、模型训练、指标可视化展示和PyQt5界面设计。以下是所有相关的代码文件:
- 训练脚本 (
train_yolov5.py
) - 指标可视化脚本 (
visualize_metrics.py
) - GUI应用代码 (
gui_app.py
) - 辅助工具文件 (
utils.py
) - 文档 (
README.md
)