changeset 2208:90ea60bee5ff

New metadata automatically computed at the instance level: "SopClassUid"
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 09 Dec 2016 14:48:31 +0100
parents 6dc3bdb4088b
children e3fd5bc429a2
files NEWS OrthancServer/OrthancFindRequestHandler.cpp OrthancServer/ServerEnumerations.cpp OrthancServer/ServerEnumerations.h OrthancServer/ServerIndex.cpp Resources/Configuration.json TODO UnitTestsSources/ServerIndexTests.cpp
diffstat 8 files changed, 59 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Fri Dec 09 11:24:04 2016 +0100
+++ b/NEWS	Fri Dec 09 14:48:31 2016 +0100
@@ -6,7 +6,7 @@
 
 * Handling of private tags/creators in the "Dictionary" configuration option
 * New configuration options: "LoadPrivateDictionary", "DicomScuTimeout" and "DicomScpTimeout"
-* New metadata automatically computed at the instance level: "TransferSyntax"
+* New metadata automatically computed at the instance level: "TransferSyntax" and "SopClassUid"
 
 REST API
 --------
--- a/OrthancServer/OrthancFindRequestHandler.cpp	Fri Dec 09 11:24:04 2016 +0100
+++ b/OrthancServer/OrthancFindRequestHandler.cpp	Fri Dec 09 14:48:31 2016 +0100
@@ -107,10 +107,34 @@
   }
 
 
-  static void ExtractTagFromInstances(std::set<std::string>& target,
-                                      ServerContext& context,
-                                      const DicomTag& tag,
-                                      const std::list<std::string>& instances)
+  static bool ExtractMetadata(std::set<std::string>& target,
+                              ServerIndex& index,
+                              MetadataType metadata,
+                              const std::list<std::string>& resources)
+  {
+    for (std::list<std::string>::const_iterator
+           it = resources.begin(); it != resources.end(); ++it)
+    {
+      std::string value;
+      if (index.LookupMetadata(value, *it, metadata))
+      {
+        target.insert(value);
+      }
+      else
+      {
+        // This metadata is unavailable for some resource, give up
+        return false;
+      }
+    }
+
+    return true;
+  }  
+
+
+  static void ExtractTagFromInstancesOnDisk(std::set<std::string>& target,
+                                            ServerContext& context,
+                                            const DicomTag& tag,
+                                            const std::list<std::string>& instances)
   {
     // WARNING: This function is slow, as it reads the JSON file
     // summarizing each instance of interest from the hard drive.
@@ -226,10 +250,16 @@
 
     if (query.HasTag(DICOM_TAG_SOP_CLASSES_IN_STUDY))
     {
-      if (Configuration::GetGlobalBoolParameter("AllowFindSopClassesInStudy", false))
+      std::set<std::string> values;
+
+      if (ExtractMetadata(values, index, MetadataType_Instance_SopClassUid, instances))
       {
-        std::set<std::string> values;
-        ExtractTagFromInstances(values, context, DICOM_TAG_SOP_CLASS_UID, instances);
+        // The metadata "SopClassUid" is available for each of these instances
+        StoreSetOfStrings(result, DICOM_TAG_SOP_CLASSES_IN_STUDY, values);
+      }
+      else if (Configuration::GetGlobalBoolParameter("AllowFindSopClassesInStudy", false))
+      {
+        ExtractTagFromInstancesOnDisk(values, context, DICOM_TAG_SOP_CLASS_UID, instances);
         StoreSetOfStrings(result, DICOM_TAG_SOP_CLASSES_IN_STUDY, values);
       }
       else
--- a/OrthancServer/ServerEnumerations.cpp	Fri Dec 09 11:24:04 2016 +0100
+++ b/OrthancServer/ServerEnumerations.cpp	Fri Dec 09 14:48:31 2016 +0100
@@ -65,6 +65,7 @@
     dictMetadataType_.Add(MetadataType_LastUpdate, "LastUpdate");
     dictMetadataType_.Add(MetadataType_Instance_Origin, "Origin");
     dictMetadataType_.Add(MetadataType_Instance_TransferSyntax, "TransferSyntax");
+    dictMetadataType_.Add(MetadataType_Instance_SopClassUid, "SopClassUid");
 
     dictContentType_.Add(FileContentType_Dicom, "dicom");
     dictContentType_.Add(FileContentType_DicomAsJson, "dicom-as-json");
--- a/OrthancServer/ServerEnumerations.h	Fri Dec 09 11:24:04 2016 +0100
+++ b/OrthancServer/ServerEnumerations.h	Fri Dec 09 14:48:31 2016 +0100
@@ -159,6 +159,7 @@
     MetadataType_LastUpdate = 7,
     MetadataType_Instance_Origin = 8,          // New in Orthanc 0.9.5
     MetadataType_Instance_TransferSyntax = 9,  // New in Orthanc 1.2.0
+    MetadataType_Instance_SopClassUid = 10,    // New in Orthanc 1.2.0
 
     // Make sure that the value "65535" can be stored into this enumeration
     MetadataType_StartUser = 1024,
--- a/OrthancServer/ServerIndex.cpp	Fri Dec 09 11:24:04 2016 +0100
+++ b/OrthancServer/ServerIndex.cpp	Fri Dec 09 14:48:31 2016 +0100
@@ -787,6 +787,13 @@
       }
 
       const DicomValue* value;
+      if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_SOP_CLASS_UID)) != NULL &&
+          !value->IsNull() &&
+          !value->IsBinary())
+      {
+        SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_SopClassUid, value->GetContent());
+      }
+
       if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_INSTANCE_NUMBER)) != NULL ||
           (value = dicomSummary.TestAndGetValue(DICOM_TAG_IMAGE_INDEX)) != NULL)
       {
--- a/Resources/Configuration.json	Fri Dec 09 11:24:04 2016 +0100
+++ b/Resources/Configuration.json	Fri Dec 09 14:48:31 2016 +0100
@@ -314,9 +314,12 @@
      }
    **/
   
-  // If set to "true", Orthanc will handle "SOP Classes in Study"
-  // (0008,0062) in C-FIND requests. This option is turned off by
-  // default, as it requires intensive accesses to the hard drive.
+  // If set to "true", Orthanc will still handle "SOP Classes in
+  // Study" (0008,0062) in C-FIND requests, even if the "SOP Class
+  // UID" metadata is not available in the database (which is the case
+  // if the DB was previously used by Orthanc <= 1.1.0). This option
+  // is turned off by default, as it requires intensive accesses to
+  // the hard drive.
   "AllowFindSopClassesInStudy" : false,
 
   // If set to "false", Orthanc will not load its default dictionary
--- a/TODO	Fri Dec 09 11:24:04 2016 +0100
+++ b/TODO	Fri Dec 09 14:48:31 2016 +0100
@@ -105,7 +105,7 @@
 Orthanc Book
 ============
 
-* Document C-FIND filters
+* Document Lua C-FIND filters (cf. "IncomingFindRequestFilter()")
 
 
 ================
--- a/UnitTestsSources/ServerIndexTests.cpp	Fri Dec 09 11:24:04 2016 +0100
+++ b/UnitTestsSources/ServerIndexTests.cpp	Fri Dec 09 14:48:31 2016 +0100
@@ -793,19 +793,23 @@
     instance.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, "study-" + id, false);
     instance.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, "series-" + id, false);
     instance.SetValue(DICOM_TAG_SOP_INSTANCE_UID, "instance-" + id, false);
+    instance.SetValue(DICOM_TAG_SOP_CLASS_UID, "1.2.840.10008.5.1.4.1.1.1", false);  // CR image
 
     std::map<MetadataType, std::string> instanceMetadata;
     DicomInstanceToStore toStore;
     toStore.SetSummary(instance);
     ASSERT_EQ(StoreStatus_Success, index.Store(instanceMetadata, toStore, attachments));
-    ASSERT_EQ(4u, instanceMetadata.size());
+    ASSERT_EQ(5u, instanceMetadata.size());
     ASSERT_TRUE(instanceMetadata.find(MetadataType_Instance_RemoteAet) != instanceMetadata.end());
     ASSERT_TRUE(instanceMetadata.find(MetadataType_Instance_ReceptionDate) != instanceMetadata.end());
     ASSERT_TRUE(instanceMetadata.find(MetadataType_Instance_TransferSyntax) != instanceMetadata.end());
+    ASSERT_TRUE(instanceMetadata.find(MetadataType_Instance_SopClassUid) != instanceMetadata.end());
 
     // By default, an Explicit VR Little Endian is used by Orthanc
     ASSERT_EQ("1.2.840.10008.1.2.1", instanceMetadata[MetadataType_Instance_TransferSyntax]);
 
+    ASSERT_EQ("1.2.840.10008.5.1.4.1.1.1", instanceMetadata[MetadataType_Instance_SopClassUid]);
+
     DicomInstanceHasher hasher(instance);
     ids.push_back(hasher.HashPatient());
     ids.push_back(hasher.HashStudy());