DCMTK DCMScu和DCMScp 细节讨论



Post new topic This topic is locked, you cannot edit posts or make further replies.  [ 65 posts ]  Go to page 12345  Next
Author Message
  Post subject: PACS connection
Post Posted: Mon, 2011-11-07, 12:26 
Offline

Joined: Mon, 2011-04-18, 20:36
Posts: 112
Location: France
Hello everybody, 
I trying to connect my new application to PACS Network. 
I found this code : 

Code:
connection(QString qipAdress, QString qport, QString qaet)
{

T_ASC_Network *net; // network struct, contains DICOM upper layer FSM etc.
//ASC_initializeNetwork(NET_REQUESTOR, 0, 1000 /* timeout */, &net);
ASC_initializeNetwork(NET_REQUESTOR, 104, 1000, &net);

T_ASC_Parameters *params; // parameters of association request
ASC_createAssociationParameters(&params, ASC_DEFAULTMAXPDU);

// set calling and called AE titles
ASC_setAPTitles(params, "ECHOSCU", "ANY-SCP", NULL);

// the DICOM server accepts connections at server.nowhere.com port 104
QString XXX = "server.nowhere.com:"+qport;
ASC_setPresentationAddresses(params, qipAdress, XXX);

// list of transfer syntaxes, only a single entry here
const char* ts[] = { UID_LittleEndianImplicitTransferSyntax };

// add presentation context to association request
ASC_addPresentationContext(params, 1, UID_VerificationSOPClass, ts, 1);

// request DICOM association
T_ASC_Association *assoc;
if (ASC_requestAssociation(net, params, &assoc).good())
{
   QMessageBox::information(0,"","Parametre ok");
   if (ASC_countAcceptedPresentationContexts(params) == 1)
      {
         QMessageBox::information(0,"","Connexion ok");
         // the remote SCP has accepted the Verification Service Class
         DIC_US id = assoc->nextMsgID++; // generate next message ID
         DIC_US status; // DIMSE status of C-ECHO-RSP will be stored here
         DcmDataset *sd = NULL; // status detail will be stored here
         // send C-ECHO-RQ and handle response
         DIMSE_echoUser(assoc, id, DIMSE_BLOCKING, 0, &status, &sd);
         delete sd; // we don't care about status detail
      }
}
ASC_releaseAssociation(assoc); // release association
ASC_destroyAssociation(&assoc); // delete assoc structure
ASC_dropNetwork(&net); // delete net structure
return 0;
}


But I do not understand it. 
What is "server.nowhere.com" ??? 

I suppose that I need to give who I am and where I want to be connected. So, in my example, "server.nowhere.com" could be qipAdress and qipAdress could be my ip adress ? Isn't it ? 

-------- 
And (AFTER), with this code, how I can ask some question to the server and download some Dicom pictures ??

_________________
Respectueusement, 
MitMal
 

Report this post
Top
  Profile  
Reply with quote  
  Post subject:
Post Posted: Mon, 2011-11-07, 12:32 
Offline
OFFIS DICOM Team
OFFIS DICOM Team

Joined: Fri, 2004-11-05, 14:47
Posts: 1153
Location: Oldenburg, Germany
Hi, 

Quote:
I suppose that I need to give who I am and where I want to be connected. So, in my example, "server.nowhere.com" could be qipAdress and qipAdress could be my ip adress ? Isn't it ?


XXX is the server you want to connect to. qipAdress is your own adress. 

This is the  original example in the online documentation

Also, instead, you might use the DcmSCU class which is more object-oriented. An example can be found in our support wiki

Best regards, 
Michael


Report this post
Top
  Profile  
Reply with quote  
  Post subject:
Post Posted: Mon, 2011-11-07, 12:57 
Offline

Joined: Mon, 2011-04-18, 20:36
Posts: 112
Location: France
Thanks Michael, 

But I don't understand : 
With : ASC_setPresentationAddresses(params, "120.40.30.99:104", qipAdress+":"+qport); the connection is failded. 

And with : ASC_setPresentationAddresses(params, qipAdress+":"+qport, "120.40.30.99:104"); the connection is done. 

(I mine when it is done, I can read the ok message) 

I will test now with your second option, the class DcmSCU, and I go back to keep you inform 

*************** 
As for me, if I switch the two parameter, my ip address, and the server, the connection is done even if the network is broken. So maybe something listen on my computer, sorry...

_________________
Respectueusement, 
MitMal
 

Last edited by Mitmal on Mon, 2011-11-07, 13:25, edited 1 time in total. 

Report this post
Top
  Profile  
Reply with quote  
  Post subject:
Post Posted: Mon, 2011-11-07, 13:11 
Offline

Joined: Mon, 2011-04-18, 20:36
Posts: 112
Location: France
And just before, can you explain to me what this line mines: 
ASC_initializeNetwork(NET_REQUESTOR, 0, 1000 /* timeout */, &net); 

0 is it my port or the server port ?

_________________
Respectueusement, 
MitMal
 

Report this post
Top
  Profile  
Reply with quote  
  Post subject:
Post Posted: Mon, 2011-11-07, 13:51 
Offline
OFFIS DICOM Team
OFFIS DICOM Team

Joined: Fri, 2004-11-05, 14:47
Posts: 1153
Location: Oldenburg, Germany
Looking into the header file: 
Code:
/** network instance creation function (constructor)
*  @param role association acceptor, requestor or both
*  @param acceptorPort acceptor port for incoming connections.
*    For association requestors, zero should be passed here.
*  @param timeout timeout for network operations, in seconds
*  @param network T_ASC_Network will be allocated and returned in this parameter
*  @param options network options. Only DUL_FULLDOMAINNAME is currently defined
*    as a possible option.
*  @return EC_Normal if successful, an error code otherwise
*/
OFCondition ASC_initializeNetwork(
    T_ASC_NetworkRole role,
    int acceptorPort,
    int timeout,
    T_ASC_Network ** network,
    unsigned long options = 0);


Report this post
Top
  Profile  
Reply with quote  
  Post subject:
Post Posted: Mon, 2011-11-07, 13:54 
Offline

Joined: Mon, 2011-04-18, 20:36
Posts: 112
Location: France
Of course, thank you, know I will look every time in the header  ;-)

_________________
Respectueusement, 
MitMal
 

Report this post
Top
  Profile  
Reply with quote  
  Post subject:
Post Posted: Tue, 2011-11-08, 12:06 
Offline

Joined: Mon, 2011-04-18, 20:36
Posts: 112
Location: France
I trying to use the DcmSCU example, but I don't understand this part : 
Code:
int MedicTool2::connectionPacs(QString serverIpAdress, QString serverPort, QString serverAet, QString myIpAdress, QString myPort, QString myAet)
{
   QProgressDialog progressDialog ("Connecting\nPlease wait...",QString(),0,100);
   progressDialog.setWindowModality(Qt::WindowModal);
   progressDialog.show();

   /* Setup DICOM connection parameters */
   OFLog::configure(OFLogger::DEBUG_LOG_LEVEL);
   DcmTestSCU scu;
progressDialog.setValue(10);

   // set AE titles
   OFString ipAdresse = serverIpAdress;
   Uint16 port = serverPort.toUInt();
   OFString aet = serverAet;

   scu.setAETitle("TEST-SCU" );
   scu.setPeerHostName(ipAdresse);
   scu.setPeerPort(port);
   scu.setPeerAETitle(aet);


In setAETitle, setPeerHostName, setPeerPort, setPeerAETitle what kind of information I need to give ?


**********************
After looking in the header file , I saw:
Code:
/** Set SCU's AETitle to be used in association negotiation
   *  @param myAETtitle [in] The SCU's AETitle to be used
   */
  void setAETitle(const OFString &myAETtitle);

  /** Set SCP's host (hostname or IP address) to talk to in association negotiation
   *  @param peerHostName [in] The SCP's hostname or IP address to be used
   */
  void setPeerHostName(const OFString &peerHostName);

  /** Set SCP's AETitle to talk to in association negotiation
   *  @param peerAETitle [in] The SCP's AETitle to be used
   */
  void setPeerAETitle(const OFString &peerAETitle);


So I add this lines :
Code:
// set AE titles
   OFString OFmyAet = myAet;
   OFString OFipAdresse = serverIpAdress;
   Uint16 OFport = serverPort.toUInt();
   OFString OFaet = serverAet;

   scu.setAETitle(OFmyAet);
   scu.setPeerHostName(OFipAdresse);
   scu.setPeerPort(OFport);
   scu.setPeerAETitle(OFaet);


But the process failed, I can read the display 40 but after it's write "Unable to negotiate association: " :
Code:
   /* Initialize network */ 
   OFCondition result = scu.initNetwork(); 
   if (result.bad()) 
   { 
      QMessageBox::information(0,"","Unable to set up the network: ");
      return 1; 
   }
progressDialog.setValue(40);

   /* Negotiate Association */ 
   result = scu.negotiateAssociation(); 
   if (result.bad()) 
   {
      QMessageBox::information(0,"","Unable to negotiate association: "); 
      return 1; 
   }
progressDialog.setValue(50);


I will search how to add the result.text() but maybe have you some ideas ?

_________________
Respectueusement, 
MitMal
 

Report this post
Top
  Profile  
Reply with quote  
  Post subject:
Post Posted: Tue, 2011-11-08, 12:26 
Offline

Joined: Mon, 2011-04-18, 20:36
Posts: 112
Location: France
The message is : 
Quote:
Unable to negociate association: DUL Association Rejected


Can you explain me what is it ? 


*********************** 
Ok, it was my fault (logically), i was make a fault in my AETitle...lol

_________________
Respectueusement, 
MitMal
 

Report this post
Top
  Profile  
Reply with quote  
  Post subject:
Post Posted: Tue, 2011-11-08, 15:14 
Offline

Joined: Mon, 2011-04-18, 20:36
Posts: 112
Location: France
Great, now I can run a ECHO test on my connection to the PACS. 
Now I need to search (name, first name, number, date ...) and after download the images on my hard drive. 

Do you know how to do this?

_________________
Respectueusement, 
MitMal
 

Report this post
Top
  Profile  
Reply with quote  
  Post subject:
Post Posted: Tue, 2011-11-08, 15:21 
Offline

Joined: Mon, 2011-04-18, 20:36
Posts: 112
Location: France
For those who are interested, my function ECHO is : 
Code:
/***
Connexion et tentative de requete ECHO vers le noeud DICOM spécifié
-serverIpAdress represente l'adresse IP nécéssaire à la connexion
-serverPort represente le numero du port nécéssaire à la connexion, coté serveur
-serverAet represente l'AET nécéssaire à la connexion
-monIpAdress represente l'adresse IP de la machine
-monPort represente le numero du port nécéssaire à la connexion coté client
-monAet represente l'AET de la machine
*/
bool MedicTool2::echoDicomNode(QString serverIpAdress, QString serverPort, QString serverAet, QString monIpAdress, QString monPort, QString monAet)
{
   QProgressDialog progressDialog ("Connexion ECHO en cours\nVeuillez patienter...",QString(),0,60);
   progressDialog.setWindowModality(Qt::WindowModal);
   progressDialog.show();

   //Mise en place des parametre pour établire la connexion DICOM
   OFLog::configure(OFLogger::DEBUG_LOG_LEVEL);
   DcmTestSCU scu;
progressDialog.setValue(10);

   //Mise en place des parametres AET
   OFString OFmonAet = monAet;            scu.setAETitle(OFmonAet);
   OFString OFipAdresse = serverIpAdress;   scu.setPeerHostName(OFipAdresse);
   Uint16 OFport = serverPort.toUInt();   scu.setPeerPort(OFport);
   OFString OFaet = serverAet;            scu.setPeerAETitle(OFaet);
progressDialog.setValue(20);

   //Utilisation du contexte de présentation FIND / MOVE dans la racine des series, pour proposer toutes les syntaxes de transfert compressées (Use presentation context for FIND/MOVE in study root, propose all uncompressed transfer syntaxes)
   OFList<OFString> ts; 
   ts.push_back(UID_LittleEndianExplicitTransferSyntax); 
   ts.push_back(UID_BigEndianExplicitTransferSyntax); 
   ts.push_back(UID_LittleEndianImplicitTransferSyntax); 
   scu.addPresentationContext(UID_FINDStudyRootQueryRetrieveInformationModel, ts); 
   scu.addPresentationContext(UID_MOVEStudyRootQueryRetrieveInformationModel, ts); 
   scu.addPresentationContext(UID_VerificationSOPClass, ts);
progressDialog.setValue(30);

   //Initialisation du reseau
   OFCondition result = scu.initNetwork(); 
   if (result.bad()) 
   {//PROBLEME DE CONNEXION
      QString add = result.text();
      QMessageBox::information(0,"Test ECHO","TENTATIVE DE CONNEXION :\nJe suis : "+monIpAdress+":"+monPort+" ("+monAet+")\nEt je veux parler à : "+serverIpAdress+":"+serverPort+" ("+serverAet+")\n\nImpossible d'initialiser le reseau: "+add);
      return false; 
   }
progressDialog.setValue(40);

   //TENTATIVE D'ASSOCIATION
   result = scu.negotiateAssociation(); 
   if (result.bad()) 
   {//PROBLEME D'IDENTIFICATION
      QString add = result.text();
      QMessageBox::information(0,"Test ECHO","TENTATIVE DE CONNEXION :\nJe suis : "+monIpAdress+":"+monPort+" ("+monAet+")\nEt je veux parler à : "+serverIpAdress+":"+serverPort+" ("+serverAet+")\n\nImpossible de negocier l'association: "+add);
      return false; 
   }
progressDialog.setValue(50);

   //Voyons si le serveur est en écoute: Contruction et envoi d'une demande C-ECHO (Let's look whether the server is listening: Assemble and send C-ECHO request)
   result = scu.sendECHORequest(0); 
   if (result.bad()) 
   {//PROBLEME, LE SERVER NE REPOND PAS
      QString add = result.text();
      QMessageBox::information(0,"Test ECHO","TENTATIVE DE CONNEXION :\nJe suis : "+monIpAdress+":"+monPort+" ("+monAet+")\nEt je veux parler à : "+serverIpAdress+":"+serverPort+" ("+serverAet+")\n\nImpossible d'utiliser le processus E-ECHO avec le serveur: "+add);
      return false;
   }
   else return true;
progressDialog.setValue(60);
   return false;
}


I am looking how to add a specific request now, may it be here, right?
Code:
//Construction et envoi d'une requete C-FIND, pour trouver les examens
   FINDResponses findResponses; 
   DcmDataset req; 
   req.putAndInsertOFStringArray(DCM_QueryRetrieveLevel, "STUDY");
   req.putAndInsertOFStringArray(DCM_StudyInstanceUID, "DUMONT^NICOLAS"); 
   T_ASC_PresentationContextID presID = findUncompressedPC(UID_FINDStudyRootQueryRetrieveInformationModel, scu);
   if (presID == 0) 
   {//PROBLEME avec le contexte de présentation
      QMessageBox::information(0,"CONNEXION","TENTATIVE DE CONNEXION :\nJe suis : "+monIpAdress+":"+monPort+" ("+monAet+")\nEt je veux parler à : "+serverIpAdress+":"+serverPort+" ("+serverAet+")\n\nIl n'y a pas de contexte de présentation non compressé pour Study Root FIND");
      return 1; 
   }


But that does not work ... I am looking for, if you have ideas  :wink:

_________________
Respectueusement, 
MitMal
 

Report this post
Top
  Profile  
Reply with quote  
  Post subject:
Post Posted: Tue, 2011-11-08, 15:23 
Offline

Joined: Mon, 2011-04-18, 20:36
Posts: 112
Location: France
Problem, I have FINDResponses but I do not have MOVEResponses...do you know why ????  :cry:

_________________
Respectueusement, 
MitMal
 

Report this post
Top
  Profile  
Reply with quote  
  Post subject:
Post Posted: Tue, 2011-11-08, 19:00 
Offline

Joined: Mon, 2011-04-18, 20:36
Posts: 112
Location: France
I tested with: 
Code:
req.putAndInsertOFStringArray(DCM_QueryRetrieveLevel, "STUDY");
req.putAndInsertOFStringArray(DCM_StudyInstanceUID, "");
   
req.putAndInsertOFStringArray(DCM_PatientName, "DUMONT");
req.putAndInsertOFStringArray(DCM_Modality, "CT");
req.putAndInsertOFStringArray(DCM_PatientID,"001578802");


But that does not seem correct. The results are not correct in with my PACS data (when I use an other viewer)

Can you tell me if this is the right approach?
I want to search according to some criteria:
- Patient's name
- The patient's first name (or name and surname together)
- modality
- Earlier
- Date posterior
- And also the type of sequence can be (but it may be difficult)


************************
Here is my code now:

Code:
//Construction et envoi d'une requete C-FIND, pour trouver les examens
   FINDResponses findResponses;
   DcmDataset req;
   req.putAndInsertOFStringArray(DCM_QueryRetrieveLevel, "SERIES");
   //req.putAndInsertOFStringArray(DCM_StudyInstanceUID, "");
   
   QString nom = "RADERANIRINA Sendrison";
   nom.replace(" ","^");
   OFString OFNom = nom;
   req.putAndInsertOFStringArray(DCM_PatientName, OFNom);
   //req.putAndInsertOFStringArray(DCM_Modality, "CT");
   //req.putAndInsertOFStringArray(DCM_PatientID,"001578802");


The search takes me back out the number 10, which corresponds to the number of series to my patients the on PACS. 
Only now I wish I could find the patient starting with a beginning, or have a string in their name. 
A little like in SQL, when I try using% xxx% 

Do you know how to do this?

_________________
Respectueusement, 
MitMal
 

Report this post
Top
  Profile  
Reply with quote  
  Post subject:
Post Posted: Wed, 2011-11-09, 11:38 
Offline
OFFIS DICOM Team
OFFIS DICOM Team

Joined: Fri, 2004-11-05, 14:47
Posts: 1153
Location: Oldenburg, Germany
Hi, 

Quote:
Problem, I have FINDResponses but I do not have MOVEResponses...do you know why ????


Maybe you have a version installed that is not depending on the latest snapshots? See also note at the end of the  DcmSCU example on the wiki.

Quote:
Can you tell me if this is the right approach?


Query/Retrieve requests need to follow specific rules, laid down in part 4 of the DICOM standard. I explained the most basic ones several times in the forum; please try to understand by reading the standard and searching the forum. 

Best regards, 
Michael 

P.S: Sorry to interrupt your thread  :-)


Report this post
Top
  Profile  
Reply with quote  
  Post subject:
Post Posted: Wed, 2011-11-09, 12:53 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 DCMTK 库读取 DICOM 文件需要进行以下步骤: 1. 引入 DCMTK 库 在 QT 项目中引入 DCMTK 库,可以通过在项目文件中添加以下代码引入静态库: ``` LIBS += -L/path/to/dcmtk/lib -ldcmdata -loflog -lofstd -li2d -ldcmimage -lzlib -lpng -ltiff ``` 注意:需要将 /path/to/dcmtk/lib 替换为 DCMTK 库的安装路径。 2. 初始化 DCMTK 库 在 QT 代码中,需要先初始化 DCMTK 库,可以在 main 函数中添加以下代码: ``` #include <dcmtk/config/osconfig.h> #include <dcmtk/dcmdata/dctk.h> int main(int argc, char *argv[]) { // 初始化 DCMTK 库 DcmInitialize(argc, argv); ... } ``` 3. 读取 DICOM 文件 使用 DCMTK 库读取 DICOM 文件可以使用 DcmFileFormat 类,以下是一个示例代码: ``` #include <dcmtk/config/osconfig.h> #include <dcmtk/dcmdata/dctk.h> void readDICOM(const char* filename) { // 创建 DcmFileFormat 对象 DcmFileFormat fileformat; // 读取 DICOM 文件到 DcmFileFormat 对象中 OFCondition status = fileformat.loadFile(filename); if (!status.good()) { qDebug() << "Failed to read DICOM file"; return; } // 获取 DICOM 数据集 DcmDataset* dataset = fileformat.getDataset(); // 获取 DICOM 图像数据 Uint16 *pixelData; dataset->findAndGetUint16Array(DCM_PixelData, pixelData); // 获取 DICOM 图像大小 Uint16 rows, cols; dataset->findAndGetUint16(DCM_Rows, rows); dataset->findAndGetUint16(DCM_Columns, cols); } ``` 上述代码中,首先创建 DcmFileFormat 对象,然后使用 loadFile() 方法读取 DICOM 文件,如果读取成功,则可以使用 getDataset() 方法获取 DICOM 数据集,使用 findAndGetUint16Array() 方法获取图像数据,使用 findAndGetUint16() 方法获取图像大小。 注意:DCMTK 库使用 C++98 标准,因此需要在 QT 项目中添加 -std=c++98 编译选项。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值