Практические примеры интеграции API рентгеновских детекторов

Интеграция рентгеновских детекторов в существующие системы требует глубокого понимания API и практических навыков программирования. В этой статье мы рассмотрим реальные примеры интеграции детекторов XRayDetect в различные типы приложений с использованием популярных языков программирования.

Все примеры основаны на реальных проектах и могут быть использованы как отправная точка для ваших собственных разработок.

Обзор API XRayDetect

API XRayDetect предоставляет полный набор функций для управления детекторами, захвата данных и обработки изображений. Основные компоненты:

Управление устройством

  • Инициализация и подключение
  • Настройка параметров
  • Калибровка детектора
  • Мониторинг состояния

Захват данных

  • Одиночные снимки
  • Непрерывный захват
  • Синхронизация
  • Буферизация данных

Обработка изображений

  • Коррекция дефектных пикселей
  • Калибровка плоского поля
  • Фильтрация шума
  • Улучшение контраста

Архитектура SDK

SDK XRayDetect построен по модульному принципу, обеспечивая гибкость интеграции и простоту использования:

Уровень приложения

Ваше приложение использует высокоуровневые функции API для управления детекторами

API слой

Унифицированный интерфейс для всех типов детекторов с поддержкой C++, C#, Python

Драйвер устройства

Низкоуровневое взаимодействие с аппаратурой через USB/Ethernet

Аппаратный уровень

Детекторы XSe-64-1.5, XDe-64-1.5 и системы захвата XCB

Интеграция на C++

C++ API обеспечивает максимальную производительность и подходит для высокоскоростных приложений реального времени.

Базовая инициализация детектора

#include "XRayDetectorAPI.h"

int main() {
    // Инициализация библиотеки
    XRayAPI::Initialize();
    
    // Поиск доступных детекторов
    std::vector<XRayAPI::DetectorInfo> detectors;
    XRayAPI::EnumerateDetectors(detectors);
    
    if (detectors.empty()) {
        std::cout << "Детекторы не найдены" << std::endl;
        return -1;
    }
    
    // Подключение к первому детектору
    XRayAPI::Detector detector;
    if (detector.Connect(detectors[0].id) != XRayAPI::SUCCESS) {
        std::cout << "Ошибка подключения" << std::endl;
        return -1;
    }
    
    std::cout << "Детектор подключен: " << detectors[0].name << std::endl;
    
    // Настройка параметров
    detector.SetIntegrationTime(1000); // 1 мс
    detector.SetGain(1.0f);
    
    // Калибровка
    detector.Calibrate();
    
    return 0;
}

Захват изображений

// Одиночный снимок
XRayAPI::Image image;
if (detector.CaptureImage(image) == XRayAPI::SUCCESS) {
    // Обработка изображения
    ProcessImage(image);
    
    // Сохранение в файл
    image.SaveToFile("capture.tiff");
}

// Непрерывный захват
class ImageCallback : public XRayAPI::IImageCallback {
public:
    void OnImageReceived(const XRayAPI::Image& image) override {
        // Обработка каждого кадра
        ProcessFrame(image);
        
        // Проверка качества
        if (image.GetQuality() < 0.8f) {
            std::cout << "Предупреждение: низкое качество изображения" << std::endl;
        }
    }
    
    void OnError(XRayAPI::ErrorCode error) override {
        std::cout << "Ошибка захвата: " << error << std::endl;
    }
};

ImageCallback callback;
detector.StartContinuousCapture(&callback);

// Захват в течение 10 секунд
std::this_thread::sleep_for(std::chrono::seconds(10));

detector.StopContinuousCapture();

Интеграция на Python

Python API идеально подходит для быстрого прототипирования, научных исследований и интеграции с библиотеками машинного обучения.

Простой пример захвата

import xraydetector as xrd
import numpy as np
import matplotlib.pyplot as plt

# Инициализация
xrd.initialize()

# Поиск детекторов
detectors = xrd.enumerate_detectors()
if not detectors:
    print("Детекторы не найдены")
    exit(1)

# Подключение
detector = xrd.Detector()
detector.connect(detectors[0]['id'])

print(f"Подключен детектор: {detectors[0]['name']}")

# Настройка
detector.set_integration_time(1000)  # 1 мс
detector.set_gain(1.0)

# Калибровка
detector.calibrate()

# Захват изображения
image = detector.capture_image()

# Конвертация в numpy array
data = np.array(image.get_data())

# Отображение
plt.figure(figsize=(10, 8))
plt.imshow(data, cmap='gray')
plt.title('Рентгеновское изображение')
plt.colorbar()
plt.show()

# Сохранение
image.save_to_file('capture.tiff')

detector.disconnect()

Обработка с использованием OpenCV

import xraydetector as xrd
import cv2
import numpy as np

def process_xray_image(detector):
    # Захват изображения
    image = detector.capture_image()
    data = np.array(image.get_data(), dtype=np.uint16)
    
    # Нормализация к 8-бит
    normalized = cv2.normalize(data, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U)
    
    # Улучшение контраста
    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
    enhanced = clahe.apply(normalized)
    
    # Фильтрация шума
    denoised = cv2.bilateralFilter(enhanced, 9, 75, 75)
    
    # Обнаружение краев
    edges = cv2.Canny(denoised, 50, 150)
    
    return {
        'original': normalized,
        'enhanced': enhanced,
        'denoised': denoised,
        'edges': edges
    }

# Использование
detector = xrd.Detector()
detector.connect(detectors[0]['id'])

results = process_xray_image(detector)

# Отображение результатов
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
axes[0,0].imshow(results['original'], cmap='gray')
axes[0,0].set_title('Оригинал')
axes[0,1].imshow(results['enhanced'], cmap='gray')
axes[0,1].set_title('Улучшенный контраст')
axes[1,0].imshow(results['denoised'], cmap='gray')
axes[1,0].set_title('Подавление шума')
axes[1,1].imshow(results['edges'], cmap='gray')
axes[1,1].set_title('Обнаружение краев')

plt.tight_layout()
plt.show()

Интеграция на C#

C# API обеспечивает удобную интеграцию с .NET приложениями и WPF интерфейсами.

WPF приложение для просмотра изображений

using System;
using System.Windows;
using System.Windows.Media.Imaging;
using XRayDetector.NET;

namespace XRayViewer
{
    public partial class MainWindow : Window
    {
        private Detector detector;
        private bool isCapturing = false;
        
        public MainWindow()
        {
            InitializeComponent();
            InitializeDetector();
        }
        
        private async void InitializeDetector()
        {
            try
            {
                // Инициализация API
                XRayAPI.Initialize();
                
                // Поиск детекторов
                var detectors = await XRayAPI.EnumerateDetectorsAsync();
                if (detectors.Count == 0)
                {
                    MessageBox.Show("Детекторы не найдены");
                    return;
                }
                
                // Подключение
                detector = new Detector();
                await detector.ConnectAsync(detectors[0].Id);
                
                StatusLabel.Content = $"Подключен: {detectors[0].Name}";
                
                // Настройка
                detector.IntegrationTime = 1000; // 1 мс
                detector.Gain = 1.0f;
                
                // Калибровка
                await detector.CalibrateAsync();
                
                CaptureButton.IsEnabled = true;
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Ошибка инициализации: {ex.Message}");
            }
        }
        
        private async void CaptureButton_Click(object sender, RoutedEventArgs e)
        {
            if (!isCapturing)
            {
                // Начать захват
                isCapturing = true;
                CaptureButton.Content = "Остановить";
                
                detector.ImageReceived += OnImageReceived;
                await detector.StartContinuousCaptureAsync();
            }
            else
            {
                // Остановить захват
                isCapturing = false;
                CaptureButton.Content = "Захват";
                
                await detector.StopContinuousCaptureAsync();
                detector.ImageReceived -= OnImageReceived;
            }
        }
        
        private void OnImageReceived(object sender, ImageEventArgs e)
        {
            // Обновление UI в главном потоке
            Dispatcher.Invoke(() =>
            {
                // Конвертация в BitmapSource
                var bitmap = ConvertToBitmapSource(e.Image);
                ImageDisplay.Source = bitmap;
                
                // Обновление статистики
                UpdateImageStats(e.Image);
            });
        }
        
        private BitmapSource ConvertToBitmapSource(XRayImage image)
        {
            var width = image.Width;
            var height = image.Height;
            var data = image.GetData();
            
            // Нормализация данных
            var normalizedData = new byte[width * height];
            var min = data.Min();
            var max = data.Max();
            var range = max - min;
            
            for (int i = 0; i < data.Length; i++)
            {
                normalizedData[i] = (byte)((data[i] - min) * 255 / range);
            }
            
            return BitmapSource.Create(width, height, 96, 96, 
                PixelFormats.Gray8, null, normalizedData, width);
        }
        
        private void UpdateImageStats(XRayImage image)
        {
            var stats = image.GetStatistics();
            StatsPanel.Children.Clear();
            
            StatsPanel.Children.Add(new TextBlock { Text = $"Размер: {image.Width}x{image.Height}" });
            StatsPanel.Children.Add(new TextBlock { Text = $"Среднее: {stats.Mean:F1}" });
            StatsPanel.Children.Add(new TextBlock { Text = $"Мин/Макс: {stats.Min}/{stats.Max}" });
            StatsPanel.Children.Add(new TextBlock { Text = $"Качество: {stats.Quality:P1}" });
        }
    }
}
                        

Обработка ошибок и диагностика

Правильная обработка ошибок критически важна для стабильной работы системы:

Типы ошибок

  • Ошибки подключения: Детектор не найден или недоступен
  • Ошибки конфигурации: Неверные параметры
  • Ошибки захвата: Сбои при получении данных
  • Ошибки обработки: Проблемы с анализом изображений

Методы диагностики

  • Логирование: Детальные логи всех операций
  • Самодиагностика: Встроенные тесты детектора
  • Мониторинг: Контроль состояния в реальном времени
  • Уведомления: Автоматические оповещения о проблемах

Пример обработки ошибок в C++

class XRaySystem {
private:
    XRayAPI::Detector detector;
    std::unique_ptr<Logger> logger;
    
public:
    bool Initialize() {
        try {
            logger = std::make_unique<Logger>("xray_system.log");
            
            // Инициализация API
            auto result = XRayAPI::Initialize();
            if (result != XRayAPI::SUCCESS) {
                logger->Error("Ошибка инициализации API: {}", result);
                return false;
            }
            
            // Поиск детекторов
            std::vector<XRayAPI::DetectorInfo> detectors;
            result = XRayAPI::EnumerateDetectors(detectors);
            if (result != XRayAPI::SUCCESS || detectors.empty()) {
                logger->Error("Детекторы не найдены");
                return false;
            }
            
            // Подключение с повторными попытками
            for (int attempt = 0; attempt < 3; ++attempt) {
                result = detector.Connect(detectors[0].id);
                if (result == XRayAPI::SUCCESS) {
                    logger->Info("Детектор подключен: {}", detectors[0].name);
                    break;
                }
                
                logger->Warning("Попытка подключения {} неудачна", attempt + 1);
                std::this_thread::sleep_for(std::chrono::seconds(1));
            }
            
            if (result != XRayAPI::SUCCESS) {
                logger->Error("Не удалось подключиться к детектору");
                return false;
            }
            
            // Проверка состояния детектора
            if (!PerformSelfTest()) {
                logger->Error("Самодиагностика детектора не пройдена");
                return false;
            }
            
            return true;
        }
        catch (const std::exception& e) {
            logger->Error("Исключение при инициализации: {}", e.what());
            return false;
        }
    }
    
    bool PerformSelfTest() {
        // Проверка температуры
        float temperature = detector.GetTemperature();
        if (temperature < -10 || temperature > 60) {
            logger->Warning("Температура детектора вне нормы: {}°C", temperature);
        }
        
        // Проверка темнового тока
        auto darkCurrent = detector.MeasureDarkCurrent();
        if (darkCurrent > 100) { // пА
            logger->Warning("Высокий темновой ток: {} пА", darkCurrent);
        }
        
        // Проверка пикселей
        auto deadPixels = detector.GetDeadPixelCount();
        if (deadPixels > 5) {
            logger->Warning("Обнаружено {} дефектных пикселей", deadPixels);
        }
        
        logger->Info("Самодиагностика завершена успешно");
        return true;
    }
};

Оптимизация производительности

Управление памятью

  • Пулы буферов: Переиспользование буферов изображений
  • Потоковая обработка: Обработка данных по мере поступления
  • Сжатие: Использование сжатия для экономии памяти
  • Кэширование: Кэширование часто используемых данных

Многопоточность

  • Параллельная обработка: Использование всех ядер процессора
  • Асинхронные операции: Неблокирующие вызовы API
  • Конвейерная обработка: Параллельный захват и обработка
  • GPU ускорение: Использование CUDA/OpenCL

Высокопроизводительный захват

class HighPerformanceCapture {
private:
    XRayAPI::Detector detector;
    std::queue<XRayAPI::Image> imageQueue;
    std::mutex queueMutex;
    std::condition_variable queueCondition;
    std::atomic<bool> stopProcessing{false};
    
    // Пул буферов для переиспользования
    std::vector<std::unique_ptr<uint16_t[]>> bufferPool;
    std::queue<uint16_t*> availableBuffers;
    std::mutex bufferMutex;
    
public:
    void StartCapture() {
        // Инициализация пула буферов
        InitializeBufferPool();
        
        // Поток захвата
        std::thread captureThread([this]() {
            CaptureLoop();
        });
        
        // Потоки обработки
        std::vector<std::thread> processingThreads;
        for (int i = 0; i < std::thread::hardware_concurrency(); ++i) {
            processingThreads.emplace_back([this]() {
                ProcessingLoop();
            });
        }
        
        // Ожидание завершения
        captureThread.join();
        for (auto& thread : processingThreads) {
            thread.join();
        }
    }
    
private:
    void InitializeBufferPool() {
        const int bufferCount = 10;
        const int imageSize = 64 * 1024; // 64K пикселей
        
        for (int i = 0; i < bufferCount; ++i) {
            auto buffer = std::make_unique<uint16_t[]>(imageSize);
            availableBuffers.push(buffer.get());
            bufferPool.push_back(std::move(buffer));
        }
    }
    
    void CaptureLoop() {
        while (!stopProcessing) {
            // Получение буфера из пула
            uint16_t* buffer = nullptr;
            {
                std::lock_guard<std::mutex> lock(bufferMutex);
                if (!availableBuffers.empty()) {
                    buffer = availableBuffers.front();
                    availableBuffers.pop();
                }
            }
            
            if (buffer) {
                // Захват изображения в буфер
                XRayAPI::Image image;
                if (detector.CaptureImageToBuffer(buffer, image) == XRayAPI::SUCCESS) {
                    // Добавление в очередь обработки
                    {
                        std::lock_guard<std::mutex> lock(queueMutex);
                        imageQueue.push(std::move(image));
                    }
                    queueCondition.notify_one();
                } else {
                    // Возврат буфера в пул при ошибке
                    std::lock_guard<std::mutex> lock(bufferMutex);
                    availableBuffers.push(buffer);
                }
            } else {
                // Нет доступных буферов, небольшая пауза
                std::this_thread::sleep_for(std::chrono::microseconds(100));
            }
        }
    }
    
    void ProcessingLoop() {
        while (!stopProcessing) {
            XRayAPI::Image image;
            
            // Ожидание изображения
            {
                std::unique_lock<std::mutex> lock(queueMutex);
                queueCondition.wait(lock, [this] { 
                    return !imageQueue.empty() || stopProcessing; 
                });
                
                if (stopProcessing) break;
                
                image = std::move(imageQueue.front());
                imageQueue.pop();
            }
            
            // Обработка изображения
            ProcessImage(image);
            
            // Возврат буфера в пул
            {
                std::lock_guard<std::mutex> lock(bufferMutex);
                availableBuffers.push(image.GetBuffer());
            }
        }
    }
    
    void ProcessImage(const XRayAPI::Image& image) {
        // Быстрая обработка изображения
        auto stats = image.CalculateStatistics();
        
        // Проверка качества
        if (stats.quality < 0.8f) {
            // Логирование предупреждения
        }
        
        // Сохранение или передача данных
        SaveOrTransmitImage(image);
    }
};

Лучшие практики интеграции

Инициализация и подключение

  • Всегда проверяйте возвращаемые коды ошибок
  • Используйте таймауты для операций подключения
  • Реализуйте механизм повторных попыток
  • Выполняйте самодиагностику после подключения

Управление ресурсами

  • Освобождайте все захваченные ресурсы
  • Используйте RAII в C++ или using в C#
  • Корректно завершайте потоки захвата
  • Мониторьте использование памяти

Обработка ошибок

  • Предусматривайте все возможные сценарии сбоев
  • Ведите подробные логи операций
  • Реализуйте graceful degradation
  • Уведомляйте пользователя о проблемах

Производительность

  • Используйте многопоточность для обработки
  • Оптимизируйте алгоритмы обработки изображений
  • Применяйте кэширование где возможно
  • Профилируйте код для выявления узких мест

Примеры реальных проектов

Система досмотра багажа

Задача:

Создание высокоскоростной системы рентгеновского досмотра для аэропорта с пропускной способностью 1000 единиц багажа в час.

Решение:

  • Использование детекторов XDe-64-1.5 для двухэнергетического анализа
  • Система захвата XCB с 4 каналами
  • Алгоритмы машинного обучения для автоматического обнаружения угроз
  • Интеграция с системой управления аэропорта

Результаты:

  • Скорость обработки: 1200 единиц/час
  • Точность обнаружения угроз: 98.5%
  • Ложные срабатывания: менее 2%
  • Время окупаемости: 18 месяцев

Контроль качества в автопроме

Задача:

Автоматизированный контроль качества литых деталей двигателя на конвейере автомобильного завода.

Решение:

  • Роботизированная система с детекторами XSe-64-1.5
  • Компьютерная томография для сложных деталей
  • ИИ-алгоритмы для классификации дефектов
  • Интеграция с MES системой завода

Результаты:

  • Производительность: 120 деталей/час
  • Обнаружение дефектов: 99.2%
  • Снижение брака: на 85%
  • Экономия: $2.5M в год

Заключение

Интеграция рентгеновских детекторов XRayDetect в ваши системы может быть выполнена эффективно с использованием предоставленного API. Ключевые моменты для успешной интеграции:

  • Правильная инициализация: Всегда проверяйте возвращаемые коды ошибок
  • Управление ресурсами: Освобождайте все захваченные ресурсы
  • Обработка ошибок: Предусматривайте все возможные сценарии сбоев
  • Производительность: Используйте многопоточность и оптимизацию
  • Тестирование: Тщательно тестируйте все сценарии использования

Техническая поддержка разработчиков

Наша команда готова помочь вам с интеграцией детекторов XRayDetect в ваши проекты. Мы предоставляем полную техническую документацию, примеры кода и персональную поддержку.