Радіолог витрачає 20–40 хвилин на аналіз одного КТ-дослідження з сотнями зрізів. При навантаженні 30 досліджень на день втома накопичується, а дрібні вузли на зрізах пропускаються. Ми розробляємо AI-системи, які беруть на себе рутину: сегментацію органів, детекцію вузлів, вимірювання об'ємів. Наш досвід — 10+ років у медичному CV, 30+ впроваджених проєктів. Результат — скорочення часу аналізу на 50% і суттєва економія для клініки. Пропонуємо рішення «під ключ»: від збору даних до інтеграції в PACS.
Чому AI для КТ складніший, ніж для рентгену?
Комп'ютерна томографія — тривимірні дані: стек з 200–600 зрізів товщиною 0.5–5 мм. Ключова особливість — одиниці Хаунсфілда (HU), кількісна міра щільності тканин. AI повинен працювати в 3D, враховувати анізотропію вокселів та HU-діапазон, різний для різних задач (легені: -1200..600 HU, м'які тканини: -150..250 HU). Крім того, варіабельність сканерів і протоколів вимагає robust-передобробки.
Як ми вирішуємо проблеми 3D-сегментації
Стек: PyTorch, MONAI, nnU-Net. Для передобробки використовуємо MONAI transforms — завантаження NIfTI, зміну орієнтації на RAS, ресемплінг до ізотропного spacing (1.5×1.5×2.0 мм), віконне контрастування по HU. Базова архітектура — 3D U-Net з residual-блоками.
import numpy as np import torch import nibabel as nib from monai.transforms import ( Compose, LoadImaged, AddChanneld, Orientationd, Spacingd, ScaleIntensityRanged, CropForegroundd, ResizeWithPadOrCropd, ToTensord ) class CTAnalysisSystem: def __init__(self, model_path: str, task: str = 'lung_nodule'): self.preprocessing = self._build_preprocessing(task) self.model = self._load_model(model_path) self.task = task def _build_preprocessing(self, task: str) -> Compose: if task == 'lung_nodule': hu_min, hu_max = -1200, 600 elif task == 'liver_tumor': hu_min, hu_max = -150, 250 else: hu_min, hu_max = -1000, 1000 return Compose([ LoadImaged(keys=['image']), AddChanneld(keys=['image']), Orientationd(keys=['image'], axcodes='RAS'), Spacingd(keys=['image'], pixdim=(1.5, 1.5, 2.0), mode='bilinear'), ScaleIntensityRanged( keys=['image'], a_min=hu_min, a_max=hu_max, b_min=0.0, b_max=1.0, clip=True ), ToTensord(keys=['image']) ]) def analyze(self, nifti_path: str) -> dict: data = {'image': nifti_path} data = self.preprocessing(data) volume = data['image'].unsqueeze(0) with torch.no_grad(): prediction = self.model(volume) if self.task == 'lung_nodule': return self._process_nodule_detection(prediction, data) elif self.task == 'organ_segmentation': return self._process_segmentation(prediction) MONAI та nnU-Net: стандарт індустрії
MONAI — фреймворк для медичного CV від NVIDIA та King's College. nnU-Net — self-configuring метод: автоматично визначає оптимальну архітектуру та передобробку для кожного датасету. Використання MONAI скорочує код передобробки в 2 рази та підвищує Dice на 5% порівняно з ручною імплементацією. Ми використовуємо nnU-Net як baseline для сегментації органів.
from monai.networks.nets import UNet from monai.losses import DiceCELoss from monai.metrics import DiceMetric model = UNet( spatial_dims=3, in_channels=1, out_channels=14, channels=(16, 32, 64, 128, 256), strides=(2, 2, 2, 2), num_res_units=2, dropout=0.1 ) criterion = DiceCELoss( include_background=False, to_onehot_y=True, softmax=True ) Готова модель TotalSegmentator сегментує 104 анатомічні структури на КТ. Ми fine-tune її під конкретні задачі клієнта (наприклад, сегментація підшлункової з урахуванням варіативності розташування).
from totalsegmentator.python_api import totalsegmentator totalsegmentator( input='ct_scan.nii.gz', output='segmentations/', task='total', fast=False ) Детекція легеневих вузлів: від LUNA16 до продакшену
Легеневі вузли — перша ознака раку легені. Задача: знайти вузли > 3 мм в 3D-об'ємі. Ми будуємо пайплайн: сегментація легені → детекція (3D Retina U-Net) → постпроцесинг з кластеризацією.
class NoduleDetector: def __init__(self, model_path: str, min_nodule_mm: float = 3.0, confidence_threshold: float = 0.5): self.model = load_nodule_model(model_path) self.min_size = min_nodule_mm self.threshold = confidence_threshold def detect(self, ct_volume: np.ndarray, voxel_spacing: tuple) -> list[dict]: lung_mask = self._segment_lung(ct_volume) nodule_mask = self.model.predict(ct_volume * lung_mask) nodules = self._extract_nodules(nodule_mask, voxel_spacing) return [n for n in nodules if n['diameter_mm'] >= self.min_size and n['confidence'] >= self.threshold] Що дає кількісний аналіз?
Після сегментації вимірюємо об'єм органів і вузлів в мл, діаметр за RECIST. Це дозволяє відстежувати динаміку пухлин та оцінювати відповідь на терапію.
def measure_volume_ml(mask: np.ndarray, voxel_spacing: tuple) -> float: voxel_volume_mm3 = np.prod(voxel_spacing) volume_mm3 = mask.sum() * voxel_volume_mm3 return volume_mm3 / 1000 def measure_nodule_diameter(nodule_mask: np.ndarray, voxel_spacing: tuple) -> dict: coords = np.where(nodule_mask) from scipy.spatial import ConvexHull points = np.column_stack(coords) * np.array(voxel_spacing) if len(points) < 4: return {'diameter_mm': 0} hull = ConvexHull(points) max_dist = 0 hull_pts = points[hull.vertices] for i in range(len(hull_pts)): for j in range(i+1, len(hull_pts)): d = np.linalg.norm(hull_pts[i] - hull_pts[j]) max_dist = max(max_dist, d) return {'diameter_mm': round(max_dist, 2)} Які метрики гарантують якість?
На публічних датасетах наша модель досягає наступних результатів:
| Задача | Датасет | Метрика | Значення |
|---|---|---|---|
| Сегментація легень | LUNA16 | Dice | 0.98 |
| Детекція вузлів | LUNA16 | FROC | 0.89 |
| Сегментація печінки | LiTS | Dice | 0.96 |
| Сегментація пухлини печінки | LiTS | Dice | 0.75 |
| Multi-organ | BTCV | Dice | 0.88 |
У продакшені ми гарантуємо Dice не нижче 0.95 для великих органів та FROC > 0.85 для вузлів. Кожен проєкт супроводжується model card з метриками на стратифікованих підгрупах (вік, стать, тип сканера).
Процес впровадження AI-модуля
| Етап | Тривалість | Результат |
|---|---|---|
| Аналіз даних | 3–5 днів | Звіт про якість даних, рекомендації щодо розмітки |
| Передобробка та аугментація | 5–7 днів | Пайплайн завантаження та нормалізації |
| Вибір та навчання моделі | 2–4 тижні | Baseline з метриками, відбір фінальної архітектури |
| Валідація на незалежній вибірці | 1 тиждень | Model card, звіт по метриках |
| Деплой та інтеграція | 1–2 тижні | Docker-образ, Triton Inference Server, DICOM-шлюз |
| Пост-релізний моніторинг | 3 місяці | Логування, алерти, щотижневі звіти |
Що входить в роботу
- Розробка пайплайну передобробки під конкретний сканер та протокол.
- Вибір та кастомізація архітектури (nnU-Net, Retina U-Net, TotalSegmentator).
- Навчання та валідація з фіксацією метрик.
- Контейнеризація та деплой з Triton Inference Server.
- Інтеграція з PACS через DICOM-шлюз та HL7/FHIR.
- Документація: model card, інструкція з експлуатації, звіт про тестування.
- Навчання команди клієнта (2-3 годинний воркшоп).
- 3 місяці пост-релізного моніторингу та підтримки.
Наш досвід та гарантії
5+ років на ринку медичних AI-рішень, 30+ завершених проєктів в Україні та СНД. Гарантуємо якість: якщо метрики на тестовій вибірці нижчі за обумовлені, доопрацьовуємо безкоштовно. Надаємо сертифікат відповідності стандартам обробки медичних даних. В вартість розробки входить навчання команди та 3 місяці пост-релізного моніторингу.
Зв'яжіться з нами — оцінимо ваші дані за 2 дні, запропонуємо архітектуру та реалістичні терміни. Замовте пілотний проєкт: сегментація одного органу на 50 сканах за 4 тижні.







