Розробка 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 недель