diff OrthancFramework/Sources/DicomParsing/DicomModification.cpp @ 4693:45bce660ce3a

added routes for bulk anonymization/modification
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 16 Jun 2021 16:44:04 +0200
parents a08ef46c95a1
children dd6274412ff4
line wrap: on
line diff
--- a/OrthancFramework/Sources/DicomParsing/DicomModification.cpp	Fri Jun 11 10:48:28 2021 +0200
+++ b/OrthancFramework/Sources/DicomParsing/DicomModification.cpp	Wed Jun 16 16:44:04 2021 +0200
@@ -155,10 +155,21 @@
         if (that_.uids_.find(tag) != that_.uids_.end() &&
             !IsManuallyModified(tag))
         {
-          // This is a first-level UID tag that must be anonymized
-          assert(vr == ValueRepresentation_UniqueIdentifier ||
-                 vr == ValueRepresentation_NotSupported /* for older versions of DCMTK */);
-          newValue = that_.MapDicomIdentifier(value, ResourceType_Instance);
+          if (tag == DICOM_TAG_PATIENT_ID ||
+              tag == DICOM_TAG_PATIENT_NAME)
+          {
+            assert(vr == ValueRepresentation_LongString ||
+                   vr == ValueRepresentation_PersonName);
+            newValue = that_.MapDicomIdentifier(value, ResourceType_Patient);            
+          }
+          else
+          {
+            // This is a first-level UID tag that must be anonymized
+            assert(vr == ValueRepresentation_UniqueIdentifier ||
+                   vr == ValueRepresentation_NotSupported /* for older versions of DCMTK */);
+            newValue = that_.MapDicomIdentifier(value, ResourceType_Instance);
+          }
+          
           return Action_Replace;
         }
         else
@@ -202,27 +213,35 @@
         }
         else if (that_.uids_.find(tag) != that_.uids_.end())
         {
-          assert(vr == ValueRepresentation_UniqueIdentifier ||
-                 vr == ValueRepresentation_NotSupported /* for older versions of DCMTK */);
-
-          if (parentTags.size() == 2 &&
-              parentTags[0] == DICOM_TAG_REFERENCED_FRAME_OF_REFERENCE_SEQUENCE &&
-              parentTags[1] == DICOM_TAG_RT_REFERENCED_STUDY_SEQUENCE &&
-              tag == DICOM_TAG_REFERENCED_SOP_INSTANCE_UID)
+          if (tag == DICOM_TAG_PATIENT_ID ||
+              tag == DICOM_TAG_PATIENT_NAME)
           {
-            /**
-             * In RT-STRUCT, this ReferencedSOPInstanceUID is actually
-             * referencing a StudyInstanceUID !! (observed in many
-             * data sets including:
-             * https://wiki.cancerimagingarchive.net/display/Public/Lung+CT+Segmentation+Challenge+2017)
-             * Tested in "test_anonymize_relationships_5". Introduced
-             * in: https://hg.orthanc-server.com/orthanc/rev/3513
-             **/
-            newValue = that_.MapDicomIdentifier(value, ResourceType_Study);
+            newValue = that_.MapDicomIdentifier(value, ResourceType_Patient);
           }
           else
           {
-            newValue = that_.MapDicomIdentifier(value, ResourceType_Instance);
+            assert(vr == ValueRepresentation_UniqueIdentifier ||
+                   vr == ValueRepresentation_NotSupported /* for older versions of DCMTK */);
+
+            if (parentTags.size() == 2 &&
+                parentTags[0] == DICOM_TAG_REFERENCED_FRAME_OF_REFERENCE_SEQUENCE &&
+                parentTags[1] == DICOM_TAG_RT_REFERENCED_STUDY_SEQUENCE &&
+                tag == DICOM_TAG_REFERENCED_SOP_INSTANCE_UID)
+            {
+              /**
+               * In RT-STRUCT, this ReferencedSOPInstanceUID is actually
+               * referencing a StudyInstanceUID !! (observed in many
+               * data sets including:
+               * https://wiki.cancerimagingarchive.net/display/Public/Lung+CT+Segmentation+Challenge+2017)
+               * Tested in "test_anonymize_relationships_5". Introduced
+               * in: https://hg.orthanc-server.com/orthanc/rev/3513
+               **/
+              newValue = that_.MapDicomIdentifier(value, ResourceType_Study);
+            }
+            else
+            {
+              newValue = that_.MapDicomIdentifier(value, ResourceType_Instance);
+            }
           }
 
           return Action_Replace;
@@ -619,6 +638,10 @@
      **/
     uids_.clear();
 
+    // (*) "PatientID" and "PatientName" are handled as UIDs since Orthanc 1.9.4
+    uids_.insert(DICOM_TAG_PATIENT_ID);
+    uids_.insert(DICOM_TAG_PATIENT_NAME);
+    
     SetupUidsFromOrthancInternal(uids_, removals_, DicomTag(0x0008, 0x0014));  // Instance Creator UID                   <= from SetupAnonymization2008()
     SetupUidsFromOrthancInternal(uids_, removals_, DicomTag(0x0008, 0x1155));  // Referenced SOP Instance UID            <= from VisitString() + RemoveRelationships()
     SetupUidsFromOrthancInternal(uids_, removals_, DicomTag(0x0020, 0x0052));  // Frame of Reference UID                 <= from VisitString() + RemoveRelationships()
@@ -772,16 +795,29 @@
     ReplaceInternal(DicomTag(0x0012, 0x0062), "YES");
 
     // (*) Choose a random patient name and ID
-    std::string patientId = FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Patient);
-    ReplaceInternal(DICOM_TAG_PATIENT_ID, patientId);
-    ReplaceInternal(DICOM_TAG_PATIENT_NAME, patientId);
+    uids_.insert(DICOM_TAG_PATIENT_ID);
+    uids_.insert(DICOM_TAG_PATIENT_NAME);
 
     // Sanity check
     for (SetOfTags::const_iterator it = uids_.begin(); it != uids_.end(); ++it)
     {
       ValueRepresentation vr = FromDcmtkBridge::LookupValueRepresentation(*it);
-      if (vr != ValueRepresentation_UniqueIdentifier &&
-          vr != ValueRepresentation_NotSupported /* for older versions of DCMTK */)
+      if (*it == DICOM_TAG_PATIENT_ID)
+      {
+        if (vr != ValueRepresentation_LongString)
+        {
+          throw OrthancException(ErrorCode_InternalError);
+        }
+      }
+      else if (*it == DICOM_TAG_PATIENT_NAME)
+      {
+        if (vr != ValueRepresentation_PersonName)
+        {
+          throw OrthancException(ErrorCode_InternalError);
+        }
+      }
+      else if (vr != ValueRepresentation_UniqueIdentifier &&
+               vr != ValueRepresentation_NotSupported /* for older versions of DCMTK */)
       {
         throw OrthancException(ErrorCode_InternalError);
       }
@@ -805,7 +841,10 @@
     
 
     // Sanity checks at the patient level
-    if (level_ == ResourceType_Patient && !IsReplaced(DICOM_TAG_PATIENT_ID))
+    bool isReplacedPatientId = (IsReplaced(DICOM_TAG_PATIENT_ID) ||
+                                uids_.find(DICOM_TAG_PATIENT_ID) != uids_.end());
+    
+    if (level_ == ResourceType_Patient && !isReplacedPatientId)
     {
       throw OrthancException(ErrorCode_BadRequest,
                              "When modifying a patient, her PatientID is required to be modified");
@@ -834,7 +873,7 @@
 
 
     // Sanity checks at the study level
-    if (level_ == ResourceType_Study && IsReplaced(DICOM_TAG_PATIENT_ID))
+    if (level_ == ResourceType_Study && isReplacedPatientId)
     {
       throw OrthancException(ErrorCode_BadRequest,
                              "When modifying a study, the parent PatientID cannot be manually modified");
@@ -857,7 +896,7 @@
 
 
     // Sanity checks at the series level
-    if (level_ == ResourceType_Series && IsReplaced(DICOM_TAG_PATIENT_ID))
+    if (level_ == ResourceType_Series && isReplacedPatientId)
     {
       throw OrthancException(ErrorCode_BadRequest,
                              "When modifying a series, the parent PatientID cannot be manually modified");
@@ -880,7 +919,7 @@
 
 
     // Sanity checks at the instance level
-    if (level_ == ResourceType_Instance && IsReplaced(DICOM_TAG_PATIENT_ID))
+    if (level_ == ResourceType_Instance && isReplacedPatientId)
     {
       throw OrthancException(ErrorCode_BadRequest,
                              "When modifying an instance, the parent PatientID cannot be manually modified");
@@ -1203,7 +1242,7 @@
   }
 
 
-  void DicomModification::ParseAnonymizationRequest(bool& patientNameReplaced,
+  void DicomModification::ParseAnonymizationRequest(bool& patientNameOverridden,
                                                     const Json::Value& request)
   {
     if (!request.isObject())
@@ -1230,8 +1269,6 @@
         
     SetupAnonymization(version);
 
-    std::string patientName = GetReplacementAsString(DICOM_TAG_PATIENT_NAME);    
-
     if (GetBooleanValue("KeepPrivateTags", request, false))
     {
       SetRemovePrivateTags(false);
@@ -1252,9 +1289,8 @@
       ParseListOfTags(*this, request["Keep"], TagOperation_Keep, force);
     }
 
-    patientNameReplaced = (IsReplaced(DICOM_TAG_PATIENT_NAME) &&
-                           GetReplacement(DICOM_TAG_PATIENT_NAME) == patientName);
-
+    patientNameOverridden = (uids_.find(DICOM_TAG_PATIENT_NAME) == uids_.end());
+    
     // New in Orthanc 1.6.0
     if (request.isMember("PrivateCreator"))
     {