自定义数据集labelimg标定并yolo v11使用训练
目录
labelimg标定数据集
安装
- 使用conda进行labelimg安装
conda create -n labelimg python=3.8
- 这里创建完之后进入labelimg环境
conda activate labelimg
- 进入labelimg环境之后通过pip下载labelimg
pip install labelimg
- conda环境中输入
labelimg
进入软件
使用
- 创建两个文件夹,images是存放图片的位置,labels是存放图片对应的标签。
- 打开数据集文件夹以及labels文件夹 ,点击Open dir选择我们训练图片所在的文件夹images,选择之后会弹窗让你选择labels所在的文件夹。labels文件夹需要自己建立,目的是用来存储图片标注后的信息。
- labelImg生成的标签放在labels文件夹下。生成的标签文件格式:class x_center y_center width height 。每行表示一个目标对象,每行中的第一个数表示目标类别,计数从0开始,比如这里的0代表的类别。后面的4个值代表目标真实框中心点(x,y)和真实框的宽、高信息。
- 编辑数据集配置文件***.yaml。注意 label不用配置:train.py在训练过程中,会将路径中的images替换为 labels来寻找labels数据
#train是训练时加载的图片或者标签的路径
train: images/train
#val是验证时加载的图片或者标签的路径
val: images/train
#test是测试时加载的图片或者标签的路径
test: images/test
# 类别数
nc: 2
# 类别名称
names: ['buffalo','lion']
生成标注后图片
这个脚本会读取标签文件中的矩形框信息,将其绘制在对应的原图上,并将结果保存到指定的输出文件夹中。不同类别的矩形框和类别名称将使用不同的颜色。
import os
import cv2
# 文件夹路径
images_folder = "./data_lableimg/JPEGImages"
labels_folder = "./data_lableimg/labels"
output_folder = "./data_lableimg/output_images"
classes_file = "./data_lableimg/classes.txt"
# 创建输出文件夹(如果不存在)
os.makedirs(output_folder, exist_ok=True)
# 读取类别名称
with open(classes_file, "r") as f:
class_names = f.read().strip().split()
# 定义颜色列表(每个类别对应一种颜色)
colors = [
(255, 0, 0), # 红色
(0, 255, 0), # 绿色
(0, 0, 255), # 蓝色
(255, 255, 0), # 青色
(255, 0, 255), # 洋红
(0, 255, 255), # 黄色
(128, 0, 0), # 深红
(0, 128, 0), # 深绿
(0, 0, 128), # 深蓝
# 可以根据需要添加更多颜色
]
# 遍历标签文件夹中的所有文件
for label_file in os.listdir(labels_folder):
# 构建标签文件路径
label_path = os.path.join(labels_folder, label_file)
# 构建对应的图像文件路径
image_file = label_file.replace(".txt", ".jpg")
image_path = os.path.join(images_folder, image_file)
# 检查图像文件是否存在
if not os.path.exists(image_path):
print(f"Image file '{image_file}' not found, skipping.")
continue
# 读取图像
image = cv2.imread(image_path)
# 检查图像是否成功读取
if image is None:
print(f"Failed to read image '{image_file}', skipping.")
continue
height, width, _ = image.shape
# 读取标签文件
with open(label_path, "r") as f:
for line in f.readlines():
# 解析标签文件中的每一行
class_id, x_center, y_center, bbox_width, bbox_height = map(float, line.strip().split())
# 转换坐标
x_center *= width
y_center *= height
bbox_width *= width
bbox_height *= height
# 计算矩形框的左上角和右下角坐标
x1 = int(x_center - bbox_width / 2)
y1 = int(y_center - bbox_height / 2)
x2 = int(x_center + bbox_width / 2)
y2 = int(y_center + bbox_height / 2)
# 获取类别对应的颜色
color = colors[int(class_id) % len(colors)]
# 绘制矩形框
cv2.rectangle(image, (x1, y1), (x2, y2), color, 2)
# 绘制类别名称
class_name = class_names[int(class_id)]
cv2.putText(image, class_name, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, color, 2)
# 保存带有矩形框的图像
output_path = os.path.join(output_folder, image_file)
cv2.imwrite(output_path, image)
print(f"Saved '{output_path}'")
print("All images processed.")
yolo 训练
yolo安装
先进入自己带pytorch的虚拟环境,与之前的yolo系列安装都不太一样,yolov8仅需要安装ultralytics这一个库。
pip install ultralytics
测试yolo v11模型
from ultralytics import YOLO
# Load a model
model = YOLO("yolo11n.yaml") # build a new model from YAML
model = YOLO("yolo11n.pt") # load a pretrained model (recommended for training)
model = YOLO("yolo11n.yaml").load("yolo11n.pt") # build from YAML and transfer weights
# Train the model. Device is determined automatically. If a GPU is available then it will be used, otherwise training will start on CPU.
results = model.train(data="coco8.yaml", epochs=100, imgsz=640)
# Train the model with 2 GPUs
results = model.train(data="coco8.yaml", epochs=100, imgsz=640, device=[0, 1])
# Train the model with MPS
results = model.train(data="coco8.yaml", epochs=100, imgsz=640, device="mps")
按比例划分数据集
# 作者:CSDN-笑脸惹桃花 https://blog.csdn.net/qq_67105081?type=blog
# github:peng-xiaobai https://github.com/peng-xiaobai/Dataset-Conversion
import os
import shutil
import random
# random.seed(0) #随机种子,可自选开启
def split_data(file_path, label_path, new_file_path, train_rate, val_rate, test_rate):
images = os.listdir(file_path)
labels = os.listdir(label_path)
images_no_ext = {os.path.splitext(image)[0]: image for image in images}
labels_no_ext = {os.path.splitext(label)[0]: label for label in labels}
matched_data = [(img, images_no_ext[img], labels_no_ext[img]) for img in images_no_ext if img in labels_no_ext]
unmatched_images = [img for img in images_no_ext if img not in labels_no_ext]
unmatched_labels = [label for label in labels_no_ext if label not in images_no_ext]
if unmatched_images:
print("未匹配的图片文件:")
for img in unmatched_images:
print(images_no_ext[img])
if unmatched_labels:
print("未匹配的标签文件:")
for label in unmatched_labels:
print(labels_no_ext[label])
random.shuffle(matched_data)
total = len(matched_data)
train_data = matched_data[:int(train_rate * total)]
val_data = matched_data[int(train_rate * total):int((train_rate + val_rate) * total)]
test_data = matched_data[int((train_rate + val_rate) * total):]
# 处理训练集
for img_name, img_file, label_file in train_data:
old_img_path = os.path.join(file_path, img_file)
old_label_path = os.path.join(label_path, label_file)
new_img_dir = os.path.join(new_file_path, 'train', 'images')
new_label_dir = os.path.join(new_file_path, 'train', 'labels')
os.makedirs(new_img_dir, exist_ok=True)
os.makedirs(new_label_dir, exist_ok=True)
shutil.copy(old_img_path, os.path.join(new_img_dir, img_file))
shutil.copy(old_label_path, os.path.join(new_label_dir, label_file))
# 处理验证集
for img_name, img_file, label_file in val_data:
old_img_path = os.path.join(file_path, img_file)
old_label_path = os.path.join(label_path, label_file)
new_img_dir = os.path.join(new_file_path, 'val', 'images')
new_label_dir = os.path.join(new_file_path, 'val', 'labels')
os.makedirs(new_img_dir, exist_ok=True)
os.makedirs(new_label_dir, exist_ok=True)
shutil.copy(old_img_path, os.path.join(new_img_dir, img_file))
shutil.copy(old_label_path, os.path.join(new_label_dir, label_file))
# 处理测试集
for img_name, img_file, label_file in test_data:
old_img_path = os.path.join(file_path, img_file)
old_label_path = os.path.join(label_path, label_file)
new_img_dir = os.path.join(new_file_path, 'test', 'images')
new_label_dir = os.path.join(new_file_path, 'test', 'labels')
os.makedirs(new_img_dir, exist_ok=True)
os.makedirs(new_label_dir, exist_ok=True)
shutil.copy(old_img_path, os.path.join(new_img_dir, img_file))
shutil.copy(old_label_path, os.path.join(new_label_dir, label_file))
print("数据集已划分完成")
if __name__ == '__main__':
file_path = "./data_lableimg/JPEGImages" # 图片文件夹
label_path = './data_lableimg/labels' # 标签文件夹
new_file_path = "./datayolo" # 新数据存放位置
split_data(file_path, label_path, new_file_path, train_rate=0.8, val_rate=0.1, test_rate=0.1)
yolo使用
开始训练
from ultralytics import YOLO
pt_file = "yolo11n.pt"
model = YOLO("yolo11n.yaml").load(pt_file) # build from YAML and transfer weights
# Train the model
results = model.train(data="data.yaml", epochs=100, imgsz=640, device="mps")
恢复训练
通过设置resume=True, train函数将使用存储在‘path/to/last.pt’文件中的状态,从它停止的地方继续训练。如果省略resume参数或将其设置为False,则train函数将开始新的训练会话。
from ultralytics import YOLO
# Load a model
model = YOLO("path/to/last.pt") # load a partially trained model
# Resume training
results = model.train(resume=True)
参数设置
# Train the model
results = model.train(
data=data_file, # 数据集配置文件
epochs=100, # 训练周期数
imgsz=640, # 输入图像大小
device="mps", # 训练设备(例如 "cpu", "cuda", "mps")
batch=16, # 批处理大小
workers=8, # 数据加载器的工作线程数
project="runs/train", # 训练结果保存目录
name="exp", # 训练结果保存子目录名称
exist_ok=False, # 如果为 True,则允许覆盖现有目录
pretrained=True, # 如果为 True,则使用预训练模型
optimizer="SGD", # 优化器类型(例如 "SGD", "Adam")
lr0=0.01, # 初始学习率
lrf=0.1, # 最终学习率
momentum=0.937, # SGD 动量
weight_decay=0.0005, # 权重衰减
warmup_epochs=3.0, # 学习率预热周期数
warmup_momentum=0.8, # 预热动量
warmup_bias_lr=0.1, # 预热偏置学习率
box=0.05, # 边界框损失系数
cls=0.5, # 分类损失系数
cls_pw=1.0, # 分类损失权重
obj=1.0, # 目标损失系数
obj_pw=1.0, # 目标损失权重
iou_t=0.2, # IoU 阈值
anchor_t=4.0, # 锚框阈值
fl_gamma=0.0, # Focal Loss gamma
hsv_h=0.015, # HSV 色调增强
hsv_s=0.7, # HSV 饱和度增强
hsv_v=0.4, # HSV 亮度增强
degrees=0.0, # 图像旋转角度
translate=0.1, # 图像平移
scale=0.5, # 图像缩放
shear=0.0, # 图像剪切
perspective=0.0, # 透视变换
flipud=0.0, # 上下翻转
fliplr=0.5, # 左右翻转
mosaic=1.0, # 马赛克数据增强
mixup=0.0, # MixUp 数据增强
copy_paste=0.0, # Copy-Paste 数据增强
)
查看训练过程
新开一个终端窗口,输入tensorboard --logdir runs/detect/train
,进入tensorboard观察训练过程。浏览器打开http://localhost:6006/
YOLOv11(Ultralytics)可视化界面ui设计
首先选择模型,选择完之后可以分别点击图片检测选择单张图片检测后显示在界面上,可点击保存到指定位置,点击文件夹检测可以选择一个文件夹后将其按照一定的速度展示,文件夹检测会将检测结果自动保存,视频检测完可以选择保存视频,也可以在检测过程中将视频分段保存,摄像头可选本地和云摄像头,本地会自动获取摄像头编号可选择,云摄像头则需要输入ip后开始检测,均可点击保存为视频。检测之后的图像会实时显示在界面上,左边显示原始图像,右边显示检测后的图像。
import sys
import os
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QVBoxLayout, QWidget, QPushButton, QHBoxLayout, QFileDialog, QMessageBox
from PyQt5.QtGui import QImage, QPixmap, QIcon
import cv2
from ultralytics import YOLO
class Worker:
def __init__(self):
self.model = None
self.current_annotated_image = None
self.detection_type = None
def load_model(self):
model_path, _ = QFileDialog.getOpenFileName(None, "选择模型文件", "", "模型文件 (*.pt)")
if model_path:
self.model = YOLO(model_path)
if self.model:
return True
else:
return False
def detect_objects(self, frame):
det_info = []
class_ids = frame[0].boxes.cls
class_names_dict = frame[0].names
for class_id in class_ids:
class_name = class_names_dict[int(class_id)]
det_info.append(class_name)
return det_info
def save_image(self, image):
if image is not None:
file_name, _ = QFileDialog.getSaveFileName(None, "保存图片", "", "JPEG (*.jpg);;PNG (*.png);;All Files (*)")
if file_name:
cv2.imwrite(file_name, image)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("@author:笑脸惹桃花")
#self.setWindowIcon(QIcon("icon.png"))
self.setGeometry(300, 150, 1200, 600)
# 创建两个 QLabel 分别显示左右图像
self.label1 = QLabel()
self.label1.setAlignment(Qt.AlignCenter)
self.label1.setMinimumSize(580, 450) # 设置大小
self.label1.setStyleSheet('border:3px solid #6950a1; background-color: black;') # 添加边框并设置背景颜色为黑色
self.label2 = QLabel()
self.label2.setAlignment(Qt.AlignCenter)
self.label2.setMinimumSize(580, 450) # 设置大小
self.label2.setStyleSheet('border:3px solid #6950a1; background-color: black;') # 添加边框并设置背景颜色为黑色
# 水平布局,用于放置左右两个 QLabel
layout = QVBoxLayout()
hbox_video = QHBoxLayout()
hbox_video.addWidget(self.label1)
hbox_video.addWidget(self.label2)
layout.addLayout(hbox_video)
self.worker = Worker()
# 创建按钮布局
hbox_buttons = QHBoxLayout()
# 添加模型选择按钮
self.load_model_button = QPushButton("👆模型选择")
self.load_model_button.clicked.connect(self.load_model)
self.load_model_button.setFixedSize(120, 30)
hbox_buttons.addWidget(self.load_model_button)
# 添加图片检测按钮
self.image_detect_button = QPushButton("🖼️️图片检测")
self.image_detect_button.clicked.connect(self.select_image)
self.image_detect_button.setEnabled(False)
self.image_detect_button.setFixedSize(120, 30)
hbox_buttons.addWidget(self.image_detect_button)
# 添加图片文件夹检测按钮
self.folder_detect_button = QPushButton("️📁文件夹检测")
self.folder_detect_button.clicked.connect(self.detect_folder)
self.folder_detect_button.setEnabled(False)
self.folder_detect_button.setFixedSize(120, 30)
hbox_buttons.addWidget(self.folder_detect_button)
# 添加显示检测物体按钮
self.display_objects_button = QPushButton("🔍显示检测物体")
self.display_objects_button.clicked.connect(self.show_detected_objects)
self.display_objects_button.setEnabled(False)
self.display_objects_button.setFixedSize(120, 30)
hbox_buttons.addWidget(self.display_objects_button)
# # 添加保存检测结果按钮
self.save_button = QPushButton("💾保存检测结果")
self.save_button.clicked.connect(self.save_detection)
self.save_button.setEnabled(False)
self.save_button.setFixedSize(120, 30)
hbox_buttons.addWidget(self.save_button)
# 添加退出按钮
self.exit_button = QPushButton("❌退出")
self.exit_button.clicked.connect(self.exit_application)
self.exit_button.setFixedSize(120, 30)
hbox_buttons.addWidget(self.exit_button)
layout.addLayout(hbox_buttons)
central_widget = QWidget()
central_widget.setLayout(layout)
self.setCentralWidget(central_widget)
def save_detection(self):
detection_type = self.worker.detection_type
if detection_type == "image":
self.save_detection_results()
def select_image(self):
image_path, _ = QFileDialog.getOpenFileName(None, "选择图片文件", "", "图片文件 (*.jpg *.jpeg *.png)")
self.flag = 0
if image_path:
self.detect_image(image_path)
def detect_folder(self):
folder_path = QFileDialog.getExistingDirectory(self, "选择图片文件夹")
self.flag = 1
if folder_path:
image_paths = []
for filename in os.listdir(folder_path):
if filename.lower().endswith((".jpg", ".jpeg", ".png")):
image_path = os.path.join(folder_path, filename)
image_paths.append(image_path)
for image_path in image_paths:
self.detect_image(image_path)
def detect_image(self, image_path):
if image_path:
print(image_path)
image = cv2.imread(image_path)
if image is not None:
if self.flag == 0:
results = self.worker.model.predict(image)
elif self.flag == 1:
results = self.worker.model.predict(image_path, save=True)
self.worker.detection_type = "image"
if results:
self.current_results = results
self.worker.current_annotated_image = results[0].plot()
annotated_image = self.worker.current_annotated_image
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
height1, width1, channel1 = image_rgb.shape
bytesPerLine1 = 3 * width1
qimage1 = QImage(image_rgb.data, width1, height1, bytesPerLine1, QImage.Format_RGB888)
pixmap1 = QPixmap.fromImage(qimage1)
self.label1.setPixmap(pixmap1.scaled(self.label1.size(), Qt.KeepAspectRatio))
annotated_image = cv2.cvtColor(annotated_image, cv2.COLOR_BGR2RGB)
height2, width2, channel2 = annotated_image.shape
bytesPerLine2 = 3 * width2
qimage2 = QImage(annotated_image.data, width2, height2, bytesPerLine2, QImage.Format_RGB888)
pixmap2 = QPixmap.fromImage(qimage2)
self.label2.setPixmap(pixmap2.scaled(self.label2.size(), Qt.KeepAspectRatio))
self.save_button.setEnabled(True)
cv2.waitKey(300) # 修改图片切换时间
def save_detection_results(self):
if self.worker.current_annotated_image is not None:
self.worker.save_image(self.worker.current_annotated_image)
def show_detected_objects(self):
frame = self.current_results
if frame:
det_info = self.worker.detect_objects(frame)
if det_info:
object_count = len(det_info)
object_info = f"识别到的物体总个数:{object_count}\n"
object_dict = {}
for obj in det_info:
if obj in object_dict:
object_dict[obj] += 1
else:
object_dict[obj] = 1
sorted_objects = sorted(object_dict.items(), key=lambda x: x[1], reverse=True)
for obj_name, obj_count in sorted_objects:
object_info += f"{obj_name}: {obj_count}\n"
self.show_message_box("识别结果", object_info)
else:
self.show_message_box("识别结果", "未检测到物体")
def show_message_box(self, title, message):
msg_box = QMessageBox(self)
msg_box.setWindowTitle(title)
msg_box.setText(message)
msg_box.exec_()
def load_model(self):
if self.worker.load_model():
self.image_detect_button.setEnabled(True)
self.folder_detect_button.setEnabled(True)
self.display_objects_button.setEnabled(True)
def exit_application(self):
sys.exit()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
参考: 笑脸惹桃花