AI for X-Ray Image Analysis

We design and deploy artificial intelligence systems: from prototype to production-ready solutions. Our team combines expertise in machine learning, data engineering and MLOps to make AI work not in the lab, but in real business.
Showing 1 of 1 servicesAll 1566 services
AI for X-Ray Image Analysis
Complex
~2-4 weeks
FAQ
AI Development Areas
AI Solution Development Stages
Latest works
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823
  • image_logo-aider_0.jpg
    AIDER company logo development
    762
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    848

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