java - 从 dcm4che2 迁移到 dcm4che3

标签 java dcm4che

我使用了下面提到的来自这个存储库的 dcm4che2 API http://www.dcm4che.org/maven2/dcm4che/在我的 java 项目中。

dcm4che-core-2.0.29.jar

org.dcm4che2.data.DicomObject  
org.dcm4che2.io.StopTagInputHandler  
org.dcm4che2.data.BasicDicomObject  
org.dcm4che2.data.UIDDictionary  
org.dcm4che2.data.DicomElement  
org.dcm4che2.data.SimpleDcmElement  
org.dcm4che2.net.service.StorageCommitmentService  
org.dcm4che2.util.CloseUtils  

dcm4che-net-2.0.29.jar

org.dcm4che2.net.CommandUtils  
org.dcm4che2.net.ConfigurationException  
org.dcm4che2.net.NetworkApplicationEntity  
org.dcm4che2.net.NetworkConnection  
org.dcm4che2.net.NewThreadExecutor  
org.dcm4che3.net.service.StorageService  
org.dcm4che3.net.service.VerificationService  

目前我想迁移到 dcm4che3,但是在我从这个存储库下载的 dcm4che3 中找不到上面列出的 API http://sourceforge.net/projects/dcm4che/files/dcm4che3/
您能否指导我使用其他方法?

最佳答案

正如您已经观察到的那样,BasicDicomObject 已成为历史——与许多其他对象一样。

新的“Dicom 对象”是属性——对象是属性的集合。

因此,您创建属性,用 RQ 行为(C-FIND 等)所需的标签填充它们,您得到的返回是另一个属性对象,您可以从中提取所需的标签。

在我看来,dcm4che 2.x 在处理单个值表示的主题上含糊不清。 dcm4che 3.x 更清晰一些。

迁移要求重写有关查询方式和处理单个标签的代码。另一方面,dcm4che 3.x 使新代码不那么复杂。

根据要求,我添加了与某些服务类提供商 (SCP) 的连接的初始设置:

// Based on org.dcm4che:dcm4che-core:5.25.0 and org.dcm4che:dcm4che-net:5.25.0
import org.dcm4che3.data.*;
import org.dcm4che3.net.*;
import org.dcm4che3.net.pdu.AAssociateRQ;
import org.dcm4che3.net.pdu.PresentationContext;
import org.dcm4che3.net.pdu.RoleSelection;
import org.dcm4che3.net.pdu.UserIdentityRQ;


// Client side representation of the connection. As a client, I will 
// not be listening for incoming traffic (but I could choose to do so
// if I need to transfer data via MOVE)
Connection local = new Connection();
local.setHostname("client.on.network.com");
local.setPort(Connection.NOT_LISTENING);

// Remote side representation of the connection
Connection remote = new Connection();
remote.setHostname("pacs.on.network.com");
remote.setPort(4100);

remote.setTlsProtocols(local.getTlsProtocols());
remote.setTlsCipherSuites(local.getTlsCipherSuites());

// Calling application entity
ApplicationEntity ae = new ApplicationEntity("MeAsAServiceClassUser".toUpperCase());
ae.setAETitle("MeAsAServiceClassUser");
ae.addConnection(local); // on which we may not be listening
ae.setAssociationInitiator(true);
ae.setAssociationAcceptor(false);

// Device
Device device = new Device("MeAsAServiceClassUser".toLowerCase());
device.addConnection(local);
device.addApplicationEntity(ae);

// Configure association
AAssociateRQ rq = new AAssociateRQ();
rq.setCallingAET("MeAsAServiceClassUser");
rq.setCalledAET("NameThatIdentifiesTheProvider"); // e.g. "GEPACS"
rq.setImplVersionName("MY-SCU-1.0"); // Max 16 chars

// Credentials (if appropriate)
String username = "username";
String passcode = "so secret";
if (null != username && username.length() > 0 && null != passcode && passcode.length() > 0) {
    rq.setUserIdentityRQ(UserIdentityRQ.usernamePasscode(username, passcode.toCharArray(), true));
}

例如,ping PACS(使用上面的设置):

String[] TRANSFER_SYNTAX_CHAIN = {
        UID.ExplicitVRLittleEndian,
        UID.ImplicitVRLittleEndian
};

// Define transfer capabilities for verification SOP class
ae.addTransferCapability(
        new TransferCapability(null,
            /* SOP Class */ UID.Verification,
            /* Role */ TransferCapability.Role.SCU,
            /* Transfer syntax */ TRANSFER_SYNTAX_CHAIN)
);

// Setup presentation context
rq.addPresentationContext(
        new PresentationContext(
                rq.getNumberOfPresentationContexts() * 2 + 1,
                /* abstract syntax */ UID.Verification,
                /* transfer syntax */ TRANSFER_SYNTAX_CHAIN
        )
);

rq.addRoleSelection(new RoleSelection(UID.Verification, /* is SCU? */ true, /* is SCP? */ false));

try {
    // 1) Open a connection to the SCP
    Association association = ae.connect(local, remote, rq);

    // 2) PING!
    DimseRSP rsp = association.cecho();
    rsp.next(); // Consume reply, which may fail

    // Still here? Success!
    // 3) Close the connection to the SCP
    if (as.isReadyForDataTransfer()) {
        as.waitForOutstandingRSP();
        as.release();
    }
} catch (Throwable ignore) {
    // Failure
}

另一个例子,从给定登录号的 PACS 中检索研究;设置查询并处理结果:

String modality = null; // e.g. "OT"
String accessionNumber = "1234567890";

//--------------------------------------------------------
// HERE follows setup of a query, using an Attributes object
//--------------------------------------------------------
Attributes query = new Attributes();

// Indicate character set
{
    int tag = Tag.SpecificCharacterSet;
    VR vr = ElementDictionary.vrOf(tag, query.getPrivateCreator(tag));
    query.setString(tag, vr, "ISO_IR 100");
}

// Study level query
{
    int tag = Tag.QueryRetrieveLevel;
    VR vr = ElementDictionary.vrOf(tag, query.getPrivateCreator(tag));
    query.setString(tag, vr, "STUDY");
}

// Accession number
{
    int tag = Tag.AccessionNumber;
    VR vr = ElementDictionary.vrOf(tag, query.getPrivateCreator(tag));
    query.setString(tag, vr, accessionNumber);
}

// Optionally filter on modality in study if 'modality' is provided,
// otherwise retrieve modality
{
    int tag = Tag.ModalitiesInStudy;
    VR vr = ElementDictionary.vrOf(tag, query.getPrivateCreator(tag));
    if (null != modality && modality.length() > 0) {
        query.setString(tag, vr, modality);
    } else {
        query.setNull(tag, vr);
    }
}

// We are interested in study instance UID
{
    int tag = Tag.StudyInstanceUID;
    VR vr = ElementDictionary.vrOf(tag, query.getPrivateCreator(tag));
    query.setNull(tag, vr);
}

// Do the actual query, needing an AppliationEntity (ae),
// a local (local) and remote (remote) Connection, and
// an AAssociateRQ (rq) set up earlier.

try {
    // 1) Open a connection to the SCP
    Association as = ae.connect(local, remote, rq);

    // 2) Query
    int priority = 0x0002; // low for the sake of demo :)
    as.cfind(UID.StudyRootQueryRetrieveInformationModelFind, priority, query, null,
            new DimseRSPHandler(as.nextMessageID()) {

                @Override
                public void onDimseRSP(Association assoc, Attributes cmd,
                                       Attributes response) {

                    super.onDimseRSP(assoc, cmd, response);

                    int status = cmd.getInt(Tag.Status, -1);
                    if (Status.isPending(status)) {
                        //--------------------------------------------------------
                        // HERE follows handling of the response, which
                        // is just another Attributes object
                        //--------------------------------------------------------
                        String studyInstanceUID = response.getString(Tag.StudyInstanceUID);
                        // etc...
                    }
                }
            });

    // 3) Close the connection to the SCP
    if (as.isReadyForDataTransfer()) {
        as.waitForOutstandingRSP();
        as.release();
    }
}
catch (Exception e) {
    // Failure
}

https://github.com/FrodeRanders/dicom-tools 上有更多相关信息

关于java - 从 dcm4che2 迁移到 dcm4che3,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31728477/

相关文章:

java - Spring 和 Hibernate 的延迟加载

java - 如何用 Java 读取 DICOM 文件的内容?

java - 如何在 Java 中使用 dcm4che3 创建 DICOM MWL 查询?

java - 错误 : Could not find or load main class org. antlr.Tool

java - "Cannot start compilation: the output path is not specified for module..."

dicom - 如何修改存储的dcm文件

servlets - Java Servlet 和 ImageIO 错误

java - 在 onCStoreRQ 关联请求上读取 PDVInputStream dicomObject 信息

java - WebLogic 版本 12.2.1.1 及更高版本上的 "ClassNotFoundException: org.objectweb.asm.ClassVisitor"(文档 ID 2526226.1)

java - 动态创建接口(interface)/抽象类的对象实例