前言

本文基于 YOLOv11 模型开发关于草莓分级采摘的应用平台,数据集为网上购买的草莓模型经采集设备端完成,采集设备主要用DaBai DCW深度相机采集,部分为手机端拍摄的高清图像,数据分成熟果实(大、中、小三级)以及未成熟果实(一级),约1000张,标签采用labelimg手动标注。该草莓分级采摘应用平台主要服务实验室室内机械臂抓取实验、比赛演示等使用,可提供草莓模型链接。

一、软件功能演示与使用

软件主要功能演示

(1)单张、多张图片检测

单张检测:
在这里插入图片描述

文件夹检测:
在这里插入图片描述

(2)保存检测图片与信息

在这里插入图片描述

二、环境搭建

pytorch环境配置可参考以下内容:PyTorch全网最全安装实践教程【上篇】

三、模型训练、评估、预测

在这里插入图片描述

1、数据集准备

(1)数据集与标签
在这里插入图片描述
(2)数据标注
在这里插入图片描述

(3)原始数据集采用如下代码(voc_to_yolo.py)将xml格式转为txt格式:


 
import os
import xml.etree.ElementTree as ET

# 定义类别顺序
categories = ['ripe1', 'ripe2','ripe3','unripe']
category_to_index = {category: index for index, category in enumerate(categories)}

# 定义输入文件夹和输出文件夹
input_folder = r'./data/annotations'  # 替换为实际的XML文件夹路径
output_folder = r'./data/labels'  # 替换为实际的输出TXT文件夹路径

# 确保输出文件夹存在
os.makedirs(output_folder, exist_ok=True)

# 遍历输入文件夹中的所有XML文件
for filename in os.listdir(input_folder):
    if filename.endswith('.xml'):
        xml_path = os.path.join(input_folder, filename)
        # 解析XML文件
        tree = ET.parse(xml_path)
        root = tree.getroot()
        # 提取图像的尺寸
        size = root.find('size')
        width = int(size.find('width').text)
        height = int(size.find('height').text)
        # 存储name和对应的归一化坐标
        objects = []

        # 遍历XML中的object标签
        for obj in root.findall('object'):
            name = obj.find('name').text
            if name in category_to_index:
                category_index = category_to_index[name]
            else:
                continue  # 如果name不在指定类别中,跳过该object

            bndbox = obj.find('bndbox')
            xmin = int(bndbox.find('xmin').text)
            ymin = int(bndbox.find('ymin').text)
            xmax = int(bndbox.find('xmax').text)
            ymax = int(bndbox.find('ymax').text)

            # 转换为中心点坐标和宽高
            x_center = (xmin + xmax) / 2.0
            y_center = (ymin + ymax) / 2.0
            w = xmax - xmin
            h = ymax - ymin

            # 归一化
            x = x_center / width
            y = y_center / height
            w = w / width
            h = h / height

            objects.append(f"{category_index} {x} {y} {w} {h}")

        # 输出结果到对应的TXT文件
        txt_filename = os.path.splitext(filename)[0] + '.txt'
        txt_path = os.path.join(output_folder, txt_filename)
        with open(txt_path, 'w') as f:
            for obj in objects:
                f.write(obj + '\n')

结果如下图:

在这里插入图片描述
(4)数据集划分为yolov11可训练模式,取8:1:1(可调整)
在这里插入图片描述
采用如下代码(datas_split.py)实现:



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 = r"data\images"  # 图片文件夹
	label_path = r'data\labels'  # 标签文件夹
	new_file_path = r"data\VOCdevkit"  # 新数据存放位置
	split_data(file_path, label_path, new_file_path, train_rate=0.8, val_rate=0.1, test_rate=0.1)

2、数据集训练

(1)新建data.yaml文件,train/data.yaml,内容如下:

train: ultralytics-main/data/VOCdevkit/train/images  # train images (relative to 'path') 128 images
val: ultralytics-main/data/VOCdevkit/val/images  # val images (relative to 'path') 128 images
test: ultralytics-main/data/VOCdevkit/test/images
 
nc: 4
 
# Classes
names: ['ripe1', 'ripe2','ripe3','unripe']

介绍:

train、val、test为上一步datas_split.py生成结果,填写本地相对应路径即可。
nc:标签类别数量。
names:自己数据集的标签名称,我的数据集标签名称分两种“helmet”和“head”。

(2)新建训练文件train.py。

import warnings
warnings.filterwarnings('ignore')
from ultralytics import YOLO
if __name__ == '__main__':
  model = YOLO('ultralytics/cfg/models/11/yolo11n.yaml')
  model.load('model/yolo11n.pt')  #注释则不加载
  results = model.train(
    data='ultralytics-main/train/data.yaml',  #数据集配置文件的路径
    epochs=200,  #训练轮次总数
    batch=32,  #批量大小,即单次输入多少图片训练
    imgsz=640,  #训练图像尺寸
    workers=8,  #加载数据的工作线程数
    device= 0,  #指定训练的计算设备,无nvidia显卡则改为 'cpu'
    optimizer='SGD',  #训练使用优化器,可选 auto,SGD,Adam,AdamW 等
    amp= True,  #True 或者 False, 解释为:自动混合精度(AMP) 训练
    cache=False  # True 在内存中缓存数据集图像,服务器推荐开启
)

(3)运行train.py训练文件。

python train.py

在这里插入图片描述
成功开始训练!

3、训练结果评估

训练完毕后,训练结果保存在run/detect/目录下,包含权重文件、训练损失函数等信息。
在这里插入图片描述

4、模型预测

本文提供多种预测方式,支持单张预测、文件夹批量预测、视频预测、开启摄像头预测。在这里仅展示单张图片预测效果,代码和结果如下:

代码展示:

from ultralytics import YOLO

# 加载一个预训练的 YOLO11n 模型
model = YOLO(r"E:\Projects\YOLOV11-pyqt5\4-strawberry\model\strawberry.pt")
# 对图像执行目标检测
results = model(r"E:\Projects\YOLOV11-pyqt5\4-strawberry\interface\input\img1\100.jpg")  # 对图像进行预测
results[0].show()  # 显示结果

结果展示:
在这里插入图片描述
(注:yolov11提供5种预训练权重模型(n、s、m、l、x),不同模型会对精度和推理速度有一定影响,按精度顺序大小:x>l>m>s>n,相应的推理速度快慢:n>s>m>l>x,根据自己的需求选择适合自己的模型。展示所用模型为“yolov11n”)

关注公众号【码上视觉】,分享更多有趣项目~

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐