瀏覽代碼

More support for DICOM Query.

Added sendFINDRequest to DcmSCU class in DCMTK.  Using this new functionality to query a DICOM image store.  Added sample application (Applications/ctkDICOMQuery.cpp) to demonstrate C-FIND commands over the network.
Daniel Blezek 15 年之前
父節點
當前提交
44c399abf3

+ 45 - 0
Applications/ctkDICOMQuery/CMakeLists.txt

@@ -0,0 +1,45 @@
+PROJECT(ctkDICOMQuery)
+
+#
+# See CTK/CMake/ctkMacroBuildApp.cmake for details
+#
+  
+# Source files
+SET(KIT_SRCS
+  ctkDICOMQuery.cpp
+  )
+
+# Headers that should run through moc
+SET(KIT_MOC_SRCS
+  )
+
+# UI files
+SET(KIT_UI_FORMS
+)
+
+# Resources
+SET(KIT_resources
+)
+
+# Target libraries - See CMake/ctkMacroGetTargetLibraries.cmake
+# The following macro will read the target libraries from the file 'target_libraries.cmake'
+ctkMacroGetTargetLibraries(KIT_target_libraries)
+
+# Additional directories to include - Not that CTK_INCLUDE_LIBRARIES is already included
+SET(KIT_include_directories
+  )
+
+ctkMacroBuildApp(
+  NAME ${PROJECT_NAME}
+  INCLUDE_DIRECTORIES ${KIT_include_directories}
+  SRCS ${KIT_SRCS}
+  MOC_SRCS ${KIT_MOC_SRCS}
+  UI_FORMS ${KIT_UI_FORMS}
+  TARGET_LIBRARIES ${KIT_target_libraries}
+  RESOURCES ${KIT_resources}
+  )
+
+# Testing
+IF(BUILD_TESTING)
+  #ADD_SUBDIRECTORY(Testing)
+ENDIF(BUILD_TESTING)

+ 92 - 0
Applications/ctkDICOMQuery/ctkDICOMQuery.cpp

@@ -0,0 +1,92 @@
+/*=========================================================================
+
+  Library:   CTK
+ 
+  Copyright (c) 2010  Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ 
+=========================================================================*/
+
+// Qt includes
+#include <QApplication>
+#include <QTextStream>
+
+// CTK includes
+#include <ctkDICOMQuery.h>
+#include <ctkDICOM.h>
+#include "ctkLogger.h"
+
+// STD includes
+#include <cstdlib>
+#include <iostream>
+#include <fstream>
+
+void print_usage()
+{
+  std::cerr << "Usage:\n";
+  std::cerr << "  ctkDICOMQuery callingAETitle calledAETitle host port\n";
+  return;
+}
+
+
+/**
+  *
+*/
+int main(int argc, char** argv)
+{
+  ctkLogger::configure();
+  ctkLogger logger ( "org.commontk.core.Logger" );
+  logger.setDebug();
+
+  if ( logger.isDebugEnabled() )
+    {
+    std::cout << "Debugging" << std::endl;
+    }
+
+  if (argc < 4)
+  {
+    print_usage();
+    return EXIT_FAILURE;
+  }
+
+  QApplication app(argc, argv);
+  QTextStream out(stdout);
+
+  ctkDICOMQuery query;
+
+  query.setCallingAETitle ( QString ( argv[1] ) );
+  query.setCalledAETitle ( QString ( argv[2] ) );
+  query.setHost ( QString ( argv[3] ) );
+  int port;
+  bool ok;
+  port = QString ( argv[4] ).toInt ( &ok );
+  if ( !ok )
+    {
+    std::cerr << "Could not convert " << argv[4] << " to an integer" << std::endl;
+    print_usage();
+    return EXIT_FAILURE;
+    }
+  query.setPort ( port );
+
+  try
+    {
+    QSqlDatabase db;
+    query.query ( db );
+    }
+  catch (std::exception e)
+  {
+    return EXIT_FAILURE;
+  }
+  return EXIT_SUCCESS;
+}

+ 9 - 0
Applications/ctkDICOMQuery/target_libraries.cmake

@@ -0,0 +1,9 @@
+#
+# See CMake/ctkMacroGetTargetLibraries.cmake
+# 
+# This file should list the libraries required to build the current CTK application.
+# 
+
+SET(target_libraries
+  CTKDICOMCore
+  )

+ 61 - 2
Libs/DICOM/Core/ctkDICOMQuery.cpp

@@ -65,6 +65,8 @@ public:
   QString Host;
   int Port;
   DcmSCU SCU;
+  QSqlDatabase db;
+  DcmDataset* query;
 
 };
 
@@ -74,11 +76,26 @@ public:
 //------------------------------------------------------------------------------
 ctkDICOMQueryPrivate::ctkDICOMQueryPrivate()
 {
+  query = new DcmDataset();
 }
 
 //------------------------------------------------------------------------------
 ctkDICOMQueryPrivate::~ctkDICOMQueryPrivate()
 {
+  delete query;
+}
+
+
+// Find callback
+static void QueryCallback (void *callbackData, 
+                           T_DIMSE_C_FindRQ* /*request*/, 
+                           int /*responseCount*/, 
+                           T_DIMSE_C_FindRSP* /*rsp*/, 
+                           DcmDataset *responseIdentifiers) {
+  ctkDICOMQueryPrivate* d = (ctkDICOMQueryPrivate*) callbackData;
+  OFString StudyDescription;
+  responseIdentifiers->findAndGetOFString ( DCM_StudyDescription, StudyDescription );
+  logger.debug ( QString ( "Found study description: " ) + QString ( StudyDescription.c_str() ) );
 }
 
 //------------------------------------------------------------------------------
@@ -142,8 +159,8 @@ int ctkDICOMQuery::port()
 void ctkDICOMQuery::query(QSqlDatabase database )
 {
   CTK_D(ctkDICOMQuery);
-  QSqlDatabase db = database;
-
+  d->db = database;
+  
   if ( logger.isDebugEnabled() )
     {
     std::cout << "Debugging ctkDICOMQuery" << std::endl;
@@ -179,6 +196,48 @@ void ctkDICOMQuery::query(QSqlDatabase database )
     {
     std::cerr << "ECHO Failed" << std::endl;
     }
+  // Clear the query
+  unsigned long elements = d->query->card();
+  // Clean it out
+  for ( unsigned long i = 0; i < elements; i++ ) 
+    {
+    d->query->remove ( (unsigned long) 0 );
+    }
+  d->query->insertEmptyElement ( DCM_QueryRetrieveLevel );
+  d->query->insertEmptyElement ( DCM_PatientID );
+  d->query->insertEmptyElement ( DCM_PatientsName );
+  d->query->insertEmptyElement ( DCM_PatientsBirthDate );
+  d->query->insertEmptyElement ( DCM_StudyID );
+  d->query->insertEmptyElement ( DCM_StudyInstanceUID );
+  d->query->insertEmptyElement ( DCM_StudyDescription );
+  d->query->insertEmptyElement ( DCM_StudyDate );
+  d->query->insertEmptyElement ( DCM_StudyID );
+  d->query->insertEmptyElement ( DCM_PatientID );
+  d->query->insertEmptyElement ( DCM_PatientsName );
+  d->query->insertEmptyElement ( DCM_SeriesNumber );
+  d->query->insertEmptyElement ( DCM_SeriesDescription );
+  d->query->insertEmptyElement ( DCM_StudyInstanceUID );
+  d->query->insertEmptyElement ( DCM_SeriesInstanceUID );
+  d->query->insertEmptyElement ( DCM_StudyTime );
+  d->query->insertEmptyElement ( DCM_SeriesDate );
+  d->query->insertEmptyElement ( DCM_SeriesTime );
+  d->query->insertEmptyElement ( DCM_Modality );
+  d->query->insertEmptyElement ( DCM_ModalitiesInStudy );
+  d->query->insertEmptyElement ( DCM_AccessionNumber );
+  d->query->insertEmptyElement ( DCM_NumberOfSeriesRelatedInstances ); // Number of images in the series
+  d->query->insertEmptyElement ( DCM_NumberOfStudyRelatedInstances ); // Number of images in the series
+  d->query->insertEmptyElement ( DCM_NumberOfStudyRelatedSeries ); // Number of images in the series
+  d->query->putAndInsertString ( DCM_QueryRetrieveLevel, "STUDY" );
+
+  OFCondition status = d->SCU.sendFINDRequest ( 0, d->query, QueryCallback, (void*)d );
+  if ( status.good() )
+    {
+    logger.debug ( "Find succeded" );
+    }
+  else
+    {
+    logger.error ( "Find failed" );
+    }
   d->SCU.closeAssociation ( DUL_PEERREQUESTEDRELEASE );
 }