Разработка AI для анализа снимков глазного дна (Retinal Imaging)
Снимки глазного дна (fundus photography) — неинвазивный метод визуализации сетчатки. По состоянию сетчатки можно диагностировать: диабетическую ретинопатию (DR), глаукому, AMD (возрастную макулярную дегенерацию), гипертензивную ретинопатию. AI-анализ особенно ценен для массового скрининга в условиях дефицита офтальмологов.
Диабетическая ретинопатия: грейдирование
DR — ведущая причина слепоты у людей трудоспособного возраста. Грейдирование по шкале ICDR (0-4):
import torch
import timm
import torch.nn as nn
from torchvision import transforms
class DRGrader:
DR_GRADES = {
0: 'No DR',
1: 'Mild NPDR',
2: 'Moderate NPDR',
3: 'Severe NPDR',
4: 'Proliferative DR'
}
def __init__(self, model_path: str):
# EfficientNet-B5 показывает лучший результат на Kaggle DR dataset
backbone = timm.create_model('efficientnet_b5', pretrained=False)
backbone.classifier = nn.Sequential(
nn.Dropout(0.4),
nn.Linear(backbone.classifier.in_features, 5)
)
backbone.load_state_dict(torch.load(model_path))
backbone.eval()
self.model = backbone
self.transform = transforms.Compose([
transforms.Resize((456, 456)),
transforms.CenterCrop(400),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406],
[0.229, 0.224, 0.225])
])
@torch.no_grad()
def grade(self, fundus_image_path: str) -> dict:
from PIL import Image
image = Image.open(fundus_image_path).convert('RGB')
# Предобработка: CLAHE для улучшения контраста сосудов
image = self._enhance_fundus(image)
tensor = self.transform(image).unsqueeze(0)
logits = self.model(tensor)
probs = torch.softmax(logits, dim=1).squeeze().numpy()
grade = int(probs.argmax())
return {
'grade': grade,
'grade_label': self.DR_GRADES[grade],
'probabilities': {self.DR_GRADES[i]: float(probs[i]) for i in range(5)},
'referable': grade >= 2, # направить к офтальмологу
'vision_threatening': grade >= 3
}
def _enhance_fundus(self, image) -> 'PIL.Image':
"""CLAHE улучшение для сетчатки"""
import cv2
import numpy as np
img_array = np.array(image)
# Применяем CLAHE к L-каналу в LAB
lab = cv2.cvtColor(img_array, cv2.COLOR_RGB2LAB)
l, a, b = cv2.split(lab)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
l_enhanced = clahe.apply(l)
enhanced = cv2.cvtColor(cv2.merge([l_enhanced, a, b]), cv2.COLOR_LAB2RGB)
return Image.fromarray(enhanced)
Сегментация сосудов сетчатки
Сегментация сосудов важна для ранней диагностики изменений микроциркуляции:
import segmentation_models_pytorch as smp
# U-Net с SE-ResNeXt энкодером для сегментации сосудов
vessel_segmenter = smp.UnetPlusPlus(
encoder_name='se_resnext50_32x4d',
encoder_weights='imagenet',
in_channels=3,
classes=1, # бинарная маска сосудов
activation='sigmoid'
)
Метрика: AUC 0.9887 на DRIVE датасете (U-Net++, дообученный специфично).
Детекция диска зрительного нерва и макулы
from ultralytics import YOLO
class RetinalStructureDetector:
def __init__(self, model_path: str):
self.detector = YOLO(model_path)
self.structures = ['optic_disc', 'macula', 'fovea']
def detect(self, fundus_image: np.ndarray) -> dict:
results = self.detector(fundus_image, conf=0.5)
detected = {}
for box in results[0].boxes:
structure = self.structures[int(box.cls)]
x1, y1, x2, y2 = map(int, box.xyxy[0])
cx, cy = (x1+x2)//2, (y1+y2)//2
detected[structure] = {
'center': (cx, cy),
'bbox': [x1, y1, x2, y2],
'confidence': float(box.conf)
}
# C/D ratio (cup-to-disc ratio) для глаукомы
if 'optic_disc' in detected:
detected['cdr'] = self._calculate_cdr(fundus_image,
detected['optic_disc'])
return detected
Скрининговые системы
AI-решение для массового скрининга ДР:
- Mобильный сканер + AI → результат в 1 минуту
- Без офтальмолога в контуре на первом этапе
- Направление только тех, у кого grade ≥ 2 (referable DR)
- 30–40% снижение нагрузки на офтальмологов
Примеры внедрений: IDx-DR (FDA-clearance), EyeArt (1,200+ клиник в США).
Публичные датасеты
| Датасет | Задача | Изображений |
|---|---|---|
| Kaggle DR (EyePACS) | Грейдирование DR | 88,702 |
| DRIVE | Сегментация сосудов | 40 |
| STARE | Сосуды + патологии | 397 |
| RIM-ONE | Глаукома | 455 |
| MESSIDOR-2 | DR грейдирование | 1748 |
| Задача | AUC/Метрика | Срок |
|---|---|---|
| DR grading EfficientNet-B5 | AUC 0.96 | 6–10 недель |
| Сегментация сосудов | AUC 0.99 | 6–8 недель |
| Полная ретинальная система | — | 14–22 недели |







