小白直接用yolov11环境配置+yolov11训练

yolov11+luna16数据集

1.简单粗暴配环境(已经测试过,可以进行兼容)

1. 创建新的虚拟环境

使用 conda 创建一个新的虚拟环境,命名为 yolov11_env(你可以根据需要修改名称),并指定 Python 版本(推荐使用 Python 3.10):

conda create -n yolov11_env python=3.10

2. 激活虚拟环境

激活刚刚创建的环境:

conda activate yolov11_env

3. 安装 PyTorch

根据你的硬件(CPU 或 GPU)安装 PyTorch。以下是安装命令:

  • CPU 版本

    pip install torch==2.0.0 torchvision==0.15.0 torchaudio==2.0.0 --index-url https://download.pytorch.org/whl/cpu
    
  • GPU 版本(CUDA 11.8)

    pip install torch==2.0.0 torchvision==0.15.0 torchaudio==2.0.0 --index-url https://download.pytorch.org/whl/cu118
    
  • GPU 版本(CUDA 11.7)

    pip install torch==2.0.0 torchvision==0.15.0 torchaudio==2.0.0 --index-url https://download.pytorch.org/whl/cu117
    
  • GPU 版本(CUDA 11.6)

    pip install torch==2.0.0 torchvision==0.15.0 torchaudio==2.0.0 --index-url https://download.pytorch.org/whl/cu116
    

如果你不确定该安装哪个版本,可以参考 PyTorch 官方安装指南


4. 安装 Ultralytics 和 YOLOv11 依赖

安装 ultralytics 库及其依赖:

pip install ultralytics

5. 安装其他必要库

安装一些常用的数据处理和可视化库:

pip install numpy pandas matplotlib opencv-python scipy

6. 验证安装

验证 PyTorch 和 Ultralytics 是否正确安装:

python -c "import torch; print(torch.__version__)"
python -c "import ultralytics; print(ultralytics.__version__)"

7. 运行 YOLOv11 训练

激活环境后,运行你的 YOLOv11 训练脚本:

python train.py --data your_dataset.yaml --weights yolov11s.pt --epochs 50 --batch 16

8. 清理旧环境(可选)

如果你不再需要旧的 yolov11 环境,可以将其删除:

conda remove -n yolov11 --all

2.对其luna16数据集的处理

1.在官网上进行下载好数据集,下载annotations.csv和多个subset0-9以内几个都可以

2.直接运行以下代码,文件存储如图

image-20250318183627036

import os
from glob import glob
import pandas as pd
import numpy as np
import SimpleITK as sitk
from tqdm import tqdm
from sklearn.cluster import KMeans
from skimage import morphology, measure
from xml.etree.ElementTree import Element, ElementTree, tostring
from PIL import Image


# 设置基础路径
luna_base_path = "subset0-9/"
annotation_path = "subset0-9/annotations.csv"
output_npy_base_path = "npy"
output_data_base_path = "data"

# 定义函数,将CT扫描中的像素值归一化
def normalizePlanes(npzarray):
    maxHU = 400
    minHU = -1000
    npzarray = (npzarray - minHU) / (maxHU - minHU)  # 像素直归一化处理
    npzarray[npzarray > 1] = 1
    npzarray[npzarray < 0] = 0
    npzarray *= 255  # 所有归一的像素乘以255,即1-255范围

    return npzarray.astype(int)

# 定义函数,创建结节在CT扫描中的掩膜
def make_mask(center, diam, z, width, height, spacing, origin):
    mask = np.zeros([height, width])  # 匹配图像,生成一个确定高和宽的,元素全为0的掩码

    # 定义结节所在的体素范围
    v_center = (center - origin) / spacing  # 将肺结节中心坐标从世界坐标系转换为体素坐标系
    v_diam = int(diam / spacing[0] + 5)  # 计算肺结节直径在体素坐标系中的大小
    v_xmin = np.max([0, int(v_center[0] - v_diam) - 5])  # 计算肺结节所在的 x 方向上的最小体素坐标
    v_xmax = np.min([width - 1, int(v_center[0] + v_diam) + 5])  # 计算肺结节所在的 x 方向上的最大体素坐标
    v_ymin = np.max([0, int(v_center[1] - v_diam) - 5])  # 计算肺结节所在的 y 方向上的最小体素坐标
    v_ymax = np.min([height - 1, int(v_center[1] + v_diam) + 5])  # 计算肺结节所在的 y 方向上的最大体素坐标

    v_xrange = range(v_xmin, v_xmax + 1)  # 表示 x 方向上的体素坐标范围
    v_yrange = range(v_ymin, v_ymax + 1)  # 表示 y 方向上的体素坐标范围

    x_data = [x * spacing[0] + origin[0] for x in range(width)]  # 通过列表推导式,创建一个列表 x_data,其中包含了图像每个像素点在 x 方向上的世界坐标
    y_data = [x * spacing[1] + origin[1] for x in range(height)]  # 通过列表推导式,创建一个列表 y_data,其中包含了图像每个像素点在 y 方向上的世界坐标

    # 结节周围全都填充1,用于在图像中标记肺结节位置
    for v_x in v_xrange:
        for v_y in v_yrange:
            p_x = spacing[0] * v_x + origin[0]  # 计算了当前体素在世界坐标系中的 x 坐标
            p_y = spacing[1] * v_y + origin[1]  # 计算了当前体素在世界坐标系中的 y 坐标
            if np.linalg.norm(center - np.array([p_x, p_y, z])) <= diam:  # 如果体素在肺结节内部或边缘
                mask[int((p_y - origin[1]) / spacing[1]), int((p_x - origin[0]) / spacing[0])] = 1.0

    return mask

def beatau(e, level=0):
    if len(e) > 0:
        e.text = '\n' + '\t' * (level + 1)
        for child in e:
            beatau(child, level + 1)
        child.tail = child.tail[:-1]
    e.tail = '\n' + '\t' * level

def csvtoxml(name, x, y, w, h):
    root = Element('annotation')  # 根节点
    erow1 = Element('folder')  # 节点1
    erow1.text = "VOC"

    erow2 = Element('filename')  # 节点2
    erow2.text = str(name)

    erow3 = Element('size')  # 节点3
    erow31 = Element('width')
    erow31.text = "512"
    erow32 = Element('height')
    erow32.text = "512"
    erow33 = Element('depth')
    erow33.text = "3"
    erow3.append(erow31)
    erow3.append(erow32)
    erow3.append(erow33)

    erow4 = Element('object')
    erow41 = Element('name')
    erow41.text = 'nodule'
    erow42 = Element('bndbox')
    erow4.append(erow41)
    erow4.append(erow42)
    erow421 = Element('xmin')
    erow421.text = str(x - np.round(w / 2).astype(int))
    erow422 = Element('ymin')
    erow422.text = str(y - np.round(h / 2).astype(int))
    erow423 = Element('xmax')
    erow423.text = str(x + np.round(w / 2).astype(int))
    erow424 = Element('ymax')
    erow424.text = str(y + np.round(h / 2).astype(int))
    erow42.append(erow421)
    erow42.append(erow422)
    erow42.append(erow423)
    erow42.append(erow424)

    root.append(erow1)
    root.append(erow2)
    root.append(erow3)
    root.append(erow4)
    beatau(root)

    return ElementTree(root)

# 定义主要处理函数
def process_subset(subset_path):
    # 获取文件列表
    file_list = glob(os.path.join(subset_path, "*.mhd"))

    # 获取文件名与案例相关的路径
    def get_filename(case):
        nonlocal file_list
        for f in file_list:
            if case in f:
                return f

    # 读取包含结节注释的CSV文件
    df_node = pd.read_csv(annotation_path)
    df_node["file"] = df_node["seriesuid"].apply(get_filename)  # 对于 "seriesuid" 中的每个值,找到对应的文件路径
    df_node = df_node.dropna()  # 从数据框中删除包含 NaN 的行,确保数据框中不包含缺失文件路径的记录

    # 遍历图像文件
    for fcount, img_file in enumerate(tqdm(file_list)):
        print("获取图像文件 %s 的掩膜" % img_file.replace(subset_path, ""))
        mini_df = df_node[df_node["file"] == img_file]  # mini_df 包含了与当前图像文件相关联的所有结节注释
        if len(mini_df) > 0:  # 跳过没有结节的文件
            # 读取图像数据
            itk_img = sitk.ReadImage(img_file)
            img_array = sitk.GetArrayFromImage(itk_img)  # 将SimpleITK图像对象转换为NumPy三维数组(z, y, x)
            num_z, height, width = img_array.shape  # 图像的深度(z方向上的切片数量)、高度和宽度
            origin = np.array(itk_img.GetOrigin())  # 世界坐标系下的 x, y, z (mm)
            spacing = np.array(itk_img.GetSpacing())  # 世界坐标中的体素间隔 (mm)

            # 遍历所有结节的注释
            for node_idx, cur_row in mini_df.iterrows():
                node_x = cur_row["coordX"]
                node_y = cur_row["coordY"]
                node_z = cur_row["coordZ"]
                diam = cur_row["diameter_mm"]

                # 保留三个切片
                imgs = np.ndarray([3, height, width], dtype=np.float32)  # 创建一个形状为 (3, height, width) 的三维数组 imgs,用于存储图像数据
                masks = np.ndarray([3, height, width], dtype=np.uint8)  # 创建一个形状为 (3, height, width) 的三维数组 masks,用于存储掩膜数据
                center = np.array([node_x, node_y, node_z])  # 表示结节在图像中的中心位置
                v_center = np.rint((center - origin) / spacing)  # 体素坐标系的结节中心 (x, y, z)

                for i, i_z in enumerate(np.arange(int(v_center[2]) - 1, int(v_center[2]) + 2).clip(0, num_z - 1)):  # 防止超出 z
                    name = "%04d_%04d.jpg" % (fcount, node_idx)
                    x = v_center[0]
                    y = v_center[1]
                    w = int(diam / spacing[0] + 5)  # 计算肺结节直径在体素坐标系中的大小
                    h = int(diam / spacing[0] + 5)  # 计算肺结节直径在体素坐标系中的大小
                    label = csvtoxml(name, x, y, w, h)
                    mask = make_mask(center, diam, i_z * spacing[2] + origin[2], width, height, spacing, origin)  # 调用 make_mask 函数生成结节的掩膜
                    masks[i] = mask  # 将生成的掩膜保存到 masks 数组的相应位置
                    imgs[i] = normalizePlanes(img_array[i_z])  # 将规范化后的数据保存到 imgs 数组的相应位置

                # 拼接输出路径
                output_npy_path = os.path.join(output_npy_base_path, os.path.basename(subset_path))
                if not os.path.exists(output_npy_path):
                    os.makedirs(output_npy_path)
                output_data_path = os.path.join(output_data_base_path, os.path.basename(subset_path), "labels")
                if not os.path.exists(output_data_path):
                    os.makedirs(output_data_path)

                np.save(os.path.join(output_npy_path, "images_%04d_%04d.npy" % (fcount, node_idx)), imgs)  # 将处理后的图像数据 imgs 保存为一个 .npy 文件
                np.save(os.path.join(output_npy_path, "masks_%04d_%04d.npy" % (fcount, node_idx)), masks)  # 将处理后的结节掩膜 masks 保存为一个 .npy 文件
                label.write(os.path.join(output_data_path, "%04d_%04d_1.xml" % (fcount, node_idx)))
                label.write(os.path.join(output_data_path, "%04d_%04d_2.xml" % (fcount, node_idx)))
                label.write(os.path.join(output_data_path, "%04d_%04d_3.xml" % (fcount, node_idx)))

# 获取肺实质
def get_lungmask(img_list):
    for img_file in img_list:
        # 加载图像数据
        imgs_to_process = np.load(img_file).astype(np.float64)
        print("处理图像", img_file)

        # 处理每个切片
        for i in range(len(imgs_to_process)):
            # print(imgs_to_process.shape)
            img = imgs_to_process[i]

            # 标准化
            mean = np.mean(img)
            std = np.std(img)
            img = (img - mean) / std

            # 寻找肺部附近的平均像素,以重新调整过度曝光的图像
            middle = img[100:400, 100:400]

            # 使用 Kmeans 算法将前景(放射性不透明组织)和背景(放射性透明组织,即肺部)分离。
            # 仅在图像中心进行此操作,以尽可能避免图像的非组织部分。
            kmeans = KMeans(n_clusters=2, n_init=10).fit(np.reshape(middle, [np.prod(middle.shape), 1]))
            centers = sorted(kmeans.cluster_centers_.flatten())
            threshold = np.mean(centers)
            thresh_img = np.where(img < threshold, 1.0, 0.0)  # 阈值化图像,二值化处理

            # 腐蚀和膨胀
            eroded = morphology.erosion(thresh_img, np.ones([4, 4]))
            dilation = morphology.dilation(eroded, np.ones([10, 10]))

            # 对二值图像进行标记,标记连通区域
            labels = measure.label(dilation)
            label_vals = np.unique(labels)
            regions = measure.regionprops(labels)

            good_labels = []
            for prop in regions:
                B = prop.bbox  # 边界框
                if B[2] - B[0] < 475 and B[3] - B[1] < 475 and B[0] > 40 and B[2] < 472:
                    good_labels.append(prop.label)

            # 创建肺部掩码lungmask
            lungmask = np.zeros([512, 512], dtype=np.int8)
            for N in good_labels:
                lungmask = lungmask + np.where(labels == N, 1, 0)
                # print(lungmask.shape)
            lungmask = morphology.dilation(lungmask, np.ones([10, 10]))
            imgs_to_process[i] = lungmask

        # 将处理后的 lungmask 保存
        # print(imgs_to_process.shape)
        np.save(img_file.replace("images", "lungmasks"), imgs_to_process)

def npytojpg(img_list):
    for i in range(len(img_list)):
        # 加载原始图像和肺部 mask
        origin_img = np.load(img_list[i])
        lung_mask = np.load(img_list[i].replace("images", "lungmasks"))
        # 使用os.path.basename()获取文件名
        file_name_npy = os.path.basename(img_list[i])
        # 使用os.path.splitext()分割文件名和后缀
        file_name, file_extension = os.path.splitext(file_name_npy)

        for j in range(len(origin_img)):
            # 获取当前切片的原始图像和肺部 mask
            img = origin_img[j]
            lung_img = lung_mask[j]

            # 对原始图像进行肺部分割
            segment = img * lung_img

            # 将分割结果转为 PIL Image,并保存为 JPEG 文件
            segment = Image.fromarray(segment)
            segment = segment.convert('RGB')
            new_file_name = file_name.replace("images_", "")
            new_file_path = os.path.join(save_path, f"{new_file_name}_{j + 1}.jpg")
            segment.save(new_file_path)

# 遍历所有子集,生成images*.npy、masks*.npy和*.xml文件
for subset_number in range(10):
    subset_path = os.path.join(luna_base_path, f"subset{subset_number}")
    process_subset(subset_path)

# 遍历所有子集,生成lungmasks*.npy文件
for i in range(10):
    img_list = glob(os.path.join(output_npy_base_path, f"subset{i}/", "images*.npy"))
    get_lungmask(img_list)

# 历遍所有子集,生成*.jpg文件
for subset_num in range(10):
    # 获取文件列表
    img_list = glob(os.path.join(output_npy_base_path, "subset{}".format(subset_num), "images*.npy"))
    print(img_list)
    # 指定保存路径
    save_path = os.path.join(output_data_base_path, "subset{}/".format(subset_num), "images")
    # 如果保存路径不存在,则创建
    if not os.path.exists(save_path):
        os.makedirs(save_path)
    npytojpg(img_list)

3。得到图片和xml格式对应

可以将subset0下的images和lables都放在一个文件夹当中例如

image-20250318183930498

4.将xml格式转为yolo格式

①找出xml的类别有多少个
import os
import xml.etree.ElementTree as ET


def convert_xml_to_yolo(xml_file, output_dir, class_mapping):
    """
    将单个 XML 文件转换为 YOLO 格式的标注文件。

    :param xml_file: XML 文件路径
    :param output_dir: YOLO 格式标注文件的输出目录
    :param class_mapping: 类别名称到类别索引的映射字典
    """
    try:
        # 解析 XML 文件
        tree = ET.parse(xml_file)
        root = tree.getroot()

        # 获取图像尺寸
        size = root.find("size")
        if size is None:
            print(f"跳过 {xml_file},原因:缺少 <size> 标签")
            return

        img_width = int(size.find("width").text)
        img_height = int(size.find("height").text)

        # 创建 YOLO 格式的标注文件
        yolo_file = os.path.join(output_dir, os.path.splitext(os.path.basename(xml_file))[0] + ".txt")
        with open(yolo_file, "w") as f:
            # 遍历每个目标
            for obj in root.findall("object"):
                class_name = obj.find("name").text
                if class_name not in class_mapping:
                    print(f"警告:{class_name} 未在类别映射中定义,跳过")
                    continue  # 忽略未映射的类别

                # 获取类别索引
                class_id = class_mapping[class_name]

                # 获取边界框坐标
                bbox = obj.find("bndbox")
                if bbox is None:
                    print(f"警告:{xml_file} 缺少 <bndbox>,跳过此对象")
                    continue

                xmin = float(bbox.find("xmin").text)
                ymin = float(bbox.find("ymin").text)
                xmax = float(bbox.find("xmax").text)
                ymax = float(bbox.find("ymax").text)

                # 边界框数值检查
                if xmin < 0 or ymin < 0 or xmax > img_width or ymax > img_height:
                    print(f"警告:{xml_file} 边界框超出范围,跳过")
                    continue

                # 计算归一化坐标(YOLO 格式)
                x_center = (xmin + xmax) / 2 / img_width
                y_center = (ymin + ymax) / 2 / img_height
                width = (xmax - xmin) / img_width
                height = (ymax - ymin) / img_height

                # 写入 YOLO 格式的标注文件
                f.write(f"{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\n")

        print(f"已转换:{xml_file} -> {yolo_file}")

    except Exception as e:
        print(f"错误处理 {xml_file}{str(e)}")


def convert_folder_xml_to_yolo(xml_dir, output_dir, class_mapping):
    """
    将指定目录下的所有 XML 文件转换为 YOLO 格式的标注文件。

    :param xml_dir: 包含 XML 文件的目录
    :param output_dir: YOLO 格式标注文件的输出目录
    :param class_mapping: 类别名称到类别索引的映射字典
    """
    # 确保输出目录存在
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)

    # 遍历 XML 目录下的所有文件
    xml_files = [f for f in os.listdir(xml_dir) if f.endswith(".xml")]
    if not xml_files:
        print("警告:未找到 XML 文件!")
        return

    for xml_file in xml_files:
        xml_path = os.path.join(xml_dir, xml_file)
        convert_xml_to_yolo(xml_path, output_dir, class_mapping)

    print(f"转换完成!YOLO 格式标注已保存至 {output_dir}")


# 示例用法
if __name__ == "__main__":
    # 定义类别映射(根据你的数据集修改)
    class_mapping = {
        "nodule": 0,
    }

    # 输入目录(包含 XML 文件的目录)
    xml_directory = 'D:/jetbrains/PycharmProjects/G-course/数据集处理/data/subset0/labels'  # 你的 XML 标注文件夹路径
    # 输出目录(保存 YOLO 格式标注文件的目录)
    output_directory = "D:/jetbrains/PycharmProjects/G-course/数据集处理/data/subset0/Ann"  # 你的 YOLO 标注输出文件夹

    # 转换 XML 文件为 YOLO 格式
    convert_folder_xml_to_yolo(xml_directory, output_directory, class_mapping)
②xml转yolo代码
import os
import xml.etree.ElementTree as ET


def convert_xml_to_yolo(xml_file, output_dir, class_mapping):
    """
    将单个 XML 文件转换为 YOLO 格式的标注文件。

    :param xml_file: XML 文件路径
    :param output_dir: YOLO 格式标注文件的输出目录
    :param class_mapping: 类别名称到类别索引的映射字典
    """
    try:
        # 解析 XML 文件
        tree = ET.parse(xml_file)
        root = tree.getroot()

        # 获取图像尺寸
        size = root.find("size")
        if size is None:
            print(f"跳过 {xml_file},原因:缺少 <size> 标签")
            return

        img_width = int(size.find("width").text)
        img_height = int(size.find("height").text)

        # 创建 YOLO 格式的标注文件
        yolo_file = os.path.join(output_dir, os.path.splitext(os.path.basename(xml_file))[0] + ".txt")
        with open(yolo_file, "w") as f:
            # 遍历每个目标
            for obj in root.findall("object"):
                class_name = obj.find("name").text
                if class_name not in class_mapping:
                    print(f"警告:{class_name} 未在类别映射中定义,跳过")
                    continue  # 忽略未映射的类别

                # 获取类别索引
                class_id = class_mapping[class_name]

                # 获取边界框坐标
                bbox = obj.find("bndbox")
                if bbox is None:
                    print(f"警告:{xml_file} 缺少 <bndbox>,跳过此对象")
                    continue

                xmin = float(bbox.find("xmin").text)
                ymin = float(bbox.find("ymin").text)
                xmax = float(bbox.find("xmax").text)
                ymax = float(bbox.find("ymax").text)

                # 边界框数值检查
                if xmin < 0 or ymin < 0 or xmax > img_width or ymax > img_height:
                    print(f"警告:{xml_file} 边界框超出范围,跳过")
                    continue

                # 计算归一化坐标(YOLO 格式)
                x_center = (xmin + xmax) / 2 / img_width
                y_center = (ymin + ymax) / 2 / img_height
                width = (xmax - xmin) / img_width
                height = (ymax - ymin) / img_height

                # 写入 YOLO 格式的标注文件
                f.write(f"{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\n")

        print(f"已转换:{xml_file} -> {yolo_file}")

    except Exception as e:
        print(f"错误处理 {xml_file}{str(e)}")


def convert_folder_xml_to_yolo(xml_dir, output_dir, class_mapping):
    """
    将指定目录下的所有 XML 文件转换为 YOLO 格式的标注文件。

    :param xml_dir: 包含 XML 文件的目录
    :param output_dir: YOLO 格式标注文件的输出目录
    :param class_mapping: 类别名称到类别索引的映射字典
    """
    # 确保输出目录存在
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)

    # 遍历 XML 目录下的所有文件
    xml_files = [f for f in os.listdir(xml_dir) if f.endswith(".xml")]
    if not xml_files:
        print("警告:未找到 XML 文件!")
        return

    for xml_file in xml_files:
        xml_path = os.path.join(xml_dir, xml_file)
        convert_xml_to_yolo(xml_path, output_dir, class_mapping)

    print(f"转换完成!YOLO 格式标注已保存至 {output_dir}")


# 示例用法
if __name__ == "__main__":
    # 定义类别映射(根据你的数据集修改)
    class_mapping = {
        "nodule": 0,
    }

    # 输入目录(包含 XML 文件的目录)
    xml_directory = "data/annotations"  # 你的 XML 标注文件夹路径
    # 输出目录(保存 YOLO 格式标注文件的目录)
    output_directory = "data/yolo_labels"  # 你的 YOLO 标注输出文件夹

    # 转换 XML 文件为 YOLO 格式
    convert_folder_xml_to_yolo(xml_directory, output_directory, class_mapping)

将其进行存储成这样

image-20250318184257545

③划分好数据集
import os
import shutil
import random
from tqdm import tqdm

"""
标注文件是yolo格式(txt文件)
训练集:验证集:测试集 (7:2:1) 
"""


def split_img(img_path, label_path, split_list):
    try:
        Data = './Maskdata'
        # 创建需要的文件夹
        train_img_dir = os.path.join(Data, 'train', 'images')
        val_img_dir = os.path.join(Data, 'val', 'images')
        test_img_dir = os.path.join(Data, 'test', 'images')

        train_label_dir = os.path.join(Data, 'train', 'labels')
        val_label_dir = os.path.join(Data, 'val', 'labels')
        test_label_dir = os.path.join(Data, 'test', 'labels')

        # 创建文件夹
        os.makedirs(train_img_dir, exist_ok=True)
        os.makedirs(train_label_dir, exist_ok=True)
        os.makedirs(val_img_dir, exist_ok=True)
        os.makedirs(val_label_dir, exist_ok=True)
        os.makedirs(test_img_dir, exist_ok=True)
        os.makedirs(test_label_dir, exist_ok=True)

    except Exception as e:
        print(f'文件目录已存在: {e}')

    train, val, test = split_list
    all_img = os.listdir(img_path)
    all_img_path = [os.path.join(img_path, img) for img in all_img]

    train_img = random.sample(all_img_path, int(train * len(all_img_path)))
    for img in train_img:
        all_img_path.remove(img)

    val_img = random.sample(all_img_path, int(val / (val + test) * len(all_img_path)))
    for img in val_img:
        all_img_path.remove(img)

    test_img = all_img_path

    # 将图片和标签文件复制到相应的目录
    copy_files(train_img, label_path, train_img_dir, train_label_dir, 'train')
    copy_files(val_img, label_path, val_img_dir, val_label_dir, 'val')
    copy_files(test_img, label_path, test_img_dir, test_label_dir, 'test')


def copy_files(img_list, label_path, img_dir, label_dir, desc):
    for img in tqdm(img_list, desc=f'{desc} ', ncols=80, unit='img'):
        img_name = os.path.basename(img)
        label_name = os.path.splitext(img_name)[0] + '.txt'
        shutil.copy(img, img_dir)
        shutil.copy(os.path.join(label_path, label_name), label_dir)


if __name__ == '__main__':
    img_path = 'JPEGImage'  # 你的图片存放的路径(路径一定是相对于你当前的这个脚本文件而言的)
    label_path = 'Annotations'  # 你的txt文件存放的路径(路径一定是相对于你当前的这个脚本文件而言的)
    split_list = [0.7, 0.3, 0.1]  # 数据集划分比例[train:val:test]
    split_img(img_path, label_path, split_list)

3.开始yolov11的训练

1.写data.yaml

image-20250318184620491

train: ../Maskdata/train/images
val: ../Maskdata/val/images
test: ../Maskdata/test/images
nc: 1
names:
  0: nodule
2.在ultralytics/models/11下重写自己配置

image-20250318184735375

只改自己的类别

image-20250318184752371

3.写一个train.py
import warnings

warnings.filterwarnings('ignore')
from ultralytics import YOLO

if __name__ == '__main__':
    model = YOLO('ultralytics/cfg/models/11/my_yolo11.yaml')  # 指定YOLO模型对象,并加载指定配置文件中的模型配置
    #model.load('yolov11s.pt')      #加载预训练的权重文件'yolov11s.pt',加速训练并提升模型性能
    model.train(data='D:/jetbrains/PycharmProjects/G-course/ultralytics-8.3.39/Maskdata/data.yaml',  # 指定训练数据集的配置文件路径,这个.yaml文件包含了数据集的路径和类别信息
                cache=False,  # 是否缓存数据集以加快后续训练速度,False表示不缓存
                imgsz=640,  # 指定训练时使用的图像尺寸,640表示将输入图像调整为640x640像素
                epochs=5,  # 设置训练的总轮数为200轮
                batch=2,  # 设置每个训练批次的大小为16,即每次更新模型时使用16张图片
                close_mosaic=10,  # 设置在训练结束前多少轮关闭 Mosaic 数据增强,10 表示在训练的最后 10 轮中关闭 Mosaic
                workers=8,  # 设置用于数据加载的线程数为8,更多线程可以加快数据加载速度
                patience=50,  # 在训练时,如果经过50轮性能没有提升,则停止训练(早停机制)
                device='cpu',  # 指定使用的设备,'0'表示使用第一块GPU进行训练
                optimizer='SGD',  # 设置优化器为SGD(随机梯度下降),用于模型参数更新
                )
### Luna16数据集与YOLO算法概述 Luna16是一个用于肺结节检测的数据集,其中包含了大量胸部CT扫描图像以及标注信息[^1]。YOLO(You Only Look Once)是一种实时目标检测框架,在单次推理过程中完成边界框预测和类别概率估计。 ### YOLO的技术细节 YOLO将输入图片分割成S×S网格结构,如果某个物体的中心落在该格子内,则此格子负责预测这个物体。对于每一个格子,模型会预测B个边框及其置信度分数,同时还会给出C类条件概率。这些预测被编码为一个维度为(S,S,B×5+C)张量。 ```python import torch from torchvision.models.detection import fasterrcnn_resnet50_fpn, yolo_v3_darknet53 model = yolo_v3_darknet53(pretrained=True) model.eval() ``` ### 结合Luna16实现YOLO的方式 为了适应医学影像领域特别是针对LUNA16这样的三维数据集,通常会对原始二维版本的YOLO做出调整: - 将传统卷积层替换为适用于体积数据处理的三维卷积操作; - 修改特征提取网络以更好地捕捉空间上下文关系; - 调整锚点尺寸来匹配肺部结节大小分布特性; 通过上述改动可以构建出适合于肺结节识别任务的新版YOLO架构,并利用LUNA16提供的高质量训练样本对其进行优化训练。 ### 使用教程概览 准备阶段需下载并预处理好来自LUNA16竞赛网站上的公开资源文件夹,接着按照官方文档指导安装必要的依赖库环境。之后可参照开源社区分享的相关项目源码学习如何定义自定义损失函数、评估指标等核心组件的设计思路。最后依据个人需求微调超参数直至获得满意效果为止。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值