comparison OrthancFramework/Sources/DicomParsing/DicomModification.cpp @ 4684:e3810750dc9d

simplified DicomModification::RelationshipsVisitor
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 08 Jun 2021 14:42:09 +0200
parents 2e850edf03d6
children 693f049729ba
comparison
equal deleted inserted replaced
4683:7182f5732480 4684:e3810750dc9d
67 67
68 class DicomModification::RelationshipsVisitor : public ITagVisitor 68 class DicomModification::RelationshipsVisitor : public ITagVisitor
69 { 69 {
70 private: 70 private:
71 DicomModification& that_; 71 DicomModification& that_;
72 72
73 bool IsEnabled(const DicomTag& tag) const 73 // This method is only applicable to first-level tags
74 { 74 bool IsManuallyModified(const DicomTag& tag) const
75 return (!that_.IsCleared(tag) && 75 {
76 !that_.IsRemoved(tag) && 76 return (that_.IsCleared(tag) ||
77 !that_.IsReplaced(tag)); 77 that_.IsRemoved(tag) ||
78 } 78 that_.IsReplaced(tag));
79 79 }
80 void RemoveIfEnabled(ParsedDicomFile& dicom,
81 const DicomTag& tag) const
82 {
83 if (IsEnabled(tag))
84 {
85 dicom.Remove(tag);
86 }
87 }
88
89 80
90 public: 81 public:
91 explicit RelationshipsVisitor(DicomModification& that) : 82 explicit RelationshipsVisitor(DicomModification& that) :
92 that_(that) 83 that_(that)
93 { 84 {
143 const std::vector<size_t>& parentIndexes, 134 const std::vector<size_t>& parentIndexes,
144 const DicomTag& tag, 135 const DicomTag& tag,
145 ValueRepresentation vr, 136 ValueRepresentation vr,
146 const std::string& value) 137 const std::string& value)
147 { 138 {
148 // Note that all the tags in "uids_" have the VR UI (unique 139 /**
149 // identifier), and are considered as strings 140 * Note that all the tags in "uids_" have the VR UI (unique
150 141 * identifier), and are considered as strings.
151 if (!IsEnabled(tag)) 142 *
152 { 143 * Also, the tags "SOP Instance UID", "Series Instance UID" and
153 return Action_None; 144 * "Study Instance UID" are *never* included in "uids_", as they
154 } 145 * are separately handed by "MapDicomTags()".
155 else if (!parentTags.empty() && // Don't anonymize twice the anonymization done by "MapDicomTags()" 146 **/
156 tag == DICOM_TAG_STUDY_INSTANCE_UID) 147
157 { 148 assert(that_.uids_.find(DICOM_TAG_STUDY_INSTANCE_UID) == that_.uids_.end());
158 newValue = that_.MapDicomIdentifier(value, ResourceType_Study); 149 assert(that_.uids_.find(DICOM_TAG_SERIES_INSTANCE_UID) == that_.uids_.end());
159 return Action_Replace; 150 assert(that_.uids_.find(DICOM_TAG_SOP_INSTANCE_UID) == that_.uids_.end());
160 } 151
161 else if (!parentTags.empty() && // Don't anonymize twice the anonymization done by "MapDicomTags()" 152 if (parentTags.empty())
162 tag == DICOM_TAG_SERIES_INSTANCE_UID) 153 {
163 { 154 // We are on a first-level tag
164 newValue = that_.MapDicomIdentifier(value, ResourceType_Series); 155 if (that_.uids_.find(tag) != that_.uids_.end() &&
165 return Action_Replace; 156 !IsManuallyModified(tag))
166 }
167 else if (!parentTags.empty() && // Don't anonymize twice the anonymization done by "MapDicomTags()"
168 tag == DICOM_TAG_SOP_INSTANCE_UID)
169 {
170 newValue = that_.MapDicomIdentifier(value, ResourceType_Instance);
171 return Action_Replace;
172 }
173 else if (that_.uids_.find(tag) != that_.uids_.end())
174 {
175 assert(vr == ValueRepresentation_UniqueIdentifier ||
176 vr == ValueRepresentation_NotSupported /* for older versions of DCMTK */);
177
178 if (parentTags.size() == 2 &&
179 parentTags[0] == DICOM_TAG_REFERENCED_FRAME_OF_REFERENCE_SEQUENCE &&
180 parentTags[1] == DICOM_TAG_RT_REFERENCED_STUDY_SEQUENCE &&
181 tag == DICOM_TAG_REFERENCED_SOP_INSTANCE_UID)
182 { 157 {
183 // in RT-STRUCT, this ReferencedSOPInstanceUID is actually referencing a StudyInstanceUID !! 158 // This is a first-level UID tag that must be anonymized
184 // (observed in many data sets including: https://wiki.cancerimagingarchive.net/display/Public/Lung+CT+Segmentation+Challenge+2017) 159 assert(vr == ValueRepresentation_UniqueIdentifier ||
185 // tested in test_anonymize_relationships_5 160 vr == ValueRepresentation_NotSupported /* for older versions of DCMTK */);
186 newValue = that_.MapDicomIdentifier(value, ResourceType_Study); 161 newValue = that_.MapDicomIdentifier(value, ResourceType_Instance);
162 return Action_Replace;
187 } 163 }
188 else 164 else
189 { 165 {
166 return Action_None;
167 }
168 }
169 else
170 {
171 // We are within a sequence
172 if (tag == DICOM_TAG_STUDY_INSTANCE_UID)
173 {
174 newValue = that_.MapDicomIdentifier(value, ResourceType_Study);
175 return Action_Replace;
176 }
177 else if (tag == DICOM_TAG_SERIES_INSTANCE_UID)
178 {
179 newValue = that_.MapDicomIdentifier(value, ResourceType_Series);
180 return Action_Replace;
181 }
182 else if (tag == DICOM_TAG_SOP_INSTANCE_UID)
183 {
190 newValue = that_.MapDicomIdentifier(value, ResourceType_Instance); 184 newValue = that_.MapDicomIdentifier(value, ResourceType_Instance);
185 return Action_Replace;
191 } 186 }
192 187 else if (that_.uids_.find(tag) != that_.uids_.end())
193 return Action_Replace; 188 {
194 } 189 assert(vr == ValueRepresentation_UniqueIdentifier ||
195 else 190 vr == ValueRepresentation_NotSupported /* for older versions of DCMTK */);
196 { 191
197 return Action_None; 192 if (parentTags.size() == 2 &&
193 parentTags[0] == DICOM_TAG_REFERENCED_FRAME_OF_REFERENCE_SEQUENCE &&
194 parentTags[1] == DICOM_TAG_RT_REFERENCED_STUDY_SEQUENCE &&
195 tag == DICOM_TAG_REFERENCED_SOP_INSTANCE_UID)
196 {
197 /**
198 * In RT-STRUCT, this ReferencedSOPInstanceUID is actually
199 * referencing a StudyInstanceUID !! (observed in many
200 * data sets including:
201 * https://wiki.cancerimagingarchive.net/display/Public/Lung+CT+Segmentation+Challenge+2017)
202 * Tested in "test_anonymize_relationships_5". Introduced
203 * in: https://hg.orthanc-server.com/orthanc/rev/3513
204 **/
205 newValue = that_.MapDicomIdentifier(value, ResourceType_Study);
206 }
207 else
208 {
209 newValue = that_.MapDicomIdentifier(value, ResourceType_Instance);
210 }
211
212 return Action_Replace;
213 }
214 else
215 {
216 return Action_None;
217 }
198 } 218 }
199 } 219 }
200 220
201 void RemoveRelationships(ParsedDicomFile& dicom) const 221 void RemoveRelationships(ParsedDicomFile& dicom) const
202 { 222 {
203 for (SetOfTags::const_iterator it = that_.uids_.begin(); it != that_.uids_.end(); ++it) 223 for (SetOfTags::const_iterator it = that_.uids_.begin(); it != that_.uids_.end(); ++it)
204 { 224 {
205 if (*it != DICOM_TAG_STUDY_INSTANCE_UID && 225 assert(*it != DICOM_TAG_STUDY_INSTANCE_UID &&
206 *it != DICOM_TAG_SERIES_INSTANCE_UID && 226 *it != DICOM_TAG_SERIES_INSTANCE_UID &&
207 *it != DICOM_TAG_SOP_INSTANCE_UID) 227 *it != DICOM_TAG_SOP_INSTANCE_UID);
228
229 if (!IsManuallyModified(*it))
208 { 230 {
209 RemoveIfEnabled(dicom, *it); 231 dicom.Remove(*it);
210 } 232 }
211 } 233 }
212 234
213 // The only two sequences with to the "X/Z/U*" rule in the 235 // The only two sequences with to the "X/Z/U*" rule in the
214 // basic profile. They were already present in Orthanc 1.9.3. 236 // basic profile. They were already present in Orthanc 1.9.3.
215 RemoveIfEnabled(dicom, DICOM_TAG_REFERENCED_IMAGE_SEQUENCE); 237 if (!IsManuallyModified(DICOM_TAG_REFERENCED_IMAGE_SEQUENCE))
216 RemoveIfEnabled(dicom, DICOM_TAG_SOURCE_IMAGE_SEQUENCE); 238 {
239 dicom.Remove(DICOM_TAG_REFERENCED_IMAGE_SEQUENCE);
240 }
241
242 if (!IsManuallyModified(DICOM_TAG_SOURCE_IMAGE_SEQUENCE))
243 {
244 dicom.Remove(DICOM_TAG_SOURCE_IMAGE_SEQUENCE);
245 }
217 } 246 }
218 }; 247 };
219 248
220 249
221 bool DicomModification::CancelReplacement(const DicomTag& tag) 250 bool DicomModification::CancelReplacement(const DicomTag& tag)