Файл настроек логгера для dicom storage

Обновлено: 03.07.2024

В одной медицинской организации внедряли решения на базе PACS-серверов Orthanc и DICOM-клиента Radiant. В ходе настройки выяснили, что каждый DICOM-клиент должен быть описан в PACS-серверах следующим образом:

  • Имя клиента
  • AE-имя (должно быть уникально)
  • TCP-порт, который автоматически открывается на стороне клиента и принимает DICOM-обследования от PACS-сервера (т.е. сервер как бы толкает их в сторону клиента – инициируя соединение первым)
  • IP-адрес

Пример файла pacs.xml по ссылке:

Примерно полгода все было хорошо, система заработала…и тут до нас дошли «подводные камни»:

  • Нам нужно ввести в строй несколько новых PACS-серверов, которые подменят старые (где стало заканчиваться место на дисках). PACS сервера в виртуальных машинах, но речь не об этом;
  • Нам нужно как-то централизованно изменить уникальные конфигурации (двумя отличающимися параметрами) на 200 машинах (их количество регулярно увеличивалось);
  • Учитывая темпы роста объемов обследований, решение нужно не разовое, а тиражируемое и регулярное (например, 1 раз в 3-5 месяцев).

Выбор инструментария для решения задачи

Вначале были попытки найти какое-то решение, которое на стороне клиента изменяло файл pacs.xml, и вносило в него изменения в список PACS-серверов, не трогая настройки AE-имени и TCP-порта. Windows клиенты на тот момент были на базе как Windows XP, так и Windows 7 – поэтому были попытки написать что-то такое на базе VBScript. Но увы – осилить такую задачу не получилось, ввиду полного отсутствия опыта написания чего-либо сложного и комплексного на этом языке. Попытки же найти и переписать также не увенчались успехом (тут надо отметить, что в голове уже был другой план, поэтому я не долбился с VBScript больше 3-4 часов).

В итоге я остановился на следующем решении:

  • Собрать групповой политикой все файлы pacs.xml в одном месте на каком ни будь сервере в сетевом ресурсе;
  • Изменить файлы скопом (опыт решения таких задач уже был – с использованием Perl);
  • Также с помощью групповых политик обновить настройки клиентов.

Сбор файлов с помощью групповой политики

Самая простая часть – при входе клиента в свой профиль он со своими правами выполняет некий .bat файл, в котором прописано:


Таким образом на сервере в скрытом ресурсе будут накапливаться файлы pacs.xml, в имени которых есть информация с какого компьютера и с какого пользователя был скопирован данный конфиг.

Самое сложное было – дождаться, когда у всех пользователей отработает данная политика.

Изменение конфигураций с помощью Perl скрипта

Нам потребуется Active Perl под Windows от компании ActiveState, а также модуль XML::Writer, который можно установить с помощью команды ppm install XML-Writer.

Сам же скрипт получился довольно простой:


Принцип его работы:

  • Открываем каталог, в котором у нас собраны конфигурации pacs.xml от клиентов и помещаем список файлов в массив скаляров (@report_files);
  • В цикле обрабатываем по одному файлу и считываем его построчно;
  • С помощью split дробим каждую строку на 5 частей, используя кавычки как разделитель;
  • Находим строку с словом listener и помещаем в две переменные уникальные для каждого файла данные (AE-имя клиента и номер TCP-порта);
  • После этого просто формируем новый XML-файл, вписываем в него уникальные параметры и далее вставляем нужное количество PACS-серверов с их параметрами – т.е. то, ради чего все затевалось)
  • Переписываем новый XML-файл поверх старого.

Распространение измененных pacs.xml файлов по клиентам

Самое простое, что пришло в голову – внести изменения в уже работающий .bat файл, который собирает конфигурации с клиентов и добавить строку:

После установки программы и ее запуска необходимо произвести некоторые общие настройки.
Здание параметров всего рабочего места производится при помощи Мастера настройки, вызываемого автоматически при первом запуске DIGISPOT II Аудио Логгер. В будущем его можно вызвать при помощи одноименного пункта в главном меню Сервис (Service). Если настройки рабочего места ранее уже были выполнены при установке других программных продуктов, входящих в систему DIGISPOT II, настройка при помощи Мастера не требуется. Если же DIGISPOT II Аудио Логгер первый программный продукт системы, устанавливаемый на данное рабочее место, рекомендуем обратиться за подробным описанием Мастера к документу «Руководство по инсталляции и базовой настройке системы DIGISPOT II».

Специфические настройки ПО DIGISPOT II Логгер можно произвести, воспользовавшись пунктами главного меню Сервис (Service).
В первую очередь в главном меню Сервис (Service) выберите команду Установки (Settings). Появится окно Настройки (Settings), в котором следует открыть закладку Прослушка (PFL) и выбрать устройство воспроизведения для прослушки.


При необходимости в том же окне с помощью закладки Language можно сменить язык интерфейса с русского на английский.


Если вы собираетесь использовать посылку уведомления о появлении / исчезновении сигнала на входе, нужно произвести настройку параметров соединения с SMTP-сервером, воспользовавшись опциями закладки Почтовые уведомления (Mail notification). В соответствующих полях необходимо задать имя отправителя (например, Logger), адрес SMTP-сервера, порт подключения (по умолчанию указывается 25 порт), а также параметры Proxy-сервера.



За подробным описанием настроек, доступных на закладке Доп. рекомендуем обратиться к документу «Описание программы DIGISPOT II Джинн».


За информацией относительно пунктов Общие настройки (Global settings) (параметры, общие для всех рабочих мест системы DIGISPOT®II), Настройки рабочего места (Workstation settings) (параметры всех программ, установленных на данном рабочем месте), Показать журнал ошибок (Show error log) (сервисная функция системы DIGISPOT®II), подменю Аппаратное обеспечение и Статус GPI (GPI Status) (параметры дистанционного управления комплекса DIGISPOT®II) также рекомендуем обратиться к Главе 4 документа «Описание программы DIGISPOT II Джинн».

Настройка модуля записи¶


Для записи сигнала необходимо указать программе соответствующие параметры – настроить канал на запись. Для этого с помощью кнопки откройте окно Настройка логгера (Logger settings).



В этом окне указываются основные параметры настраиваемого модуля записи: в списке Устройство записи аудио (Recording audio device) необходимо указать используемое устройство записи, а в списке Частота дискретизации (Sampling frequency) выбрать требуемую частоту дискретизации. Если необходимо вести независимую запись двух моно сигналов с одного стереовхода указанного устройства записи, то нужно установить флаг Записывать левый и правый каналы отдельно (Record left and right channels separately). В этом случае настройка параметров записи по левому и правому каналу будет производиться раздельно. Единственным общим параметром в случае раздельной записи является частота дискретизации сигнала, она указывается для устройства записи в целом. При установке флага Коррелятор включается одноименный режим. Данный режим позволяет сравнивать два моно-сигнала, подаваемых на один стерео вход; его настройку можно выполнить при помощи кнопки Коррелятор, появляющейся под кнопкой данного канала (под индикатором уровня).

В окне, открывающемся по нажатию кнопки Установки VU (VU metter settings), можно установить параметры индикатора уровня модуля записи — диапазон шкалы, внешний вид индикатора и пр. Установки VU не влияют на работу системы записи сигнала, они предназначены только для индивидуальной настройки внешнего вида индикатора уровня. Настройка параметров модуля завершается нажатием кнопки OK.

Для раздельного режима записи на окне модуля дублируются все информационные и управляющие элементы, что позволяет конфигурировать левый и правый каналы, а также управлять записью сигнала полностью независимо. После настройки основных параметров логгера необходимо установить параметры записи сигнала для каждого канала записи. Для этого надо вызвать окно Свойства (Properties) нажатием кнопки соответствующего канала.


Внешний вид модуля записи зависит от того, какой режим записи был выбран при настройке. На рисунке выше представлены два варианта внешнего вида модуля. В левой части рисунка — вид модуля при записи одного канала, в правом — при раздельной записи двух каналов.
Для раздельного режима записи на окне модуля дублируются все информационные и управляющие элементы, что позволяет конфигурировать левый и правый каналы, а также управлять записью сигнала полностью независимо.

Закладка Общие (General)¶


Опишем параметры, изменение которых выполняется с помощью этого окна.

Например:
- Длительность фрагмента — 15 мин.
- Начинать новый файл — Да, каждые 60 минут.
- Программу запустили в 10:47:37, и она сразу начала запись сигнала.

Первый файл будет иметь имя 10-47-37.wav. Теоретически, запись первого файла должна быть закончена через 15 минут после начала, т. е. в 11:02:37 (имя файла 11-02-37.wav), но на 60-й минуте часа, т. е. в 11:00, будет начат новый файл (11-00-00.wav), время создания которого выровнено на границу часа. Следующий файл будет начат в 11:15 (11-15-00.wav), и т. д.
В списке имен файлов, содержащих «простое» время, легче ориентироваться.

  • Записывать один файл (Single file mode) — этот параметр определяет противоположную ситуацию, когда файл лога не разрывается.

Закладка Мониторинг (Monitoring)¶

Закладка Мониторинг (Monitoring) окна Свойства (Properties) канала содержит параметры, использующиеся для настройки автоматического управления началом / завершением записи, а также системой автоматического оповещения.


На закладке можно задать следующие параметры:

Закладка Автоматизация (Automation)¶


Закладка Автоматизация (Automation) окна Свойства (Properties) канала позволяет настроить автоматическое включение / завершение записи сигнала.

Основным элементом группы является расписание, содержащее интервалы времени, в которых должна вестись запись сигнала. Алгоритм работы программы несколько сложнее, чем просто ведение записи внутри указанных интервалов. Поведение программы внутри и вне указанных интервалов настраивается при помощи двух списков — По расписанию (Record in schedule) и Вне расписания (Record out schedule).

Содержимое списков одинаково: Никогда (Never), Всегда (Always), GPI, Уровень (Level), GPI и уровень (GPI and Level), GPI или уровень (GPI or Level), DTFM и Срыв корреляции (Correlation breackdown).
Действия, выполняемые программой в указанных интервалах (или вне указанных интервалов):

  • Никогда (Never) — запись сигнала не выполняется.
  • Всегда (Always) — запись сигнала ведется всегда, вне зависимости от каких бы то ни было внешних воздействий и от наличия / отсутствия сигнала.
  • GPI — запись ведется, только если на GPI-входе присутствует активный сигнал. Требует настройки GPI. Например, запись ведется все время, пока указанный GPI имеет состояние «1».
  • Уровень (Level) — запись ведется, только если на входе присутствует сигнал (по информации от детектора наличия сигнала): запись начинается при появлении сигнала и останавливается при его пропадании.
  • GPI и уровень (GPI and Level) — запись ведется, только если звуковой сигнал присутствует на входе и GPI-сигнал находится в активном состоянии.
  • GPI или уровень (GPI or Level) — запись ведется при наличии хотя бы одного из сигналов: звукового сигнала либо активного GPI-сигнала.
  • DTMF — запись в указанном интервале управляется DTMF-сигналами, присутствующими во входном звуковом сигнале. DTMF (Double Tone Multi Frequency) — это специальным образом модулированный сигнал, подмешиваемый в обычный звуковой ряд и преобразуемый декодером DTMF в число (обычно состоящее из 3–5 цифр). В программе возможен запуск и остановка записи звука при обнаружении в нем заранее указанных DTMF-сигналов.
  • Срыв корреляции (Correlation breakdown) — запись ведется только в случае расхождения сигналов, поступающих на разные каналы. Эта функция полезна в том случае, если Логгер используется как автоматический «инспектор» точности ретрансляции сигнала региональной радиостанцией (при сетевом вещании).

Расписание записи можно создать, воспользовавшись пунктом Добавить из контекстного меню, вызываемого правой кнопкой мыши. При выборе пункта меню будет открыто дополнительное окно Временной интервал, где можно задать название и параметры (день недели, начало и окончание) нового элемента. Контекстное меню расписания также позволяет отредактировать ранее созданный и удалить выделенный элемент, а также управлять индикацией текущего элемента. При переходе к работе с расписанием логгирования во время «пересечения» границы интервала всегда создается новый файл. В процессе записи сигнала распределение его по звуковым файлам управляется параметрами Максимальная длительность фрагмента (Fragment (file) max length (min)) и Начинать новый файл (Start new file (min)), находящимися на закладке Общие (General) и описанными ранее.

Кнопка Настройка DTMF (DTFM setup) закладки Автоматизация (Automation) открывает окно настройки DTMF-сигналов, которое позволяет указать параметры декодера DTMF и сигналы, начинающие и останавливающие запись.
Кнопка Добавить вызывает окно, позволяющее задать новый сигнал, а также указать задержку его исполнения (это удобно в том случае, если сигнал передается в середине музыкальной отбивки, а запустить или завершить запись необходимо по окончании звучания фрагмента). Список в окне настройки позволяет временно включать или выключать те или иные сигналы (флаги Вкл. и Выкл). За подробной информацией относительно Настройки декодера рекомендуем обратиться к полному описанию программы DIGISPOT II Джинн.


Кнопка Настройка GPI вызывает окно Настройка битов GPI. Подробнее о работе с параметрами GPI вы можете прочитать в описании программы DIGISPOT II Джинн.

Группа параметров Дистанционное управление записью позволяет настроить возможность удаленного включения и выключения логгирования. Данная функция может быть полезна при размещении рабочего места с DIGISPOT II Логгер в территориально удаленной от основного офиса точке (быть может, даже в другом городе). Для использования этой функции необходимо установить флаг Разрешить ДУ, задать Коммуникационное устройство из выпадающего списка, а также (при необходимости) установить параметр Только с эфирного компьютера, ограничивающий возможность управления Логгером извне. Поле TCP device name относится к специфическим конфигурациям ПО DIGISPOT II Аудио Логгер и в обычных ситуациях не требует заполнения.

Закладка Аудио (Audio)¶

Закладка Аудио (Audio) окна Свойства (Properties) канала содержит следующие параметры:

Добрый день, хабрасообщество. Мне хотелось бы продолжить рассмотрение аспектов реализации DICOM Viewer'а, и сегодня речь пойдёт о функциональных возможностях.


Инструментарий в 2D

Мультипланарная реконструкция (MPR)

Мультипланарная реконструкция позволяет создавать изображения из оригинальной плоскости в аксиальную, фронтальную, сагиттальную или произвольную плоскости. Для того чтобы построить MPR, необходимо построить объёмную 3D-модель и «разрезать» её в нужных плоскостях. Как правило, наилучшее качество MPR получается при компьютерной томографии(КТ), потому что в случае КТ можно создать 3D модель с разрешением, одинаковым во всех плоскостях. Поэтому выходное MPR получается с таким же разрешением, какое было у исходных изображений, полученных из КТ. Хотя бывают и МРТ с хорошим разрешением. Вот пример мультипланарной реконструкции:


Зелёным — аксиальная плоскость (слева вверху);
Красным — фронтальная плоскость (справа вверху);
Синим — сагиттальная плоскость (слева внизу);
Жёлтым — произвольная плоскость (справа внизу).

Положение правого нижнего снимка определяется жёлтой линией на виде сбоку (левый верхний). Это и есть изображение, полученное «разрезанием» 3D-модели наклонной плоскостью. Для получения значения плотности в конкретной точки плоскости используется трилинейная интерполяция.

Мультипланарная реконструкция по произвольной кривой (curved MPR)


То же самое, что и MPR, только вместо произвольной плоскости можно взять кривую, как показано на рисунке. Используется, например, в стоматологии для панорамного снимка зубов.

Каждая точка на кривой задаёт исходную точку трассировки, а нормаль к кривой в этой точке соответствует направлению оси Y в двухмерном изображении для этой точки. Оси X изображения соответствует сама кривая. То есть в каждой точке двухмерного изображения направление оси X – это касательная к кривой в соответствующей точке на кривой.

Проекция минимальной/средней/максимальной интенсивности (MIP)

Значения минимальной интенсивности показывают мягкие ткани. Тогда как значения максимальной интенсивности соответствуют наиболее ярким участкам трёхмерного объекта — это либо наиболее плотные ткани, либо органы, насыщенные контрастным веществом. Минимальное/среднее/максимальное значение интенсивности берётся в диапазоне (как показано на рисунке пунктирными линиями). Минимальное значение по всей модели будет принимать воздух.

Алгоритм вычисления MIP очень простой: выбираем плоскость на 3D модели — пусть будет плоскость XY. Потом проходим по оси Z и выбираем максимальное значение интенсивности на заданном диапазоне и отображаем его на 2D плоскости:


Изображение, полученное путём проекции средней интенсивности, близко к обычному рентгеновскому снимку:


Некоторые виды радиологических исследований не дают должного эффекта без использования контрастного препарата, поскольку не отражают некоторые виды тканей и органов. Это связано с тем, что в организме человека есть ткани, плотность которых примерно одинакова. Чтобы отличать такие ткани друг от друга, используют контрастное вещество, которое придаёт крови большую интенсивность. Также контрастное вещество используется для визуализации сосудов при ангиографии.

Режим DSA для ангиографии

Ангиография — это приём, позволяющий визуализировать системы кровотоков (вены и сосуды) различных органов. Для этого используется контрастное вещество, которое вводят в исследуемый орган, и рентгеновский аппарат, создающий снимки во время ввода контрастного вещества. Таким образом на выходе аппарата получается набор снимков с разной степенью визуализации кровотоков:


Однако вместе с венами и сосудами на снимках видны ткани других органов, например, черепа. Режим DSA (Digital subtraction angiography) позволяет визуализировать только кровотоки без каких-либо других тканей. Как это работает? Берём изображение серии, в котором кровотоки ещё не визуализированы контрастным веществом. Как правило, это первое изображение серии, так называемая маска:


Затем вычитаем это изображение из всех остальных изображений серии. Получаем следующее изображение:


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

Инструментарий в 3D

Инструмент куб видимости (Clipping Box)

Инструмент Clipping Box позволяет увидеть кости и анатомические ткани в разрезе, а также показать внутренние органы изнутри. Инструмент реализуется на уровне рендера, просто ограничивая область рейтрейсинга.


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

Инструментарий редактирования объема — вырезание многоугольником

Инструмент похож на предыдущий и позволяет удалять фрагмент объёма под произвольным многоугольником:


Под вырезанием следует понимать зануление вокселей в 3D-моделе, попавших в область многоугольника.
Также есть инструмент «Ножницы», который позволяют удалять части 3D-модели по принципу связности. Реализация: при выделении объекта происходит циклический поиск близлежащих связных вокселей, пока все близлежащие воксели не будут просмотрены. Затем все просмотренные воксели удаляются.

Линейка в 3D

В 3D можно производить измерения органов под любым углом, что невозможно для некоторых случаех в 2D.


В режиме 3D можно также воспользоваться полигональной линейкой:


Инструментарий в 4D

Совмещение нескольких томографических серий в 3D (Fusion PET-CT)

ПЭТ-КТ (англ. PET-CT) относительно новая технология, являющаяся исследовательским методом ядерной медицины. Является методом мультимодальной томографии. Четвёртым измерением в данном случае является модальность (PET и CT). Предназначена в основном для обнаружения раковых опухолей.

CT помогает получить анатомическую структуру человеческого тела:


а PET показывает определённые области концентрации радиоактивного вещества, которая напрямую связана с интенсивностью кровоснабжения данной области.


PET получает картину биохимической активности, детектируя в теле человека радиоактивные изотопы. Радиоактивное вещество скапливается в органах, насыщенных кровью. Затем радиоактивное вещество претерпевает позитронный бета-распад. Образовавшиеся позитроны в дальнейшем аннигилирует с электронами из окружающей ткани, в результате чего происходит излучение пар гамма-лучей, которые и детектируются аппаратом, и затем на основе полученной информации строится 3D изображение.

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

Но основываясь на PET трудно понять, в какой части тела находится область с максимальной концентрацией радиоактивного вещества. При соединении геометрии тела (CT) и областей, насыщенных кровью с высокой концентрацией радиоактивного вещества (PET), получаем:


В качестве радиоактивного вещества для PET применяются радиоактивные изотопы с разными периодами полураспада. Для образования всякого рода злокачественных образований используется фтор-18 (фтордезоксиглюкоза), йод-124 используется для диагностирования рака щитовидной железы, галлий-68 — для обнаружения нейроэндокринных опухолей.

Функционал Fusion формирует новую серию, в которой изображения обоих модальностей (и PET и CT) объединены. В реализации изображения обоих модальностей перемешиваются, а затем сортируются по оси Z (считаем, что X и Y – оси изображения). Фактически получается, что изображения в серии чередуются (PET, CT, PET, CT …). Эта серия в дальнейшем используется для отрисовки 2D fusion и 3D fusion. В случае 2D fusion изображения отрисовываются попарно(PET-CT) в порядке возрастания Z:


В данном случае сначала был отрисовано изображение CT, затем PET.

3D fusion реализован для видеокарты на CUDA. На видеокарте отрисовываются одновременно обе 3D-модели — PET и CT и получается реальный мультимодальный fusion. На процессоре fusion тоже работает, но работает несколько иначе. Дело в том, что на процессоре обе модели представлены в памяти как отдельные окто-деревья. Следовательно, при отрисовке необходимо трассировать два дерева и синхронизировать пропуск прозрачных вокселей. А это бы значительно снизило скорость работы. Поэтому было решено просто накладывать результат рендера одной 3D-модели поверх другой.

4D CardiacCT

Технология Cardiac CT используется для диагностики различных нарушений работы сердца, включая коронарную болезнь сердца, тромбоэмболия легочной артерии и другие заболевания.

4D Cardiac CT представляет собой 3D во времени. Т.е. получается небольшое видео, которое будем называть кинопетлёй, в которой каждый кадр будет представлять собой 3D-объект. Исходные данные представляют собой набор dicom-изображений сразу для всех кадров кинопетли. Для того чтобы преобразовать набор изображений в кинопетлю, необходимо сначала сгруппировать исходные изображения по кадрам, а затем для каждого кадра создать 3D. Построение 3D-объекта на уровне кадра происходит так же как и для любой серии dicom-изображений. Мы используем эвристическую сортировку изображений для группировки по кадрам, используя положение изображения на оси Z (считая что X и Y это оси изображения). Полагаем, что после группировки по кадрам, в каждом кадре получается одинаковое количество изображений. Переключение кадра фактически сводится к переключение 3D-модели.

5D Fusion Pet – CardiacCT

5D Fusion Pet – CardiacCT — это 4D Cardiac CT с добавлением fusion с PET в качестве пятой размерности. В реализации сначала создаём две кинопетли: с CardiacCT и с PET. Затем делаем fuision соответствующих кадров кинопетель, что даёт нам отдельную серию. Затем строим 3D полученной серии. Выглядит это так:

Виртуальная эндоскопия

В качестве примера виртуальной эндоскопии будем рассматривать виртуальную колоноскопию, поскольку она является наиболее распространённым видом виртуальной эндоскопии. Виртуальная колоноскопия позволяет на основе данных КТ построить объёмную реконструкцию области брюшной полости и по этой трёхмерной реконструкции произвести диагностику. Во вьюере есть инструмент полёт камеры (fly-through) с навигацией по MPR:


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

Полёт камеры представляет серию последовательных перемещений по внутрикишечной области. Для каждого шага вычисляется вектор перемещения камеры в следующую часть анатомической структуры. Вычисление производится на основе прозрачных вокселей в следующей части анатомической структуры. Фактически вычисляется некий средний воксель среди прозрачных. Начальный вектор перемещения задаётся вектором камеры. В инструменте Полёт камеры используется исключительно перспективная проекция.

Также есть функционал для автоматической сегментации кишечника, т.е. функционал для отделения кишечной области от остальной анатомии:


Возможна также навигация по сегментированной 3D-модели (кнопка Show camera orientation), которая по клику мыши на 3D-моделе перемещает камеру на соответствующую позицию в исходной анатомии.
Сегментация реализуется с помощью волнового алгоритма. Полагается, что анатомия замкнутая в том смысле, что она не контактирует с другими органами и внешним пространством.

Система просмотра ЭКГ (Waveform)

Отдельным модулем во viewer'е реализовано чтение данных из Waveform и их отрисовка. DICOM ECG Waveform это специальный формат хранение данных отведений электрокардиограмм, определяемый стандартом DICOM. Данные электрокардиограммы представляют собой двенадцать отведений — 3 стандартных, 3 усиленных и 6 грудных. Данные каждого отведения представляют собой последовательность измерений электрического напряжения на поверхности тела. Для того чтобы отрисовать напряжения, нужно знать масштаб по вертикали в мм/мВ и масштаб по горизонтали в мм/сек:


В качестве вспомогательных атрибутов также отрисовывается сетка для простоты измерения расстояний и масштаб в левом верхнем углу. Варианты масштаба подобраны с учётом врачебной практики: по вертикали — 10 и 20 мм/мВ, по горизонтали — 25 и 50 мм/сек. Также реализованы инструменты для измерения расстояния по горизонтали и вертикали.

DICOM-Viewer как DICOM-клиент

DICOM-Viewer, помимо прочего, представляет собой полноценный DICOM-клиент. Есть возможность производить поиск на PACS-сервере, получать из него данные и др. Функции DICOM-клиента реализованы с помощью открытой библиотеки DCMTK. Рассмотрим типичный use-case работы DICOM-клиента на примере viewer'а. Производим поиск стадий на удалённом PACS-сервере:


При выборе стадии внизу отображаются серии для выбранной стадии и количество изображений в них. Сверху справа указывается PACS-сервер, на котором будет произведён поиск. Поиск можно параметризовать, уточняя критерии поиска: PID, дата исследования, имя пациента и др. Поиск на клиенте реализуется командой C-FIND SCU с помощью библиотеки DCMTK, которая работает на одном из уровней: STUDY, SERIES и IMAGE.

Далее изображения выбранной серии можно загрузить, используя команды С-GET-SCU и C-MOVE-SCU. Протокол DICOM обязывает стороны соединения, т.е. клиента и сервера, заранее договориться, какие типы данных они собираются передавать через это соединение. Под типом данных понимается комбинация значений параметров SOPClassUID и TransferSyntax. SOPClassUID определяет тип операции, которую планируется выполнять через данное соединение. Наиболее часто используемые SOPClassUID'ы: Verification SOP Class (пинг сервера), Storage Service Class (сохранение изображений), Printer Sop Class (выполнение печати на DICOM-принтере), CT Image Storage (сохранение изображений КТ), MR Image Storage (сохранение изображение МРТ) и другие. TransferSyntax определяет формат бинарного файла. Популярные TransferSyntax'ы: Little Endian Explicit, Big Endian Implicit, JPEG Lossless Nonhierarchical (Processes 14). То есть, чтобы передать МРТ изображения в формате Little Endian Implicit, то в соединение необходимо добавить пару MR Image Storage — Little Endian Explicit.


Загруженные изображения сохраняются в локальное хранилище и, при повторном просмотре, загружаются из него, что позволяет увеличить производительность viewer'а. Сохранённые серии помечаются жёлтым значком в верхнем левом углу первого изображения серии.

Также DicomViewer как DICOM-клиент умеет записывать диски с исследованиями в формате DICOMDIR. Формат DICOMDIR реализуется в виде бинарного файла, который содержит относительные пути ко всем DICOM-файлам, которые записываются на диск. Реализуется с помощью библиотеки DCMTK. При чтении диска считываются пути ко всем файлам из DICOMDIR и после этого загружаются. Для добавления в DICOMDIR стадий и серий был разработан такой интерфейс:


Вот и всё, что я хотел рассказать про функционал DicomViewer'а. Как всегда очень приветствуется обратная связь от квалифицированных специалистов.

Примеры данных:
MANIX — для общих примеров (MPR, 2D, 3D и т.д.)
COLONIX — для виртуальной колоноскопии
FIVIX — 4D CARDIAC-CT
CEREBRIX — Fusion PET-CT

Прикладные решения «1С:Медицина. Поликлиника» и «1С:Медицина. Больница» поддерживают возможность информационного взаимодействия с PACS (программно-аппаратный комплекс, реализующий функцию передачи и архивации изображений) по протоколу HL7 версии 2 и медицинским оборудованием по стандарту DICOM 3. Продукты могут взаимодействовать с одним или несколькими PACS и с неограниченным числом медицинских приборов. Предусмотрен вариант функционирования без PACS с помощью встроенного DICOM сервер.

Успешно пройдены тесты обмена данными между решением линейки «1С:Медицина» и системой для передачи и хранения изображений (PACS) комплекса КАП «Гамма Мультивокс».

Поддерживаемые пакеты HL7 версии 2

Протестирован обмен с GE CentricityPACS/CCG.

Термины и сокращения DICOM 3

  • DICOM (Digital Imaging and Communications in Medicine) - Стандарт обработки, хранения, печати и передачи медицинских изображений. В стандарт входит формат файлов и сетевой протокол передачи данных. Так же известен как ISO 12052:2006.
  • PACS (Picture Archiving and Communication System) - Программно-аппаратные комплексы, реализующие функции передачи и хранения изображений.
  • Storage - DICOM служба, обеспечивающая передачу и хранение изображений (файлов в формате DICOM).
  • Query/Retrieve - DICOM служба, обеспечивающая получение информации об изображениях, хранящихся на DICOM сервере, а также обеспечивающая выполнение команд по передаче изображений.
  • MWL (Modality Worklist Management) - DICOM служба, обеспечивающая передачу сведений о пациентах и их исследованиях из радиологической информационной системы на медицинское оборудование.
  • MPPS (Modality Performed Procedure Step) - DICOM служба, обеспечивающая передачу сведений о выполненных на медицинском оборудовании исследованиях в радиологическую информационную систему.
  • SCP (Service Class Provider) - Программное обеспечение, функционирующее как серверная часть некоторой DICOM службы.
  • SCU (Service Class User) - Программное обеспечение, функционирующее как клиент некоторой DICOM службы.

Поддерживаемые DICOM функции

В «1С:Медицина. Поликлиника» и «1С:Медицина. Больница» поддерживаются следующие DICOM функции:

DICOM служба Название DICOM функционала На сервере «1С:Предприятие» (Windows 32/64 и Linux 32/64) На клиенте «1С:Предприятие» (Windows 32/64 и Linux 32/64)

Серверная часть
Storage SCP DICOM storage (C-STORE) SCP + +
MWL SCP DICOM Basic Worklist Management SCP + -
MPPS SCP(*) DICOM Modality Performed Procedure Step SCP + -

Клиентская часть
Query/Retrieve SCU DICOM query (C-FIND) SCU - +

Некоторые функции могут быть использованы как на сервере «1С:Предприятие», так и на клиенте. Вариант использования определяется исходя из условий и задач конкретной медицинской организации.

Встроенный DICOM сервер

В программах «1С:Медицина. Поликлиника» и «1С:Медицина. Больница» реализован функционал DICOM сервер. Встроенный DICOM сервер реализует следующие функции:

  • передача сведений о пациентах и их исследованиях на медицинское оборудование;
  • получение сведений от медицинского оборудования о выполненных исследованиях;
  • получение изображений от медицинского оборудования
  • хранение файлов, полученных от оборудования в оригинальном виде в течение установленного срока;
  • сохранения изображений с клиническим качеством в составе протоколов исследований (встраивание в CDA документ).

Для долговременного сохранения изображений их необходимо прикрепить к конкретному медицинскому документу. Прикрепленные к документам изображения сохраняются в формате JPEG.

Взаимодействие с медицинским оборудованием (без PACS)


Рисунок 2 - Схема информационного взаимодействия продуктов «1С:Медицина. Поликлиника» и «1С:Медицина. Больница» с медицинским оборудованием без PACS

Поддержка DICOM Worklist и MPPS

В прикладных решениях «1С:Медицина. Поликлиника» и «1С:Медицина. Больница» реализован функционал MWM SCP, который позволяет осуществлять передачу списков пациентов и запланированных исследованиях. Списки передаются на медицинское оборудование автоматически. Для каждого прибора формируется индивидуальный список (worklist).

Сервис MPPS SCP позволяет регистрировать факты выполнения исследований на приборах.

Взаимодействие с PACS

Программные продукты «1С:Медицина. Поликлиника» и «1С:Медицина. Больница» позволяют осуществлять информационное взаимодействие с одним или несколькими PACS в объеме:

  • передача сведений о пациентах и их исследованиях на медицинское оборудование;
  • получение сведений от медицинского оборудования о выполненных исследованиях;
  • просмотр содержимого PACS;
  • передача команд в PACS на пересылку изображений из PACS на рабочие станции врачей с программным обеспечением, реализующим функции DICOM Viewer;
  • получение изображений как из PACS, так и от рабочих станций врачей с программным обеспечением, реализующим функции DICOM Viewer, для сохранения изображений с клиническим качеством в составе протоколов исследований.

Взаимодействие с PACS и медицинским оборудованием


Рисунок 1 - Схема информационного взаимодействия продуктов «1С:Медицина. Поликлиника» и «1С:Медицина. Больница» с PACS и медицинским оборудованием

Во встроенном в конфигурации Storage SCP могут накапливаться полученные от медицинского оборудования изображения. При этом в конфигурации не предусмотрены возможности:

image

Задача сохранения настроек встречается в подавляющем большинстве современных устройств. Реже, но тоже очень часто, требуется хранение лог-файлов. Если речь идет о большом устройстве построенном на Линукс и содержащей как минимум SD карту, то с этими задачами не возникает проблем. Но если все устройство представляет из себя микроконтроллер, то возникает вопрос, где и в каком виде хранить подобные данные. В этом случае, обычно для настроек предлагают использовать сырые данные размещенные во внешнем eeprom. Но такой подход гораздо менее удобен чем вариант с файловой системой пусть даже с сильно ограниченными свойствами. Кроме того он плохо подходит для задач логирования. В данной статье мы расскажем как можно организовать удобное хранение файлов настроек и лог-файлов во внутренней флеш памяти микроконтроллера.

Простейшая read-only файловая система

Начнем с самого понятия файловой системы. Когда речь заходит о файловой системе, то сразу возникает ощущение чего то большого, а следовательно и имеющего большие накладные расходы. Да, это правда, накладные расходы присутствуют, ведь для описания файлов, хотя бы их имен или идентификаторов, необходимо место. Да, существует проблема достаточно больших накладных расходов при применение универсальных файловых систем. Стремление сделать универсальные файловые менее ресурсоемкими привели к созданию littleFS, но даже она требует 10кб (RAM + ROM), что для микроконтроллера порой избыточно, ведь требуется всего лишь хранить несколько десятков параметров.

Но давайте можно ли ограничив функционал уменьшить накладные расходы?

Конечно можно, ведь файл это просто именованная последовательность упорядоченных данных. Давайте поместим наши параметры в некий блок данных, и присвоим этому блоку имя, и по сути дела получим файл. А теперь давайте сделаем несколько файлов с данными, запакуем их в cpio формат и поместим этот cpio в наше firmware, при этом сохраним адрес начала нашего архива.

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


И добавив линкер скрипт


Этого достаточно, теперь мы можем внутри программы ходить по файлам, метки и другие метаданные доступны. Наша файловая система упакована в очень простой формат cpio , который почти не требует накладных расходов. Собственно в Embox мы называем эту файловую систему initfs. Она является полноценной файловой read-only системой в которой доступны как файлы так и папки.

Файлы в этом случае представляют из себя описание файла содержащее имя и адрес начала данных и сами данные. Причем данные это просто массив байт. Аналогично можно представить файл в виде си-массива и включить его в проект при компиляции. Этот метод широко используется например при создании веб-сайтов на базе lwIP. Об преимуществах Embox при создании web-сайтов мы рассказывали в статье.
.
В итоге предлагаемый подход на основе cpio имеет сопоставимые накладные расходы по сравнению с внедрением массива байт, и они меньше по сравнению с littleFS. Что не удивительно, ведь мы создали еще более специализированное решение.

Общие сведения о файловой системе

Прежде чем продолжить нам необходимо сделать небольшое отступление и немного разобраться с общими принципами файловых систем. Ведь когда мы говорим об littleFS, имеют в виду тип файловой системы и драйвер для данного типа. А для того чтобы работать с файлами, потребуется еще несколько понятий. Например индексный дескриптор описывающий открытый файл. Который как минимум должен иметь методы чтения и записи этого файла.

Мы рассмотрим только несколько типов объектов без которых трудно обойтись. Начнем с описателей файла. Есть два типа описаний файла. Первый это описатель представления файла на носителе (inode ). Отмечу, что имя файла хранится не в самом inode, а в записи об этом файле в родительской директории (directory entry (dentry)). dentry хранит имя файла и ссылку на его inode эта информация нужна для поиска файла в файловой системе.

Вторым описателем файла является описатель открытого файла представленный в виде индексного дескриптора. Этот описатель получается с помощью стандартного POSIX вызова open(). Отмечу что объект FILE получаемый с помощью fopen() является описателем потока (stream) а не файла, хотя во многих вещах это одно и тоже. Индексный дескриптор для файла должен как минимум содержать текущую позицию по которой происходит чтение или запись и ссылку на его inode.

Тип файловой системы определяет формат в котором хранятся метаданные и данные в этой файловой системы. Драйвер файловой системы это реализацию функций работы с форматом для данного типа файловой системы, например, упомянутые littleFS и initfs (в Embox) это драйвера файловой системы.

Еще одним важным объектом является описатель файловой системы (superblock). В нем хранится информация о методах работы с файловой системой и ее состояние (например блочное устройство на котором оно работает).

Драйвер initFS

Вернемся к цели нашей статьи файловая система внутри микроконтроллера. Мы уже поняли, что создать удобную read-only файловую систему с очень маленькими накладными расходами возможно. Для удобной работы через привычные open/read/write нам не хватает совсем немного. Например нужно чтобы наш драйвер имел какое то API. Давайте рассмотрим некоторые функции драйвера в Embox, для общего понимания каким может быть это API.


Определяем сам драйвер. У него есть имя файловой системы и функция заполнения superblock. В драйвере еще могут быть функция форматирования блочного устройства в формате файловой системы и очистка superblock, но у нас read-only файловая система и этого точно не требуется.

Функция заполнения superblock


В ней мы заполняем несколько указателей на различные функции работы с файловой системой. А также выделяем экземпляр структуры inode для данной файловой системы. Выделение нужно поскольку любая файловая система имеет точку монтирования, что тоже является файлом, точнее директорией.


Функция сreate() создает новую inode на файловой системе, в нашем случае она просто возвращает ошибку прав доступа. Нам же понадобятся пара функций для операций с inode: lookup функция поиска по имени в заданной папке и iterate — функция для перебора и получения имени всех inode в папке.


На самом деле, если нужно только open/read/write то без iterate можно было бы попробовать обойтись. По сути дела она используется в readdir, но для красоты реализации (и универсальности конечно) функцию open() лучше выразить через readdir().

Функция lookup() ищет файл с указанным именем в директории и в случае обнаружения возвращает указатель на новую inode.


Из функций superblock интересна open_idesc. Для регулярных файлов она должна выделить объект idesc, тот самый описатель файла по которому будут происходить операции read/write. inode который описывает файл на диске уже заполнен с помощью функции lookup.


Нам осталось рассмотреть только функции для работы с файлами read/write. write() будет пустой и просто вернет ошибку. Функция read() тоже не сложная:


Переставляет текущий курсор и копирует данные в буфер.

Файловая система

Теперь когда у нас есть драйвер в нашей файловой системе, давайте посмотрим что это нам дает и оценим затраты.

Что дает хорошо видно на этом скриншоте.


Мы можем работать с данными размещенными внутри нашего образа, как с обычными файлами. Я вызываю обычную команду ‘ls’ и затем вывожу информацию с помощью обычной команды ‘cat’.

Сколько это стоит? То есть сколько требуется ресурсов для подобное удобство. Оказалось не так уж и много. Я использовал STM32F4-discovery и я сравнил образы с файловой системой и без, оказалось на text + rodata (то есть код и константы в том числе и сами файлы) нужно порядка 8 кБ. При этом я даже не включал оптимизацию. Для RAM потребовалось порядка 700 байт. Откуда они берутся. Нужен объект superblock, и inode для каждой примонтированной файловой системы, Нужны объекты dentry включающие inode для каждой открытой папки и файла. нужен idesc для каждого открытого файла.

Наверное кто то скажет что несколько кБ за read-only файловую систему для микроконтроллера много. Но нужно учитывать что я оценивал всю подсистему, причем вместе с файлами сайта которые занимали пару киллобайт, а не только драйвер. А добавление еще одного драйвера требует гораздо меньше ресурсов (если он простой конечно).

DumbFS

Давайте разработаем драйвер который может работать во внутренней флеш микроконтроллера. Наш драйвер для хранения настроек и лог-файлов, может быть очень простым. Например, нам не нужно хранить атрибуты файлов, мы можем обойтись без директорий, мы даже можем сказать что там нужно только 3 файла ведь на этапе проектирования, мы можем определить какие именно файлы нужны и можем задать их максимальных размер. Максимальный размер для файла может пригодиться, потому что мы сможем сразу отформатировать наше устройство хранение под заданные характеристики, зарезервировав и количество dentry (записей в директориях) и место под каждый файл.

Наш superblock может выглядеть следующим образом:


Первые два байта это просто идентификатор файловой системы, для проверки что наше устройство хранения отформатировано нужным образом. Далее идут счетчик файлов, на случай если мы хотим не сразу отформатировать все файлы, а все таки иметь возможность создавать как в настоящей файловой системе. Далее идет максимальное количество этих файлов. Оба параметра имеют размер 1 байт, вряд ли нужно хранить больше 255 файлов на подобной системе. Затем идет максимальная длина файла. И дальше пара необязательных параметров. free_space это свободное нераспределенное пространство, хотя его можно вычислить в через inode_count. А buff_bk служит для определения буферизации. Он полезен поскольку во внутренней флешь памяти перед записью нужно стереть целый блок. Этот параметр тоже может быть вычислен и его не обязательно хранить на устройстве.

Далее мы можем сразу разместить записи для директории, она у нас одна поэтому данные могут располагаться сразу за superblock


Все просто, первый параметр имя файла. Второй смещение начала данных в устройстве хранения. Третий текущая длина. И четвертый необязательный флаги или атрибуты файла.

Рассмотрим некоторые функции драйвера:


Функция заполнения suberblock похоже на аналогичную в initfs тоже устанавливаем обработчики операций, но так как у нас реальная файловая система нужно считать данные superblock с устройства и еще заполнить inode для корневой папки

Функции iterate и lookup тоже аналогичны initfs, разница только в формате представления dentry.

Поскольку у нас добавилась возможность записи на файловую систему, то необходимо реализовать например функцию itruncate которая изменяет текущий размер файла.


Тут тоже все просто, считываем dentry для файла, меняем текущую длину и записываем.

Самая интересная функция конечно запись, ведь если чтение это просто копирование из определенного адреса (ну или считывание блока и копирование, если флешь все таки внешняя), то запись как известно достаточно сложная операция. Причем записать можно только ячейку которую предварительно стерли. То есть для того чтобы записать какой то блок данных, нужно сохранить (закешировать) блок при этом еще и вместо старых данных записать новые, стереть изначальный блок и записать его новыми данными.


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

Зачем стирать кэш? Ведь обычно это просто массив данных в RAM размером с блок данных. Но в некоторых микроконтроллерах присутствует достаточно много flash памяти, но RAM ограничена. Пример STM32F4-discovery имеет 1024 кБ flash. Среди них 4 блока по 16кБ которые можно было бы использовать под наши нужды. Но при этом есть всего 128+64кБ ОЗУ. И не всегда есть достаточно памяти чтобы выделить 16 кБ в ОЗУ. Тогда для кэширования можно использовать второй блок по 16КБ.

Наша файловая система почти готова. Осталось только научиться писать в правильные блоки внутренней флешь. То есть нужно выделить несколько блоков памяти и превратить их в блочное устройство. Давайте поступим также как и с cpio архивом. Скажем линкеру зарезервировать соответствующую память.


Операции работать с блочным устройством рассматривать не будем, это выходит за рамки данной статьи.

Собственно все, у нас получилось сделать примитивную файловую систему с ограниченным количеством файлов, без директорий с ограниченной длиной файлов, но перезаписываемую имеющую минимально возможные накладные расходы, и позволяющую разместить ее где угодно, даже в 2 кБ внутренней памяти. (количество файлов и их максимальный размер будут соответствующие).


На этом скриншоте виден файл с настройками сети, которые могут быть изменены в процессе работы. А также приведены данные самой файловой системы. Можно увидеть и superblock и dentry и поскольку файл первый содержимое самого файла.

То же самое можно увидеть напрямую в памяти.


Остается отметить сколько нужно ресурсов. Сам драйвер занимает меньше килобайта, мы его почти весь разобрали. Накладные расходы на RAM, собственно их и нет, точнее они включены в расходы самой файловой системы, нужно иметь superblock и другие объекты, чтобы работать с файлами, но они у нас уже были включены для работы с initfs. Ну и конечно есть код драйвера для работы с flash, сама флешь и кэш буфер для нее. Но все это также нужно и при работе напрямую без файловой системы.

Лог-файлы

Для этого можно создать специальную файловую систему. Но у нас же есть файловая система, а по сути дела лог-файл, это просто файл который записывается по кругу. Таким образом мы можем разработать библиотеку и приложение, которое будет независимым от формата файловой системы, флешь памяти и самого микроконтроллера. Следовательно разрабатывать будет куда проще. Можно даже взять какой нибудь существующий логгер, но я все таки хочу добавить немного специфики. Пусть наш файл будет иметь ограниченное количество записей и записи будут одинакового размера.

Разрабатывать и отлаживать прикладной код можно прямо на Linux, но я это сделаю для Embox и запущу в qemu.

Функция печати лога:


Приложение настолько простое что пояснять его не нужно.

Таким образом формат нашей записи будет:


Результаты хорошо видно на скриншоте:


Добавим наш логгер в конфигурацию для платы STM32F4-Discovery. И получим тоже самое поведение:


Простое устройство

Файловая система это конечно хорошо, но давайте попробуем применить ее на каком нибудь простом устройстве.


Все, теперь просто скриншоты, на которых по моему мнению все понятно.





Заключение

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

Кроме того нужно учитывать, что флеш память имеет блочную структуру, следовательно если мы хотим хранить внутри микроконтроллера изменяемые настройки, нужно выделить как минимум один блок. А даже для f4 это 16 кБ.

Если же устройство имеет SD карту и требуется уметь читать FAT то в этом случае, добавление файловой системы для настроек и логирования, точно имеет смысл, поскольку за незаметные накладные расходы мы получаем удобство и универсальность решения. Например описанная в статье DumbFS работает на сериях STM32 (f3, f4, f7, h7) причем другие просто не пробовали. А сам приведенный в статье логгер вообще работает на любой файловой системе.

P.S. Спасибо за комментарии. Решил немного дополнить, изначально думал, что это понятно.

Статья направлена не на рассмотрение правильного способа сохранять настройки или логи в микроконтроллере. Есть разные способы это сделать. В статье показываются удобства и преимущества использования файловой системы и приводятся данные о том, что затраты могут быть очень небольшими. Поэтому этот подход можно использовать в том числе в микроконтроллерах.

В статье не разбираются особенности организации блочных устройств или flash памяти. Это отдельная тема. Все тоже самое, или только лог могут быть размещены не внутри микроконтроллера, а во внешней flash или другом носителе. Для этого нужен только драйвер этого устройства. Проблема учета износа ячеек также не рассматривается, это можно сделать либо на уровне драйвера блочного устройства, либо на уровне файловой системы. Ну и конечно, все исходники доступны в репозитории Embox

Читайте также: