Разработка AI для анализа рентгеновских снимков

Проектируем и внедряем системы искусственного интеллекта: от прототипа до production-ready решения. Наша команда объединяет экспертизу в машинном обучении, дата-инжиниринге и MLOps, чтобы AI работал не в лаборатории, а в реальном бизнесе.
Показано 1 из 1Все 1566 услуг
Разработка AI для анализа рентгеновских снимков
Сложный
~2-4 недели
Часто задаваемые вопросы

Направления AI-разработки

Этапы разработки AI-решения

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1284
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1196
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    901
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1119
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    586
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    853

Разработка AI для анализа рентгеновских снимков

Рентгеновские снимки — наиболее массовый тип медицинской визуализации. Ежегодно в мире делается более 3 миллиардов рентгеновских исследований. AI-анализ решает задачи: выявление патологий на рентгенограммах органов грудной клетки (пневмония, узлы, отёк), анализ костей (переломы, изменения при остеопорозе), стоматологический рентген (кариес, периодонтит, патологии корней).

Анализ рентгена грудной клетки (CXR)

CheXNet (2017) стал поворотным моментом: DenseNet-121, обученный на 112,120 снимках CheXpert, превзошёл среднего радиолога по ряду патологий.

import torch
import torch.nn as nn
import torchvision.models as models
from torchvision import transforms
from PIL import Image
import numpy as np

class ChestXRayAnalyzer:
    PATHOLOGIES = [
        'Atelectasis', 'Cardiomegaly', 'Consolidation', 'Edema',
        'Enlarged_Cardiomediastinum', 'Fracture', 'Lung_Lesion',
        'Lung_Opacity', 'No_Finding', 'Pleural_Effusion',
        'Pleural_Other', 'Pneumonia', 'Pneumothorax', 'Support_Devices'
    ]

    def __init__(self, model_path: str, threshold: float = 0.5):
        # DenseNet-121 как base
        self.model = models.densenet121(pretrained=False)
        self.model.classifier = nn.Sequential(
            nn.Linear(self.model.classifier.in_features,
                       len(self.PATHOLOGIES)),
            # НЕ sigmoid — используем BCEWithLogitsLoss при обучении
        )
        self.model.load_state_dict(torch.load(model_path))
        self.model.eval()
        self.threshold = threshold

        self.transform = transforms.Compose([
            transforms.Resize((320, 320)),
            transforms.Grayscale(3),  # CXR → 3 канала для ImageNet pretrained
            transforms.ToTensor(),
            transforms.Normalize([0.485, 0.456, 0.406],
                                  [0.229, 0.224, 0.225])
        ])

    @torch.no_grad()
    def analyze(self, dicom_path: str) -> dict:
        import pydicom
        dcm = pydicom.dcmread(dicom_path)
        pixel_array = dcm.pixel_array

        # Нормализация pixel values
        if dcm.PhotometricInterpretation == 'MONOCHROME1':
            pixel_array = pixel_array.max() - pixel_array

        pixel_norm = ((pixel_array - pixel_array.min()) /
                      (pixel_array.max() - pixel_array.min()) * 255).astype(np.uint8)
        image = Image.fromarray(pixel_norm)

        tensor = self.transform(image).unsqueeze(0)
        logits = self.model(tensor)
        probs = torch.sigmoid(logits).squeeze().numpy()

        pathology_scores = {
            path: float(prob)
            for path, prob in zip(self.PATHOLOGIES, probs)
        }

        detected = {k: v for k, v in pathology_scores.items()
                    if v > self.threshold}

        return {
            'all_scores': pathology_scores,
            'detected_pathologies': detected,
            'normal': pathology_scores.get('No_Finding', 0) > self.threshold,
            'critical_findings': self._check_critical(pathology_scores)
        }

    def _check_critical(self, scores: dict) -> list:
        critical_threshold = 0.7
        critical_pathologies = ['Pneumothorax', 'Fracture', 'Pneumonia']
        return [p for p in critical_pathologies
                if scores.get(p, 0) > critical_threshold]

Grad-CAM визуализация

Объяснение «почему модель так решила» критично для доверия врача:

from pytorch_grad_cam import GradCAM
from pytorch_grad_cam.utils.image import show_cam_on_image

class XRayExplainer:
    def __init__(self, model: nn.Module):
        target_layers = [model.features.denseblock4.denselayer16.conv2]
        self.cam = GradCAM(model=model, target_layers=target_layers)

    def explain(self, input_tensor: torch.Tensor,
                target_class: int) -> np.ndarray:
        grayscale_cam = self.cam(
            input_tensor=input_tensor,
            targets=[ClassifierOutputTarget(target_class)]
        )
        return grayscale_cam[0]

Публичные датасеты

Датасет Снимков Патологии Источник
CheXpert 224k 14 классов Stanford
NIH ChestXray14 112k 14 классов NIH
MIMIC-CXR 227k 14 классов MIT
PadChest 160k 174 радиологических наблюдения Испания
VinBigData Chest XR 18k с bbox 14 патологий Вьетнам

Ограничения и регуляторика

Разработанная система выступает как Computer-Aided Detection (CAD) — инструмент поддержки принятия решений, не замена диагноза. Радиолог принимает окончательное решение. В России применение медицинских AI-систем регулируется Росздравнадзором, требуется регистрация как медицинское изделие для клинического применения.

Задача Срок
Классификатор 14 патологий (CXR) 8–12 недель
Детекция патологий с bbox 10–16 недель
Валидация + подготовка к регистрации 20–40 недель