# HG changeset patch # User Sebastien Jodogne # Date 1568200927 -7200 # Node ID e481c2b3291419cc64724cafc4aa410f96f71bb2 # Parent 96780208dbd7bead3b075ca8d88c18fd8757a7a5# Parent 13f9ccf05a8e25803563e50796642682ca06e434 merge diff -r 96780208dbd7 -r e481c2b32914 Core/DicomFormat/DicomTag.h --- a/Core/DicomFormat/DicomTag.h Wed Sep 11 13:21:50 2019 +0200 +++ b/Core/DicomFormat/DicomTag.h Wed Sep 11 13:22:07 2019 +0200 @@ -220,4 +220,7 @@ static const DicomTag DICOM_TAG_RELATED_FRAME_OF_REFERENCE_UID(0x3006, 0x00c2); static const DicomTag DICOM_TAG_CURRENT_REQUESTED_PROCEDURE_EVIDENCE_SEQUENCE(0x0040, 0xa375); static const DicomTag DICOM_TAG_REFERENCED_SERIES_SEQUENCE(0x0008, 0x1115); + static const DicomTag DICOM_TAG_REFERENCED_FRAME_OF_REFERENCE_SEQUENCE(0x3006, 0x0010); + static const DicomTag DICOM_TAG_RT_REFERENCED_STUDY_SEQUENCE(0x3006, 0x0012); + static const DicomTag DICOM_TAG_RT_REFERENCED_SERIES_SEQUENCE(0x3006, 0x0014); } diff -r 96780208dbd7 -r e481c2b32914 Core/DicomParsing/DicomModification.cpp --- a/Core/DicomParsing/DicomModification.cpp Wed Sep 11 13:21:50 2019 +0200 +++ b/Core/DicomParsing/DicomModification.cpp Wed Sep 11 13:22:07 2019 +0200 @@ -135,7 +135,18 @@ { return Action_None; } - else if (tag == DICOM_TAG_FRAME_OF_REFERENCE_UID || + else 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 + newValue = that_.MapDicomIdentifier(Toolbox::StripSpaces(value), ResourceType_Study); + return Action_Replace; + } + else if (tag == DICOM_TAG_FRAME_OF_REFERENCE_UID || tag == DICOM_TAG_REFERENCED_FRAME_OF_REFERENCE_UID || tag == DICOM_TAG_REFERENCED_SOP_INSTANCE_UID || tag == DICOM_TAG_RELATED_FRAME_OF_REFERENCE_UID) @@ -158,6 +169,15 @@ newValue = that_.MapDicomIdentifier(Toolbox::StripSpaces(value), ResourceType_Series); return Action_Replace; } + else if (parentTags.size() == 3 && + parentTags[0] == DICOM_TAG_REFERENCED_FRAME_OF_REFERENCE_SEQUENCE && + parentTags[1] == DICOM_TAG_RT_REFERENCED_STUDY_SEQUENCE && + parentTags[2] == DICOM_TAG_RT_REFERENCED_SERIES_SEQUENCE && + tag == DICOM_TAG_SERIES_INSTANCE_UID) + { + newValue = that_.MapDicomIdentifier(Toolbox::StripSpaces(value), ResourceType_Series); + return Action_Replace; + } else if (parentTags.size() == 1 && parentTags[0] == DICOM_TAG_REFERENCED_SERIES_SEQUENCE && tag == DICOM_TAG_SERIES_INSTANCE_UID) @@ -249,7 +269,17 @@ } } + void DicomModification::RegisterMappedDicomIdentifier(const std::string& original, + const std::string& mapped, + ResourceType level) + { + UidMap::const_iterator previous = uidMap_.find(std::make_pair(level, original)); + if (previous == uidMap_.end()) + { + uidMap_.insert(std::make_pair(std::make_pair(level, original), mapped)); + } + } std::string DicomModification::MapDicomIdentifier(const std::string& original, ResourceType level) @@ -976,7 +1006,6 @@ "When modifying an instance, the parent SeriesInstanceUID cannot be manually modified"); } - // (0) Create a summary of the source file, if a custom generator // is provided if (identifierGenerator_ != NULL) @@ -984,35 +1013,64 @@ toModify.ExtractDicomSummary(currentSource_); } + // (1) Make sure the relationships are updated with the ids that we force too + // i.e: an RT-STRUCT is referencing its own StudyInstanceUID + if (isAnonymization_ && updateReferencedRelationships_) + { + if (IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) + { + std::string original; + std::string replacement = GetReplacementAsString(DICOM_TAG_STUDY_INSTANCE_UID); + toModify.GetTagValue(original, DICOM_TAG_STUDY_INSTANCE_UID); + RegisterMappedDicomIdentifier(original, replacement, ResourceType_Study); + } - // (1) Remove the private tags, if need be + if (IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID)) + { + std::string original; + std::string replacement = GetReplacementAsString(DICOM_TAG_SERIES_INSTANCE_UID); + toModify.GetTagValue(original, DICOM_TAG_SERIES_INSTANCE_UID); + RegisterMappedDicomIdentifier(original, replacement, ResourceType_Series); + } + + if (IsReplaced(DICOM_TAG_SOP_INSTANCE_UID)) + { + std::string original; + std::string replacement = GetReplacementAsString(DICOM_TAG_SOP_INSTANCE_UID); + toModify.GetTagValue(original, DICOM_TAG_SOP_INSTANCE_UID); + RegisterMappedDicomIdentifier(original, replacement, ResourceType_Instance); + } + } + + + // (2) Remove the private tags, if need be if (removePrivateTags_) { toModify.RemovePrivateTags(privateTagsToKeep_); } - // (2) Clear the tags specified by the user + // (3) Clear the tags specified by the user for (SetOfTags::const_iterator it = clearings_.begin(); it != clearings_.end(); ++it) { toModify.Clear(*it, true /* only clear if the tag exists in the original file */); } - // (3) Remove the tags specified by the user + // (4) Remove the tags specified by the user for (SetOfTags::const_iterator it = removals_.begin(); it != removals_.end(); ++it) { toModify.Remove(*it); } - // (4) Replace the tags + // (5) Replace the tags for (Replacements::const_iterator it = replacements_.begin(); it != replacements_.end(); ++it) { toModify.Replace(it->first, *it->second, true /* decode data URI scheme */, DicomReplaceMode_InsertIfAbsent); } - // (5) Update the DICOM identifiers + // (6) Update the DICOM identifiers if (level_ <= ResourceType_Study && !IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) { @@ -1045,7 +1103,7 @@ MapDicomTags(toModify, ResourceType_Instance); } - // (6) Update the "referenced" relationships in the case of an anonymization + // (7) Update the "referenced" relationships in the case of an anonymization if (isAnonymization_) { RelationshipsVisitor visitor(*this); diff -r 96780208dbd7 -r e481c2b32914 Core/DicomParsing/DicomModification.h --- a/Core/DicomParsing/DicomModification.h Wed Sep 11 13:21:50 2019 +0200 +++ b/Core/DicomParsing/DicomModification.h Wed Sep 11 13:22:07 2019 +0200 @@ -92,6 +92,10 @@ std::string MapDicomIdentifier(const std::string& original, ResourceType level); + void RegisterMappedDicomIdentifier(const std::string& original, + const std::string& mapped, + ResourceType level); + void MapDicomTags(ParsedDicomFile& dicom, ResourceType level); diff -r 96780208dbd7 -r e481c2b32914 NEWS --- a/NEWS Wed Sep 11 13:21:50 2019 +0200 +++ b/NEWS Wed Sep 11 13:22:07 2019 +0200 @@ -11,7 +11,8 @@ * Fix generation of "SOP Instance UID" on split and merge * Orthanc Explorer: include the url search params into HTTP headers to the Rest API to ease usage of the Authorization plugin Note that only the 'token', 'auth-token' & 'authorization' search params are transmitted into HTTP headers. - +* in /ordered-slices route, ignore instances without position/normal/seriesIndex +* Fix lost relationships between CT and RT-STRUCT during anonymization Version 1.5.7 (2019-06-25) ========================== diff -r 96780208dbd7 -r e481c2b32914 OrthancServer/SliceOrdering.cpp --- a/OrthancServer/SliceOrdering.cpp Wed Sep 11 13:21:50 2019 +0200 +++ b/OrthancServer/SliceOrdering.cpp Wed Sep 11 13:22:07 2019 +0200 @@ -310,7 +310,11 @@ for (std::list::const_iterator it = instancesId.begin(); it != instancesId.end(); ++it) { - instances_.push_back(new Instance(index_, *it)); + std::auto_ptr instance(new Instance(index_, *it)); + if (instance->HasPosition() || instance->HasNormal() || instance->HasIndexInSeries()) + { + instances_.push_back(instance.release()); + } } } diff -r 96780208dbd7 -r e481c2b32914 Plugins/Include/orthanc/OrthancCPlugin.h --- a/Plugins/Include/orthanc/OrthancCPlugin.h Wed Sep 11 13:21:50 2019 +0200 +++ b/Plugins/Include/orthanc/OrthancCPlugin.h Wed Sep 11 13:22:07 2019 +0200 @@ -1915,7 +1915,7 @@ typedef struct { OrthancPluginRestOutput* output; - const char* answer; + const void* answer; uint32_t answerSize; const char* mimeType; } _OrthancPluginAnswerBuffer; @@ -1935,7 +1935,7 @@ ORTHANC_PLUGIN_INLINE void OrthancPluginAnswerBuffer( OrthancPluginContext* context, OrthancPluginRestOutput* output, - const char* answer, + const void* answer, uint32_t answerSize, const char* mimeType) {