comparison Core/DicomParsing/DicomModification.cpp @ 3513:7db879b014ff

Fix lost relationships between CT and RT-STRUCT during anonymization
author amazy
date Thu, 05 Sep 2019 13:11:35 +0200
parents 90b4a5001c24
children 94f4a18a79cc
comparison
equal deleted inserted replaced
3512:4bced7d1ec20 3513:7db879b014ff
133 { 133 {
134 if (!IsEnabled(tag)) 134 if (!IsEnabled(tag))
135 { 135 {
136 return Action_None; 136 return Action_None;
137 } 137 }
138 else if (tag == DICOM_TAG_FRAME_OF_REFERENCE_UID || 138 else if (parentTags.size() == 2 &&
139 parentTags[0] == DICOM_TAG_REFERENCED_FRAME_OF_REFERENCE_SEQUENCE &&
140 parentTags[1] == DICOM_TAG_RT_REFERENCED_STUDY_SEQUENCE &&
141 tag == DICOM_TAG_REFERENCED_SOP_INSTANCE_UID)
142 {
143 // in RT-STRUCT, this ReferencedSOPInstanceUID is actually referencing a StudyInstanceUID !!
144 // (observed in many data sets including: https://wiki.cancerimagingarchive.net/display/Public/Lung+CT+Segmentation+Challenge+2017)
145 // tested in test_anonymize_relationships_5
146 newValue = that_.MapDicomIdentifier(Toolbox::StripSpaces(value), ResourceType_Study);
147 return Action_Replace;
148 }
149 else if (tag == DICOM_TAG_FRAME_OF_REFERENCE_UID ||
139 tag == DICOM_TAG_REFERENCED_FRAME_OF_REFERENCE_UID || 150 tag == DICOM_TAG_REFERENCED_FRAME_OF_REFERENCE_UID ||
140 tag == DICOM_TAG_REFERENCED_SOP_INSTANCE_UID || 151 tag == DICOM_TAG_REFERENCED_SOP_INSTANCE_UID ||
141 tag == DICOM_TAG_RELATED_FRAME_OF_REFERENCE_UID) 152 tag == DICOM_TAG_RELATED_FRAME_OF_REFERENCE_UID)
142 { 153 {
143 newValue = that_.MapDicomIdentifier(Toolbox::StripSpaces(value), ResourceType_Instance); 154 newValue = that_.MapDicomIdentifier(Toolbox::StripSpaces(value), ResourceType_Instance);
151 return Action_Replace; 162 return Action_Replace;
152 } 163 }
153 else if (parentTags.size() == 2 && 164 else if (parentTags.size() == 2 &&
154 parentTags[0] == DICOM_TAG_CURRENT_REQUESTED_PROCEDURE_EVIDENCE_SEQUENCE && 165 parentTags[0] == DICOM_TAG_CURRENT_REQUESTED_PROCEDURE_EVIDENCE_SEQUENCE &&
155 parentTags[1] == DICOM_TAG_REFERENCED_SERIES_SEQUENCE && 166 parentTags[1] == DICOM_TAG_REFERENCED_SERIES_SEQUENCE &&
167 tag == DICOM_TAG_SERIES_INSTANCE_UID)
168 {
169 newValue = that_.MapDicomIdentifier(Toolbox::StripSpaces(value), ResourceType_Series);
170 return Action_Replace;
171 }
172 else if (parentTags.size() == 3 &&
173 parentTags[0] == DICOM_TAG_REFERENCED_FRAME_OF_REFERENCE_SEQUENCE &&
174 parentTags[1] == DICOM_TAG_RT_REFERENCED_STUDY_SEQUENCE &&
175 parentTags[2] == DICOM_TAG_RT_REFERENCED_SERIES_SEQUENCE &&
156 tag == DICOM_TAG_SERIES_INSTANCE_UID) 176 tag == DICOM_TAG_SERIES_INSTANCE_UID)
157 { 177 {
158 newValue = that_.MapDicomIdentifier(Toolbox::StripSpaces(value), ResourceType_Series); 178 newValue = that_.MapDicomIdentifier(Toolbox::StripSpaces(value), ResourceType_Series);
159 return Action_Replace; 179 return Action_Replace;
160 } 180 }
247 delete it->second; 267 delete it->second;
248 replacements_.erase(it); 268 replacements_.erase(it);
249 } 269 }
250 } 270 }
251 271
252 272 void DicomModification::RegisterMappedDicomIdentifier(const std::string& original,
273 const std::string& mapped,
274 ResourceType level)
275 {
276 UidMap::const_iterator previous = uidMap_.find(std::make_pair(level, original));
277
278 if (previous == uidMap_.end())
279 {
280 uidMap_.insert(std::make_pair(std::make_pair(level, original), mapped));
281 }
282 }
253 283
254 std::string DicomModification::MapDicomIdentifier(const std::string& original, 284 std::string DicomModification::MapDicomIdentifier(const std::string& original,
255 ResourceType level) 285 ResourceType level)
256 { 286 {
257 std::string mapped; 287 std::string mapped;
974 { 1004 {
975 throw OrthancException(ErrorCode_BadRequest, 1005 throw OrthancException(ErrorCode_BadRequest,
976 "When modifying an instance, the parent SeriesInstanceUID cannot be manually modified"); 1006 "When modifying an instance, the parent SeriesInstanceUID cannot be manually modified");
977 } 1007 }
978 1008
979
980 // (0) Create a summary of the source file, if a custom generator 1009 // (0) Create a summary of the source file, if a custom generator
981 // is provided 1010 // is provided
982 if (identifierGenerator_ != NULL) 1011 if (identifierGenerator_ != NULL)
983 { 1012 {
984 toModify.ExtractDicomSummary(currentSource_); 1013 toModify.ExtractDicomSummary(currentSource_);
985 } 1014 }
986 1015
987 1016 // (1) Make sure the relationships are updated with the ids that we force too
988 // (1) Remove the private tags, if need be 1017 // i.e: an RT-STRUCT is referencing its own StudyInstanceUID
1018 if (isAnonymization_ && updateReferencedRelationships_)
1019 {
1020 if (IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID))
1021 {
1022 std::string original;
1023 std::string replacement = GetReplacementAsString(DICOM_TAG_STUDY_INSTANCE_UID);
1024 toModify.GetTagValue(original, DICOM_TAG_STUDY_INSTANCE_UID);
1025 RegisterMappedDicomIdentifier(original, replacement, ResourceType_Study);
1026 }
1027
1028 if (IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID))
1029 {
1030 std::string original;
1031 std::string replacement = GetReplacementAsString(DICOM_TAG_SERIES_INSTANCE_UID);
1032 toModify.GetTagValue(original, DICOM_TAG_SERIES_INSTANCE_UID);
1033 RegisterMappedDicomIdentifier(original, replacement, ResourceType_Series);
1034 }
1035
1036 if (IsReplaced(DICOM_TAG_SOP_INSTANCE_UID))
1037 {
1038 std::string original;
1039 std::string replacement = GetReplacementAsString(DICOM_TAG_SOP_INSTANCE_UID);
1040 toModify.GetTagValue(original, DICOM_TAG_SOP_INSTANCE_UID);
1041 RegisterMappedDicomIdentifier(original, replacement, ResourceType_Instance);
1042 }
1043 }
1044
1045
1046 // (2) Remove the private tags, if need be
989 if (removePrivateTags_) 1047 if (removePrivateTags_)
990 { 1048 {
991 toModify.RemovePrivateTags(privateTagsToKeep_); 1049 toModify.RemovePrivateTags(privateTagsToKeep_);
992 } 1050 }
993 1051
994 // (2) Clear the tags specified by the user 1052 // (3) Clear the tags specified by the user
995 for (SetOfTags::const_iterator it = clearings_.begin(); 1053 for (SetOfTags::const_iterator it = clearings_.begin();
996 it != clearings_.end(); ++it) 1054 it != clearings_.end(); ++it)
997 { 1055 {
998 toModify.Clear(*it, true /* only clear if the tag exists in the original file */); 1056 toModify.Clear(*it, true /* only clear if the tag exists in the original file */);
999 } 1057 }
1000 1058
1001 // (3) Remove the tags specified by the user 1059 // (4) Remove the tags specified by the user
1002 for (SetOfTags::const_iterator it = removals_.begin(); 1060 for (SetOfTags::const_iterator it = removals_.begin();
1003 it != removals_.end(); ++it) 1061 it != removals_.end(); ++it)
1004 { 1062 {
1005 toModify.Remove(*it); 1063 toModify.Remove(*it);
1006 } 1064 }
1007 1065
1008 // (4) Replace the tags 1066 // (5) Replace the tags
1009 for (Replacements::const_iterator it = replacements_.begin(); 1067 for (Replacements::const_iterator it = replacements_.begin();
1010 it != replacements_.end(); ++it) 1068 it != replacements_.end(); ++it)
1011 { 1069 {
1012 toModify.Replace(it->first, *it->second, true /* decode data URI scheme */, DicomReplaceMode_InsertIfAbsent); 1070 toModify.Replace(it->first, *it->second, true /* decode data URI scheme */, DicomReplaceMode_InsertIfAbsent);
1013 } 1071 }
1014 1072
1015 // (5) Update the DICOM identifiers 1073 // (6) Update the DICOM identifiers
1016 if (level_ <= ResourceType_Study && 1074 if (level_ <= ResourceType_Study &&
1017 !IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) 1075 !IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID))
1018 { 1076 {
1019 if (keepStudyInstanceUid_) 1077 if (keepStudyInstanceUid_)
1020 { 1078 {
1043 !IsReplaced(DICOM_TAG_SOP_INSTANCE_UID)) 1101 !IsReplaced(DICOM_TAG_SOP_INSTANCE_UID))
1044 { 1102 {
1045 MapDicomTags(toModify, ResourceType_Instance); 1103 MapDicomTags(toModify, ResourceType_Instance);
1046 } 1104 }
1047 1105
1048 // (6) Update the "referenced" relationships in the case of an anonymization 1106 // (7) Update the "referenced" relationships in the case of an anonymization
1049 if (isAnonymization_) 1107 if (isAnonymization_)
1050 { 1108 {
1051 RelationshipsVisitor visitor(*this); 1109 RelationshipsVisitor visitor(*this);
1052 1110
1053 if (updateReferencedRelationships_) 1111 if (updateReferencedRelationships_)