Слушатель DICOM - управление действиями ассоциации

Попытка реализовать настольное приложение DICOM Router (Java) с использованием набора инструментов dcm4che (v.2).

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

Я использую утилиту / инструмент dcmrcv для реализации приемника DICOM следующим образом (getDcmRcv () на самом деле является объектом dmcRcv):

...
private final CustomStorageService storageSCP = new CustomStorageService(CUIDS);
...
public DcmRcv(String name) {
    device = new Device(name);
    executor = new NewThreadExecutor(name);

    device.setNetworkApplicationEntity(ae);
    device.setNetworkConnection(nc);
    ae.setNetworkConnection(nc);
    ae.setAssociationAcceptor(true);
    ae.register(new VerificationService());
    ae.register(storageSCP);
    ae.register(stgcmtSCP);        
    ae.addAssociationListener(storageSCP);
}

Я как-то изменил StorageService для управления AssociationListener следующим образом:

private final class CustomStorageService extends StorageService implements AssociationListener {
    public CustomStorageService(final String[] sopClasses) {
        super(sopClasses);
    }

    @Override
    protected void onCStoreRQ(final Association association, final int pcid, final DicomObject dcmReqObj,
                               final PDVInputStream dataStream, final String transferSyntaxUID,
                               final DicomObject dcmRspObj)
            throws DicomServiceException, IOException {

        final String classUID = dcmReqObj.getString(Tag.AffectedSOPClassUID);
        final String instanceUID = dcmReqObj.getString(Tag.AffectedSOPInstanceUID);

        GlobalConfig config = new GlobalConfig();
        final File associationDir = config.getAssocDirFile();

        final String prefixedFileName = instanceUID;
    final String dicomFileBaseName = prefixedFileName + DICOM_FILE_EXTENSION;

    File dicomFile = new File(associationDir, dicomFileBaseName + PARTIAL_FILE_EXTENSION);
    assert !dicomFile.exists();

    final BasicDicomObject fileMetaDcmObj = new BasicDicomObject();
    fileMetaDcmObj.initFileMetaInformation(classUID, instanceUID, transferSyntaxUID);

    final DicomOutputStream outStream = new DicomOutputStream(
        new BufferedOutputStream(new FileOutputStream(dicomFile), 600000));
    try {
        outStream.writeFileMetaInformation(fileMetaDcmObj);
        dataStream.copyTo(outStream);

    } finally {
        outStream.close();
    }
        dicomFile.renameTo(new File(associationDir, dicomFileBaseName));
        System.out.println("DICOM file name: " + dicomFile.getName());
    }
}

Таким образом, я могу принимать запросы отправки DICOM от клиента (например, Mayam), НО файлы хранятся в плоской структуре в каталоге «rootDirectory» (C: \ XXXXXX \ YYYY \ Development \ AssocDir).

Я пытаюсь получить такую ​​информацию, как StudyID и SeriedID из объекта ассоциации, чтобы создать структуру папок, например root / StudyID / SeriesID / DicmFile из dcmReqObj или dicomFile ... Однако:

dcmReqObj фактически пуст (заполняются только теги AffectedSOPClassUID и AffectedSOPInstanceUID)

Даже если я попытаюсь получить его после: outStream.writeFileMetaInformation (fileMetaDcmObj), тег StudyID еще не заполнен (внутри этого метода) ...

Также в этом методе, если я пытаюсь получить "dicomFile" внутри onCStoreRQ, я могу использовать его только в переходной фазе, когда он еще не является заполненным объектом DICOM ...

Что мне здесь не хватало?


person thanili    schedule 27.10.2014    source источник
comment
Вам удалось это выяснить? Я нахожусь в том же положении, я бы хотел получить данные из dcm4chee в свое Java-приложение (используя dcm4che), поэтому я отправляю c-move в dcm4chee из своего Java-приложения, но не знаю, как настроить прослушиватель ассоциации для обработки входящего запроса c-store, когда dcm4chee хочет отправить мне данные. У вас есть образец кода, который направит меня на верный путь?   -  person tom    schedule 22.05.2018
comment
Если я хорошо помню, я использовал классы DcmRcv и StorageSCP для реализации этого прослушивателя dicom. Например, во время инициализации приложения я проверяю, работает ли приемник dicom; если нет, я запускаю его, используя: setAEtitle (), setHostname (), setPort () для определения адреса вашего слушателя, а затем: setDestination () для определения того, где будут храниться входящие файлы, initTransferCapability () и, наконец, start () для запуска ресивера. Проверьте документацию и примеры для класса DcmRcv   -  person thanili    schedule 22.05.2018


Ответы (2)


Вам нужно будет сделать больше, чем просто использовать класс DcmRcv как есть.

Используйте его как отправную точку, но вы также захотите реализовать

org.dcm4che2.net.AssociationListener

интерфейс для перехвата запросов ассоциации, вместе с

org.dcm4che2.net.service.StorageService

класс для фактической передачи данных.

person cneller    schedule 27.10.2014
comment
Большое спасибо за ответ! Да, это то, о чем я тоже думал. Но есть ли примеры или вы можете привести абстрактный пример такой реализации? Например, возникает вопрос, как мне присоединить слушателя ассоциации к экземпляру dcmrcv? - person thanili; 30.10.2014
comment
В качестве модели можно использовать класс DcmRcv. Добавить интерфейс AssociationListener просто, а затем назначить его AE с помощью NetworkApplicationEntity.addAssociationListener (..) - person cneller; 30.10.2014
comment
Спасибо за ответ ... реализовано таким образом, и теперь я могу отслеживать запросы ассоциации и C-STORE ... Однако все эти запросы ассоциации относятся к запросам на отправку независимых файлов DICOM. Мой клиент DICOM отправляет целые исследования! Есть ли способ отслеживать отправку всего исследования? А затем инициировать последовательность действий? - person thanili; 04.11.2014
comment
У вас должна быть возможность нажать на тесную ассоциацию, ЕСЛИ отправитель отправляет все в одной ассоциации. Если они этого не делают, свяжитесь с продавцом и узнайте, есть ли веская причина для отправки вещей в отдельные ассоциации; часто его нет, и, надеюсь, его можно настроить на открытие ассоциации, отправку всего и последующее закрытие ассоциации. - person cneller; 05.11.2014
comment
Я отмечу, что если от них требуется отправлять ассоциацию для каждого экземпляра или серии, то на самом деле нет конкретного способа определить, когда вы получили все исследование, только по сообщениям ассоциации или хранилища. - person cneller; 05.11.2014
comment
В ПОРЯДКЕ! Благодарность! по крайней мере, как я мог захватить и обработать отдельные файлы dicom после закрытия каждой ассоциации? Я пытаюсь сделать это на уровне внутреннего метода associationClosed, но я не могу понять, как это сделать! Я изменил свой вопрос, чтобы отразить точку, к которой я сейчас отношусь! - person thanili; 06.11.2014
comment
Вы можете получить информацию об исследовании / серии из метода onCStoreReq, чтобы сохранить там, где вам нужно. Он также предоставляет объект Association, чтобы вы могли сопоставить их при получении уведомления associationClosed. Просто следите за тем, какие исследования или каталоги файлов связаны с ассоциацией, а затем производите обработку, когда она закрывается. - person cneller; 06.11.2014
comment
Я пытаюсь получить StudyID из dcmReqObj или dicomFile в конце onCStoreRQ, но соответствующий тег пуст! Однако, если я проверю файловую систему, файлы dicom принимаются и хранятся нормально! Я изменил вопрос, чтобы обозначить точку, в которой я сейчас нахожусь ... - person thanili; 07.11.2014
comment
Объект DicomObject = dataStream.readDataset (); должен доставить вам объект, хранящийся. Вы смотрите в объекте запроса или ответа, а не в фактических данных. - person cneller; 11.11.2014

В вашем сценарии, если использование Java / Dcm4Che не является обязательным, вы можете взглянуть на Orthanc в качестве дополнения к Dcm4che для реализации автоматической маршрутизации DICOM. Orthanc - это легкий сервер DICOM с открытым исходным кодом, который предоставляет возможности создания сценариев: Примеры автоматической маршрутизации DICOM через Lua scripting или через доступны вызовы REST.

person Tisys    schedule 28.10.2014
comment
dcm4che не является обязательным, однако маршрутизатор DICOM, который мы пытаемся создать, является кроссплатформенным нативным приложением (JavaFX и dcm4chee). Поддерживает ли Orthanc такую ​​реализацию? - person thanili; 30.10.2014
comment
Orthanc является кроссплатформенным (Windows, Linux, OS X), и вы можете взаимодействовать с ним с любого компьютерного языка (особенно Java) через его RESTful API. - person Tisys; 30.10.2014