22 KiB
AI Medical Education & Imaging (ai-med-edu)
Образовательный проект по AI-обработке медицинских изображений: детекция и сегментация анатомических структур (почки, их сегменты, опухоли, кисты, абсцессы) на основе DICOM и 3D NRRD данных с использованием архитектур YOLO.
🎯 Цели проекта
- Конвертация медицинских 3D-данных (NRRD, DICOM) в 2D-срезы формата YOLO
- Обучение моделей детекции (yolov8s, yolo26n) и сегментации (yolov8s-seg)
- Автоматическая подготовка и стратифицированное разделение датасета на train/val/test
- Поддержка индивидуальных схем классов для каждого препарата
- Проверка доступности GPU (PyTorch + CUDA)
- Образовательные материалы: лекции, семинары, лабораторные работы
📂 Структура репозитория
ai-med-edu/
│
├── README.md # Этот файл
├── ai-use-program.doc # Учебная программа
├── references.txt # Список литературы
├── labels.cache # Кэш лейблов YOLO
│
├── data/ # Эксперименты (каждый препарат - отдельная папка)
│ ├── 1_2236040_zno_cyst_AF/ # Эксперимент 1: ZNO Cyst AF
│ │ ├── predefined_classes.txt # Схема классов (12 классов)
│ │ ├── data.yaml # Конфиг YOLO
│ │ ├── 501 arterial ax 1mm iDose (5).nrrd # Исходные 3D данные
│ │ ├── Segmentation.seg.nrrd # Сегментационная маска
│ │ ├── dcm/ # DICOM-срезы (1042 файла)
│ │ ├── images/ # PNG-срезы (300 файлов)
│ │ ├── images_labels/ # Bbox-разметка
│ │ │ └── polygons/ # Полигоны для сегментации
│ │ └── images_result/ # Визуализация результатов
│ │ └── masks_sam/ # Маски SAM
│ │
│ ├── example/ # Пример структуры
│ │ ├── README.md
│ │ ├── images/
│ │ ├── images_labels/
│ │ │ └── polygons/
│ │ └── images_results/
│ │
│ └── prep/ # Подготовительные данные
│ ├── predefined_classes.txt
│ ├── csv/ # CSV-файлы с разметкой
│ ├── images/ # DCM и JPG файлы
│ ├── images_labels/ # TXT-лейблы
│ │ └── polygons/
│ └── images_results/ # Результаты
│ └── masks_sam/
│
├── scripts/ # Универсальные скрипты
│ ├── ttv_freq2.py # Сплиттер (стратифицированный)
│ ├── train_yolo.py # Обучение детекции
│ ├── train_yolo_seg.py # Обучение сегментации
│ ├── check_PyTorch_gpu.py # Проверка GPU
│ ├── check_tf_gpu.py # Проверка TensorFlow GPU
│ ├── config/ # Конфигурационные файлы
│ │ └── data.yaml
│ ├── Тема 2.1/ # Скрипты по теме 2.1
│ │ ├── analysis.py
│ │ ├── config_3d.py
│ │ ├── feature_3d.py
│ │ └── segmentation.py
│ └── Тема 2.2/ # Скрипты по теме 2.2
│ └── nrrd_to_yolo.py # Конвертация NRRD → YOLO
│
├── env/ # Виртуальное окружение Python
│ ├── Include/
│ ├── Lib/
│ │ └── site-packages/ # Установленные пакеты
│ ├── Scripts/ # Исполняемые файлы
│ ├── etc/
│ ├── share/
│ └── pyvenv.cfg
│
├── lectures/ # Лекционные материалы
│ ├── К26_1_1.pdf
│ ├── К26_2_1.pdf
│ └── К26_2_2.pdf
│
├── seminars/ # Семинарские занятия
│ ├── FeatureExtractionClient.ipynb
│ ├── Тема 1.1/ # Jupyter ноутбуки
│ │ ├── Dataset.ipynb
│ │ ├── Noise.ipynb
│ │ ├── Resource1.ipynb
│ │ ├── resource2.ipynb
│ │ └── segm2.ipynb
│ ├── Тема 1.2/
│ │ ├── Практикум1.ipynb
│ │ ├── Т1.ipynb
│ │ ├── Т2.ipynb
│ │ └── best_spleen_model.pth # Предобученная модель
│ ├── Тема 2.1/
│ │ ├── radiomics_report.html
│ │ ├── segmentation_full_report.html
│ │ ├── requirements_3d.txt
│ │ └── Лабораторная работа.docx
│ └── Тема 2.2/
│
└── labs/ # Лабораторные работы
├── Тема 1.1/
├── Тема 1.2/
├── Тема 2.1/
│ └── Лабораторная работа.docx
└── Тема 2.2/
🏷️ Схема классов (predefined_classes.txt)
Каждый эксперимент имеет СВОЙ СОБСТВЕННЫЙ файл predefined_classes.txt, расположенный в папке эксперимента. Это позволяет использовать разные наборы классов для разных препаратов.
Формат: один класс на строку, позиция в файле = YOLO index (0-based).
Пример: data/1_2236040_zno_cyst_AF/predefined_classes.txt (12 классов)
right_kidney # ID 1 → YOLO idx 0
right_kidney_upper_segment # ID 2 → YOLO idx 1
right_kidney_middle_segment # ID 3 → YOLO idx 2
right_kidney_lower_segment # ID 4 → YOLO idx 3
left_kidney # ID 5 → YOLO idx 4
left_kidney_upper_segment # ID 6 → YOLO idx 5
left_kidney_middle_segment # ID 7 → YOLO idx 6
left_kidney_lower_segment # ID 8 → YOLO idx 7
malignant_tumor # ID 9 → YOLO idx 8
benign_tumor # ID 10 → YOLO idx 9
cyst # ID 11 → YOLO idx 10
abscess # ID 12 → YOLO idx 11
Важно: Исходные лейблы (Label Studio / CVAT) используют 1-based ID (1–N). Скрипт
ttv_freq2.pyавтоматически перенумеровывает их в 0-based формат при копировании в папкуlabels/. Это необходимо, так как YOLOv8 требует, чтобы все ID в.txt-файлах были в диапазоне [0, nc-1] без пропусков.
🚀 Быстрый старт
1. Активация окружения
Windows:
cd D:\ai-med-edu
env\Scripts\activate
Linux / macOS:
cd /path/to/ai-med-edu
source env/bin/activate
2. Проверка GPU
python scripts/check_PyTorch_gpu.py
Ожидаемый результат:
CUDA доступна!
Количество доступных GPU: 1
GPU 0: NVIDIA GeForce RTX 3060
3. Установка зависимостей (при необходимости)
pip install ultralytics torch torchvision pyyaml pydicom nrrd scipy pandas opencv-python
📋 Полный пайплайн обучения
Вариант A: Детекция (bounding boxes)
# Шаг 1: Создать сплит с перенумерацией классов
python scripts/ttv_freq2.py --task detect ^
--images-dir data/1_2236040_zno_cyst_AF/images ^
--labels-dir data/1_2236040_zno_cyst_AF/images_labels ^
--output-dir data/1_2236040_zno_cyst_AF
# Шаг 2: Запустить обучение
python scripts/train_yolo.py ^
--data data/1_2236040_zno_cyst_AF/data.yaml ^
--model yolov8s.pt ^
--epochs 100 ^
--batch 16 ^
--name kidney_det_exp1
Вариант B: Сегментация (полигоны)
# Шаг 1: Создать сплит для сегментации
python scripts/ttv_freq2.py --task segment ^
--images-dir data/1_2236040_zno_cyst_AF/images ^
--labels-dir data/1_2236040_zno_cyst_AF/images_labels/polygons ^
--output-dir data/1_2236040_zno_cyst_AF
# Шаг 2: Запустить обучение
python scripts/train_yolo_seg.py ^
--data data/1_2236040_zno_cyst_AF/data.yaml ^
--model yolov8s-seg.pt ^
--epochs 100 ^
--batch 16 ^
--name kidney_seg_exp1
Вариант C: Обе задачи сразу (общий сплит)
python scripts/ttv_freq2.py --task both ^
--images-dir data/1_2236040_zno_cyst_AF/images ^
--labels-dir data/1_2236040_zno_cyst_AF/images_labels ^
--polygons-dir data/1_2236040_zno_cyst_AF/images_labels/polygons ^
--output-dir data/1_2236040_zno_cyst_AF
📜 Описание скриптов
scripts/ttv_freq2.py — Стратифицированный сплиттер
Ключевая особенность: разбивает датасет, начиная с самых редких классов. Это гарантирует присутствие каждого класса в train/val/test наборах, что критично для медицинских данных с несбалансированными классами.
Возможности:
- Автоматический поиск
predefined_classes.txtв папке эксперимента - Автоматическая перенумерация 1-based → 0-based для YOLOv8
- Поддержка детекции, сегментации или обеих задач одновременно
- Стратифицированное разбиение по частоте классов
- Автоматическая генерация
data.yamlс абсолютными путями - Создание изолированной папки
labels/(полное копирование) - Автоматическая очистка старых
.cacheфайлов
Параметры:
| Параметр | Описание | По умолчанию |
|---|---|---|
--task |
detect / segment / both | обязательный |
--images-dir |
Папка с изображениями | обязательный |
--labels-dir |
Папка с bbox или полигонами | обязательный |
--polygons-dir |
Папка с полигонами (both) | - |
--output-dir |
Папка для результатов | обязательный |
--predefined-classes |
Путь к файлу классов | <output-dir>/predefined_classes.txt |
--train-ratio |
Доля обучающей выборки | 0.8 |
--val-ratio |
Доля валидационной выборки | 0.1 |
--seed |
Seed для воспроизводимости | 42 |
scripts/train_yolo.py — Обучение детекции (bounding boxes)
Параметры:
| Параметр | Описание | По умолчанию |
|---|---|---|
--data |
Путь к data.yaml |
обязательный |
--model |
Предобученная модель | yolov8s.pt |
--epochs |
Количество эпох | 100 |
--batch |
Batch size | 16 |
--imgsz |
Размер изображения | 512 |
--device |
Устройство (0, cpu) | 0 |
--workers |
DataLoader workers | 0 |
--project |
Директория проектов | runs/detect |
--name |
Имя эксперимента | experiment |
scripts/train_yolo_seg.py — Обучение сегментации (полигоны/маски)
Параметры (аналогичны train_yolo.py, но со спецификой сегментации):
| Параметр | Описание | По умолчанию |
|---|---|---|
--data |
Путь к data.yaml |
обязательный |
--model |
Предобученная модель | yolov8s-seg.pt |
--epochs |
Количество эпох | 100 |
--batch |
Batch size | 16 |
--imgsz |
Размер изображения | 512 |
--device |
Устройство (0, cpu) | 0 |
--workers |
DataLoader workers | 0 |
--project |
Директория проектов | runs/segment |
--name |
Имя эксперимента | seg_experiment |
scripts/nrrd_to_yolo.py — Конвертация NRRD → YOLO (Тема 2.2)
Конвертирует 3D NRRD файлы в 2D срезы формата YOLO с сохранением структуры папок.
Использование:
python scripts/Тема\ 2.2/nrrd_to_yolo.py
Скрипты темы 2.1 (scripts/Тема 2.1/)
analysis.py— Анализ данных и визуализацияconfig_3d.py— Конфигурация для 3D обработкиfeature_3d.py— Извлечение признаков из 3D данныхsegmentation.py— Сегментация 3D данных
📁 Структура результатов обучения
После обучения YOLOv8 генерирует отчёты в: runs/{detect|segment}/{name}/
runs/segment/kidney_seg_exp1/
│
├── weights/
│ ├── best.pt # Лучшая модель (для инференса)
│ └── last.pt # Модель после последней эпохи
│
├── results.png # Графики loss и метрик по эпохам
├── confusion_matrix.png # Матрица ошибок
├── confusion_matrix_normalized.png
├── F1_curve.png # F1-score по confidence
├── PR_curve.png # Precision-Recall кривая
├── P_curve.png # Precision по confidence
├── R_curve.png # Recall по confidence
├── results.csv # Числовые метрики по эпохам
└── args.yaml # Сохранённые параметры обучения
🔮 Инференс (применение обученной модели)
Пример Python-кода:
from ultralytics import YOLO
# Загрузка обученной модели
model = YOLO('runs/segment/kidney_seg_exp1/weights/best.pt')
# Предсказание на новых изображениях
results = model.predict(
source='data/1_2236040_zno_cyst_AF/images/slice_0573.png',
conf=0.25, # Порог уверенности
iou=0.45, # Порог IoU для NMS
save=True, # Сохранить результат
project='predictions',
name='inference_test'
)
# Анализ результатов
for r in results:
print(f"Обнаружено объектов: {len(r.boxes)}")
for box in r.boxes:
cls_id = int(box.cls[0])
cls_name = model.names[cls_id]
conf = float(box.conf[0])
print(f" - {cls_name}: {conf:.2f}")
🆕 Создание нового эксперимента
1. Создание структуры вручную
mkdir -p data/new_experiment/{images,images_labels/polygons,images_result}
Или используйте шаблон из папки data/example/.
2. Создание схемы классов
notepad data\new_experiment\predefined_classes.txt
Запишите классы (по одному на строку):
organ
tissue_type_1
tissue_type_2
lesion
3. Помещение данных
Скопируйте изображения в:
data/new_experiment/images/
Скопируйте разметку в:
data/new_experiment/images_labels/(для детекции)data/new_experiment/images_labels/polygons/(для сегментации)
4. Запуск обучения
python scripts/ttv_freq2.py --task segment ^
--images-dir data/new_experiment/images ^
--labels-dir data/new_experiment/images_labels/polygons ^
--output-dir data/new_experiment
python scripts/train_yolo_seg.py ^
--data data/new_experiment/data.yaml ^
--epochs 100 ^
--name new_experiment_seg
⚠️ Особенности Windows
-
Многопоточность DataLoader: Используйте
--workers 0при ошибках доступа к файлам. На Linux/macOS можно ставить--workers 8для ускорения. -
Пути: В
data.yamlи.txt-файлах используются абсолютные пути с прямыми слэшами (/) для совместимости с YOLOv8. -
Кодировка: Все файлы обрабатываются в UTF-8, кириллица в именах классов поддерживается.
-
Пути с пробелами: Имена файлов с пробелами могут вызывать проблемы. Рекомендуется переименовывать файлы, убирая пробелы.
📚 Образовательные материалы
Лекции (lectures/)
К26_1_1.pdf— Введение в обработку медицинских изображенийК26_2_1.pdf— Архитектуры нейронных сетей для медицинской визуализацииК26_2_2.pdf— Применение YOLO в медицинской диагностике
Семинары (seminars/)
Тема 1.1/— Работа с датасетами, шумоподавление, сегментацияТема 1.2/— Практикум по обучению моделейТема 2.1/— Радиомика и 3D-сегментацияТема 2.2/— Конвертация NRRD в YOLO формат
Лабораторные работы (labs/)
- Пошаговые инструкции по темам курса
- Включают теоретический материал и практические задания
🛠️ Известные проблемы и решения
Проблема: "Label class X exceeds dataset class count N"
Решение: Скрипт ttv_freq2.py автоматически перенумеровывает классы из 1-based (Label Studio) в 0-based (YOLOv8).
Проблема: "Image Not Found" ошибки
Решение: Использовать --workers 0, проверить наличие изображений, пересоздать сплит. Убедиться, что пути в data.yaml корректны.
Проблема: Редкие классы показывают Recall=0
Решение: Увеличить число эпох (100-300), использовать imgsz=640, стратифицированный сплит гарантирует минимум 1 пример в train для каждого класса.
Проблема: Не удаётся прочитать NRRD файлы
Решение: Убедитесь, что установлены зависимости: pip install nrrd pydicom scipy
Проблема: Ошибки с путями в Windows (пробелы в именах)
Решение: Переименуйте файлы, убрав пробелы. Например: "501 arterial ax 1mm iDose (5).nrrd" → "501_arterial_ax_1mm_iDose_5.nrrd"
📝 Changelog
2026-08-19 (текущая версия)
- ✅ Поддержка двух экспериментов:
1_2236040_zno_cyst_AFиprep - ✅ Реальная структура данных: DICOM (1042 среза), PNG (300 срезов)
- ✅ Разметка в формате YOLO для 300 изображений
- ✅ Образовательные материалы: лекции (3 PDF), семинары (Jupyter ноутбуки)
- ✅ Скрипты для работы с 3D данными (Тема 2.1 и 2.2)
- ✅ Виртуальное окружение с полным набором зависимостей
- ✅
predefined_classes.txtдля каждого эксперимента - ✅ Стратифицированный сплиттер
ttv_freq2.py - ✅ Скрипты обучения детекции и сегментации
Структура данных
- DICOM файлы: 1042 среза (slice_0000.dcm — slice_1041.dcm)
- PNG изображения: 300 срезов (slice_0573.png — slice_0872.png)
- Разметка: 300 файлов
.txtв формате YOLO - Классы: 12 классов (почки, сегменты, опухоли, кисты, абсцесс)
📄 Лицензия
Образовательный проект. Медицинские данные используются в исследовательских и учебных целях.