Mercurial > hg > orthanc
comparison 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 |
comparison
equal
deleted
inserted
replaced
4692:e68edf92e5cc | 4693:45bce660ce3a |
---|---|
153 { | 153 { |
154 // We are on a first-level tag | 154 // We are on a first-level tag |
155 if (that_.uids_.find(tag) != that_.uids_.end() && | 155 if (that_.uids_.find(tag) != that_.uids_.end() && |
156 !IsManuallyModified(tag)) | 156 !IsManuallyModified(tag)) |
157 { | 157 { |
158 // This is a first-level UID tag that must be anonymized | 158 if (tag == DICOM_TAG_PATIENT_ID || |
159 assert(vr == ValueRepresentation_UniqueIdentifier || | 159 tag == DICOM_TAG_PATIENT_NAME) |
160 vr == ValueRepresentation_NotSupported /* for older versions of DCMTK */); | 160 { |
161 newValue = that_.MapDicomIdentifier(value, ResourceType_Instance); | 161 assert(vr == ValueRepresentation_LongString || |
162 vr == ValueRepresentation_PersonName); | |
163 newValue = that_.MapDicomIdentifier(value, ResourceType_Patient); | |
164 } | |
165 else | |
166 { | |
167 // This is a first-level UID tag that must be anonymized | |
168 assert(vr == ValueRepresentation_UniqueIdentifier || | |
169 vr == ValueRepresentation_NotSupported /* for older versions of DCMTK */); | |
170 newValue = that_.MapDicomIdentifier(value, ResourceType_Instance); | |
171 } | |
172 | |
162 return Action_Replace; | 173 return Action_Replace; |
163 } | 174 } |
164 else | 175 else |
165 { | 176 { |
166 return Action_None; | 177 return Action_None; |
200 newValue = that_.MapDicomIdentifier(value, ResourceType_Instance); | 211 newValue = that_.MapDicomIdentifier(value, ResourceType_Instance); |
201 return Action_Replace; | 212 return Action_Replace; |
202 } | 213 } |
203 else if (that_.uids_.find(tag) != that_.uids_.end()) | 214 else if (that_.uids_.find(tag) != that_.uids_.end()) |
204 { | 215 { |
205 assert(vr == ValueRepresentation_UniqueIdentifier || | 216 if (tag == DICOM_TAG_PATIENT_ID || |
206 vr == ValueRepresentation_NotSupported /* for older versions of DCMTK */); | 217 tag == DICOM_TAG_PATIENT_NAME) |
207 | |
208 if (parentTags.size() == 2 && | |
209 parentTags[0] == DICOM_TAG_REFERENCED_FRAME_OF_REFERENCE_SEQUENCE && | |
210 parentTags[1] == DICOM_TAG_RT_REFERENCED_STUDY_SEQUENCE && | |
211 tag == DICOM_TAG_REFERENCED_SOP_INSTANCE_UID) | |
212 { | 218 { |
213 /** | 219 newValue = that_.MapDicomIdentifier(value, ResourceType_Patient); |
214 * In RT-STRUCT, this ReferencedSOPInstanceUID is actually | |
215 * referencing a StudyInstanceUID !! (observed in many | |
216 * data sets including: | |
217 * https://wiki.cancerimagingarchive.net/display/Public/Lung+CT+Segmentation+Challenge+2017) | |
218 * Tested in "test_anonymize_relationships_5". Introduced | |
219 * in: https://hg.orthanc-server.com/orthanc/rev/3513 | |
220 **/ | |
221 newValue = that_.MapDicomIdentifier(value, ResourceType_Study); | |
222 } | 220 } |
223 else | 221 else |
224 { | 222 { |
225 newValue = that_.MapDicomIdentifier(value, ResourceType_Instance); | 223 assert(vr == ValueRepresentation_UniqueIdentifier || |
224 vr == ValueRepresentation_NotSupported /* for older versions of DCMTK */); | |
225 | |
226 if (parentTags.size() == 2 && | |
227 parentTags[0] == DICOM_TAG_REFERENCED_FRAME_OF_REFERENCE_SEQUENCE && | |
228 parentTags[1] == DICOM_TAG_RT_REFERENCED_STUDY_SEQUENCE && | |
229 tag == DICOM_TAG_REFERENCED_SOP_INSTANCE_UID) | |
230 { | |
231 /** | |
232 * In RT-STRUCT, this ReferencedSOPInstanceUID is actually | |
233 * referencing a StudyInstanceUID !! (observed in many | |
234 * data sets including: | |
235 * https://wiki.cancerimagingarchive.net/display/Public/Lung+CT+Segmentation+Challenge+2017) | |
236 * Tested in "test_anonymize_relationships_5". Introduced | |
237 * in: https://hg.orthanc-server.com/orthanc/rev/3513 | |
238 **/ | |
239 newValue = that_.MapDicomIdentifier(value, ResourceType_Study); | |
240 } | |
241 else | |
242 { | |
243 newValue = that_.MapDicomIdentifier(value, ResourceType_Instance); | |
244 } | |
226 } | 245 } |
227 | 246 |
228 return Action_Replace; | 247 return Action_Replace; |
229 } | 248 } |
230 else | 249 else |
617 * DicomModification::RelationshipsVisitor::RemoveRelationships() | 636 * DicomModification::RelationshipsVisitor::RemoveRelationships() |
618 * https://hg.orthanc-server.com/orthanc/file/Orthanc-1.9.3/OrthancFramework/Sources/DicomParsing/DicomModification.cpp#l117 | 637 * https://hg.orthanc-server.com/orthanc/file/Orthanc-1.9.3/OrthancFramework/Sources/DicomParsing/DicomModification.cpp#l117 |
619 **/ | 638 **/ |
620 uids_.clear(); | 639 uids_.clear(); |
621 | 640 |
641 // (*) "PatientID" and "PatientName" are handled as UIDs since Orthanc 1.9.4 | |
642 uids_.insert(DICOM_TAG_PATIENT_ID); | |
643 uids_.insert(DICOM_TAG_PATIENT_NAME); | |
644 | |
622 SetupUidsFromOrthancInternal(uids_, removals_, DicomTag(0x0008, 0x0014)); // Instance Creator UID <= from SetupAnonymization2008() | 645 SetupUidsFromOrthancInternal(uids_, removals_, DicomTag(0x0008, 0x0014)); // Instance Creator UID <= from SetupAnonymization2008() |
623 SetupUidsFromOrthancInternal(uids_, removals_, DicomTag(0x0008, 0x1155)); // Referenced SOP Instance UID <= from VisitString() + RemoveRelationships() | 646 SetupUidsFromOrthancInternal(uids_, removals_, DicomTag(0x0008, 0x1155)); // Referenced SOP Instance UID <= from VisitString() + RemoveRelationships() |
624 SetupUidsFromOrthancInternal(uids_, removals_, DicomTag(0x0020, 0x0052)); // Frame of Reference UID <= from VisitString() + RemoveRelationships() | 647 SetupUidsFromOrthancInternal(uids_, removals_, DicomTag(0x0020, 0x0052)); // Frame of Reference UID <= from VisitString() + RemoveRelationships() |
625 SetupUidsFromOrthancInternal(uids_, removals_, DicomTag(0x0020, 0x0200)); // Synchronization Frame of Reference UID <= from SetupAnonymization2008() | 648 SetupUidsFromOrthancInternal(uids_, removals_, DicomTag(0x0020, 0x0200)); // Synchronization Frame of Reference UID <= from SetupAnonymization2008() |
626 SetupUidsFromOrthancInternal(uids_, removals_, DicomTag(0x0040, 0xa124)); // UID <= from SetupAnonymization2008() | 649 SetupUidsFromOrthancInternal(uids_, removals_, DicomTag(0x0040, 0xa124)); // UID <= from SetupAnonymization2008() |
770 | 793 |
771 // Set the PatientIdentityRemoved tag | 794 // Set the PatientIdentityRemoved tag |
772 ReplaceInternal(DicomTag(0x0012, 0x0062), "YES"); | 795 ReplaceInternal(DicomTag(0x0012, 0x0062), "YES"); |
773 | 796 |
774 // (*) Choose a random patient name and ID | 797 // (*) Choose a random patient name and ID |
775 std::string patientId = FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Patient); | 798 uids_.insert(DICOM_TAG_PATIENT_ID); |
776 ReplaceInternal(DICOM_TAG_PATIENT_ID, patientId); | 799 uids_.insert(DICOM_TAG_PATIENT_NAME); |
777 ReplaceInternal(DICOM_TAG_PATIENT_NAME, patientId); | |
778 | 800 |
779 // Sanity check | 801 // Sanity check |
780 for (SetOfTags::const_iterator it = uids_.begin(); it != uids_.end(); ++it) | 802 for (SetOfTags::const_iterator it = uids_.begin(); it != uids_.end(); ++it) |
781 { | 803 { |
782 ValueRepresentation vr = FromDcmtkBridge::LookupValueRepresentation(*it); | 804 ValueRepresentation vr = FromDcmtkBridge::LookupValueRepresentation(*it); |
783 if (vr != ValueRepresentation_UniqueIdentifier && | 805 if (*it == DICOM_TAG_PATIENT_ID) |
784 vr != ValueRepresentation_NotSupported /* for older versions of DCMTK */) | 806 { |
807 if (vr != ValueRepresentation_LongString) | |
808 { | |
809 throw OrthancException(ErrorCode_InternalError); | |
810 } | |
811 } | |
812 else if (*it == DICOM_TAG_PATIENT_NAME) | |
813 { | |
814 if (vr != ValueRepresentation_PersonName) | |
815 { | |
816 throw OrthancException(ErrorCode_InternalError); | |
817 } | |
818 } | |
819 else if (vr != ValueRepresentation_UniqueIdentifier && | |
820 vr != ValueRepresentation_NotSupported /* for older versions of DCMTK */) | |
785 { | 821 { |
786 throw OrthancException(ErrorCode_InternalError); | 822 throw OrthancException(ErrorCode_InternalError); |
787 } | 823 } |
788 } | 824 } |
789 } | 825 } |
803 throw OrthancException(ErrorCode_BadRequest); | 839 throw OrthancException(ErrorCode_BadRequest); |
804 } | 840 } |
805 | 841 |
806 | 842 |
807 // Sanity checks at the patient level | 843 // Sanity checks at the patient level |
808 if (level_ == ResourceType_Patient && !IsReplaced(DICOM_TAG_PATIENT_ID)) | 844 bool isReplacedPatientId = (IsReplaced(DICOM_TAG_PATIENT_ID) || |
845 uids_.find(DICOM_TAG_PATIENT_ID) != uids_.end()); | |
846 | |
847 if (level_ == ResourceType_Patient && !isReplacedPatientId) | |
809 { | 848 { |
810 throw OrthancException(ErrorCode_BadRequest, | 849 throw OrthancException(ErrorCode_BadRequest, |
811 "When modifying a patient, her PatientID is required to be modified"); | 850 "When modifying a patient, her PatientID is required to be modified"); |
812 } | 851 } |
813 | 852 |
832 } | 871 } |
833 } | 872 } |
834 | 873 |
835 | 874 |
836 // Sanity checks at the study level | 875 // Sanity checks at the study level |
837 if (level_ == ResourceType_Study && IsReplaced(DICOM_TAG_PATIENT_ID)) | 876 if (level_ == ResourceType_Study && isReplacedPatientId) |
838 { | 877 { |
839 throw OrthancException(ErrorCode_BadRequest, | 878 throw OrthancException(ErrorCode_BadRequest, |
840 "When modifying a study, the parent PatientID cannot be manually modified"); | 879 "When modifying a study, the parent PatientID cannot be manually modified"); |
841 } | 880 } |
842 | 881 |
855 } | 894 } |
856 } | 895 } |
857 | 896 |
858 | 897 |
859 // Sanity checks at the series level | 898 // Sanity checks at the series level |
860 if (level_ == ResourceType_Series && IsReplaced(DICOM_TAG_PATIENT_ID)) | 899 if (level_ == ResourceType_Series && isReplacedPatientId) |
861 { | 900 { |
862 throw OrthancException(ErrorCode_BadRequest, | 901 throw OrthancException(ErrorCode_BadRequest, |
863 "When modifying a series, the parent PatientID cannot be manually modified"); | 902 "When modifying a series, the parent PatientID cannot be manually modified"); |
864 } | 903 } |
865 | 904 |
878 } | 917 } |
879 } | 918 } |
880 | 919 |
881 | 920 |
882 // Sanity checks at the instance level | 921 // Sanity checks at the instance level |
883 if (level_ == ResourceType_Instance && IsReplaced(DICOM_TAG_PATIENT_ID)) | 922 if (level_ == ResourceType_Instance && isReplacedPatientId) |
884 { | 923 { |
885 throw OrthancException(ErrorCode_BadRequest, | 924 throw OrthancException(ErrorCode_BadRequest, |
886 "When modifying an instance, the parent PatientID cannot be manually modified"); | 925 "When modifying an instance, the parent PatientID cannot be manually modified"); |
887 } | 926 } |
888 | 927 |
1201 privateCreator_ = SerializationToolbox::ReadString(request, "PrivateCreator"); | 1240 privateCreator_ = SerializationToolbox::ReadString(request, "PrivateCreator"); |
1202 } | 1241 } |
1203 } | 1242 } |
1204 | 1243 |
1205 | 1244 |
1206 void DicomModification::ParseAnonymizationRequest(bool& patientNameReplaced, | 1245 void DicomModification::ParseAnonymizationRequest(bool& patientNameOverridden, |
1207 const Json::Value& request) | 1246 const Json::Value& request) |
1208 { | 1247 { |
1209 if (!request.isObject()) | 1248 if (!request.isObject()) |
1210 { | 1249 { |
1211 throw OrthancException(ErrorCode_BadFileFormat); | 1250 throw OrthancException(ErrorCode_BadFileFormat); |
1228 } | 1267 } |
1229 } | 1268 } |
1230 | 1269 |
1231 SetupAnonymization(version); | 1270 SetupAnonymization(version); |
1232 | 1271 |
1233 std::string patientName = GetReplacementAsString(DICOM_TAG_PATIENT_NAME); | |
1234 | |
1235 if (GetBooleanValue("KeepPrivateTags", request, false)) | 1272 if (GetBooleanValue("KeepPrivateTags", request, false)) |
1236 { | 1273 { |
1237 SetRemovePrivateTags(false); | 1274 SetRemovePrivateTags(false); |
1238 } | 1275 } |
1239 | 1276 |
1250 if (request.isMember("Keep")) | 1287 if (request.isMember("Keep")) |
1251 { | 1288 { |
1252 ParseListOfTags(*this, request["Keep"], TagOperation_Keep, force); | 1289 ParseListOfTags(*this, request["Keep"], TagOperation_Keep, force); |
1253 } | 1290 } |
1254 | 1291 |
1255 patientNameReplaced = (IsReplaced(DICOM_TAG_PATIENT_NAME) && | 1292 patientNameOverridden = (uids_.find(DICOM_TAG_PATIENT_NAME) == uids_.end()); |
1256 GetReplacement(DICOM_TAG_PATIENT_NAME) == patientName); | 1293 |
1257 | |
1258 // New in Orthanc 1.6.0 | 1294 // New in Orthanc 1.6.0 |
1259 if (request.isMember("PrivateCreator")) | 1295 if (request.isMember("PrivateCreator")) |
1260 { | 1296 { |
1261 privateCreator_ = SerializationToolbox::ReadString(request, "PrivateCreator"); | 1297 privateCreator_ = SerializationToolbox::ReadString(request, "PrivateCreator"); |
1262 } | 1298 } |