Mercurial > hg > orthanc
changeset 515:a8be42bcf2bb
Link from modified to original resource in Orthanc Explorer
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 19 Aug 2013 13:40:36 +0200 |
parents | 935e8c7e0b18 |
children | b2b56b4e33b0 |
files | NEWS OrthancExplorer/explorer.html OrthancExplorer/explorer.js OrthancServer/OrthancRestApi.cpp |
diffstat | 4 files changed, 105 insertions(+), 62 deletions(-) [+] |
line wrap: on
line diff
--- a/NEWS Fri Aug 16 17:11:45 2013 +0200 +++ b/NEWS Mon Aug 19 13:40:36 2013 +0200 @@ -3,6 +3,7 @@ * Detection of stable patients/studies/series * C-Find SCU at the instance level +* Link from modified to original resource in Orthanc Explorer Version 0.6.0 (2013/07/16)
--- a/OrthancExplorer/explorer.html Fri Aug 16 17:11:45 2013 +0200 +++ b/OrthancExplorer/explorer.html Mon Aug 19 13:40:36 2013 +0200 @@ -101,6 +101,9 @@ <li data-icon="info" data-theme="e" style="display:none"> <a href="#" id="patient-anonymized-from">Before anonymization</a> </li> + <li data-icon="info" data-theme="e" style="display:none"> + <a href="#" id="patient-modified-from">Before modification</a> + </li> <li data-icon="gear"><a href="#" id="patient-archive">Download ZIP</a></li> </ul> </div> @@ -144,6 +147,9 @@ <li data-icon="info" data-theme="e" style="display:none"> <a href="#" id="study-anonymized-from">Before anonymization</a> </li> + <li data-icon="info" data-theme="e" style="display:none"> + <a href="#" id="study-modified-from">Before modification</a> + </li> <li data-icon="gear"><a href="#" id="study-archive">Download ZIP</a></li> </ul> </div> @@ -189,6 +195,9 @@ <li data-icon="info" data-theme="e" style="display:none"> <a href="#" id="series-anonymized-from">Before anonymization</a> </li> + <li data-icon="info" data-theme="e" style="display:none"> + <a href="#" id="series-modified-from">Before modification</a> + </li> <li data-icon="search"><a href="#" id="series-preview">Preview this series</a></li> <li data-icon="gear"><a href="#" id="series-archive">Download ZIP</a></li> </ul> @@ -231,6 +240,12 @@ <ul data-role="listview" data-inset="true" data-theme="d" data-divider-theme="c"> <li data-role="list-divider">Access</li> + <li data-icon="info" data-theme="e" style="display:none"> + <a href="#" id="instance-anonymized-from">Before anonymization</a> + </li> + <li data-icon="info" data-theme="e" style="display:none"> + <a href="#" id="instance-modified-from">Before modification</a> + </li> <li data-icon="arrow-d"><a href="#" id="instance-download-dicom">Download the DICOM file</a></li> <li data-icon="arrow-d"><a href="#" id="instance-download-json">Download the JSON file</a></li> <li data-icon="search"><a href="#" id="instance-preview">Preview the instance</a></li>
--- a/OrthancExplorer/explorer.js Fri Aug 16 17:11:45 2013 +0200 +++ b/OrthancExplorer/explorer.js Mon Aug 19 13:40:36 2013 +0200 @@ -361,14 +361,13 @@ -function SetupAnonymizedFrom(buttonSelector, resource, resourceType) +function SetupAnonymizedOrModifiedFrom(buttonSelector, resource, resourceType, field) { - if ('AnonymizedFrom' in resource) + if (field in resource) { $(buttonSelector).closest('li').show(); $(buttonSelector).click(function(e) { - window.location.assign('explorer.html#' + resourceType + '?uuid=' + resource.AnonymizedFrom); - //window.location.reload(); + window.location.assign('explorer.html#' + resourceType + '?uuid=' + resource[field]); }); } else @@ -378,6 +377,7 @@ } + function RefreshPatient() { if ($.mobile.pageData) { @@ -404,7 +404,8 @@ target.append(FormatStudy(studies[i], '#study?uuid=' + studies[i].ID)); } - SetupAnonymizedFrom('#patient-anonymized-from', patient, 'patient'); + SetupAnonymizedOrModifiedFrom('#patient-anonymized-from', patient, 'patient', 'AnonymizedFrom'); + SetupAnonymizedOrModifiedFrom('#patient-modified-from', patient, 'patient', 'ModifiedFrom'); target.listview('refresh'); @@ -446,7 +447,8 @@ .append(FormatStudy(study)) .listview('refresh'); - SetupAnonymizedFrom('#study-anonymized-from', study, 'study'); + SetupAnonymizedOrModifiedFrom('#study-anonymized-from', study, 'study', 'AnonymizedFrom'); + SetupAnonymizedOrModifiedFrom('#study-modified-from', study, 'study', 'ModifiedFrom'); var target = $('#list-series'); $('li', target).remove(); @@ -491,7 +493,8 @@ .append(FormatSeries(series)) .listview('refresh'); - SetupAnonymizedFrom('#series-anonymized-from', series, 'series'); + SetupAnonymizedOrModifiedFrom('#series-anonymized-from', series, 'series', 'AnonymizedFrom'); + SetupAnonymizedOrModifiedFrom('#series-modified-from', series, 'series', 'ModifiedFrom'); var target = $('#list-instances'); $('li', target).remove(); @@ -595,6 +598,9 @@ } }); + SetupAnonymizedOrModifiedFrom('#instance-anonymized-from', instance, 'instance', 'AnonymizedFrom'); + SetupAnonymizedOrModifiedFrom('#instance-modified-from', instance, 'instance', 'ModifiedFrom'); + currentPage = 'instance'; currentUuid = $.mobile.pageData.uuid; });
--- a/OrthancServer/OrthancRestApi.cpp Fri Aug 16 17:11:45 2013 +0200 +++ b/OrthancServer/OrthancRestApi.cpp Mon Aug 19 13:40:36 2013 +0200 @@ -1031,8 +1031,6 @@ throw OrthancException(ErrorCode_BadRequest); } - target.clear(); - for (Json::Value::ArrayIndex i = 0; i < removals.size(); i++) { std::string name = removals[i].asString(); @@ -1052,8 +1050,6 @@ throw OrthancException(ErrorCode_BadRequest); } - target.clear(); - Json::Value::Members members = replacements.getMemberNames(); for (size_t i = 0; i < members.size(); i++) { @@ -1099,7 +1095,7 @@ removals.insert(DicomTag(0x0008, 0x1155)); // Referenced SOP Instance UID removals.insert(DicomTag(0x0008, 0x2111)); // Derivation Description removals.insert(DicomTag(0x0010, 0x0010)); // Patient's Name - removals.insert(DicomTag(0x0010, 0x0020)); // Patient ID + //removals.insert(DicomTag(0x0010, 0x0020)); // Patient ID => cf. below (*) removals.insert(DicomTag(0x0010, 0x0030)); // Patient's Birth Date removals.insert(DicomTag(0x0010, 0x0032)); // Patient's Birth Time removals.insert(DicomTag(0x0010, 0x0040)); // Patient's Sex @@ -1115,8 +1111,8 @@ removals.insert(DicomTag(0x0010, 0x4000)); // Patient Comments removals.insert(DicomTag(0x0018, 0x1000)); // Device Serial Number removals.insert(DicomTag(0x0018, 0x1030)); // Protocol Name - //removals.insert(DicomTag(0x0020, 0x000d)); // Study Instance UID => generated below - //removals.insert(DicomTag(0x0020, 0x000e)); // Series Instance UID => generated below + //removals.insert(DicomTag(0x0020, 0x000d)); // Study Instance UID => cf. below (*) + //removals.insert(DicomTag(0x0020, 0x000e)); // Series Instance UID => cf. below (*) removals.insert(DicomTag(0x0020, 0x0010)); // Study ID removals.insert(DicomTag(0x0020, 0x0052)); // Frame of Reference UID removals.insert(DicomTag(0x0020, 0x0200)); // Synchronization Frame of Reference UID @@ -1128,6 +1124,14 @@ removals.insert(DicomTag(0x3006, 0x0024)); // Referenced Frame of Reference UID removals.insert(DicomTag(0x3006, 0x00c2)); // Related Frame of Reference UID + /** + * (*) Patient ID, Study Instance UID and Series Instance UID + * are modified by "AnonymizeInstance()" if anonymizing a single + * instance, or by "RetrieveMappedUid()" if anonymizing a + * patient/study/series. + **/ + + // Some more removals (from the experience of DICOM files at the CHU of Liege) removals.insert(DicomTag(0x0010, 0x1040)); // Patient's Address removals.insert(DicomTag(0x0032, 0x1032)); // Requesting Physician @@ -1136,22 +1140,8 @@ // Set the DeidentificationMethod tag replacements.insert(std::make_pair(DicomTag(0x0012, 0x0063), "Orthanc " ORTHANC_VERSION " - PS 3.15-2008 Table E.1-1")); - // Set the PatientIdentityRemoved + // Set the PatientIdentityRemoved tag replacements.insert(std::make_pair(DicomTag(0x0012, 0x0062), "YES")); - - // Generate random study UID if not specified - if (replacements.find(DICOM_TAG_STUDY_INSTANCE_UID) == replacements.end()) - { - replacements.insert(std::make_pair(DICOM_TAG_STUDY_INSTANCE_UID, - FromDcmtkBridge::GenerateUniqueIdentifier(DicomRootLevel_Study))); - } - - // Generate random series UID if not specified - if (replacements.find(DICOM_TAG_SERIES_INSTANCE_UID) == replacements.end()) - { - replacements.insert(std::make_pair(DICOM_TAG_SERIES_INSTANCE_UID, - FromDcmtkBridge::GenerateUniqueIdentifier(DicomRootLevel_Series))); - } } @@ -1254,13 +1244,6 @@ replacements.insert(std::make_pair(DicomTag(0x0010, 0x0010), GeneratePatientName(context))); } - // Generate random Patient's ID if none is specified - if (replacements.find(DICOM_TAG_PATIENT_ID) == replacements.end()) - { - replacements.insert(std::make_pair(DICOM_TAG_PATIENT_ID, - FromDcmtkBridge::GenerateUniqueIdentifier(DicomRootLevel_Patient))); - } - return true; } else @@ -1293,14 +1276,23 @@ UidMap& uidMap) { std::auto_ptr<DicomTag> tag; - if (level == DicomRootLevel_Series) + + switch (level) { - tag.reset(new DicomTag(DICOM_TAG_SERIES_INSTANCE_UID)); - } - else - { - assert(level == DicomRootLevel_Study); - tag.reset(new DicomTag(DICOM_TAG_STUDY_INSTANCE_UID)); + case DicomRootLevel_Series: + tag.reset(new DicomTag(DICOM_TAG_SERIES_INSTANCE_UID)); + break; + + case DicomRootLevel_Study: + tag.reset(new DicomTag(DICOM_TAG_STUDY_INSTANCE_UID)); + break; + + case DicomRootLevel_Patient: + tag.reset(new DicomTag(DICOM_TAG_PATIENT_ID)); + break; + + default: + throw OrthancException(ErrorCode_InternalError); } std::string original; @@ -1330,7 +1322,8 @@ } - static void AnonymizeOrModifyResource(Removals& removals, + static void AnonymizeOrModifyResource(bool isAnonymization, + Removals& removals, Replacements& replacements, bool removePrivateTags, MetadataType metadataType, @@ -1367,15 +1360,20 @@ LOG(INFO) << "Modifying instance " << *it; ParsedDicomFile& original = context.GetDicomFile(*it); - bool isNewSeries = RetrieveMappedUid(original, DicomRootLevel_Series, replacements, uidMap); + DicomInstanceHasher originalHasher = original.GetHasher(); - bool isNewStudy = false; - if (resourceType == ResourceType_Study || - resourceType == ResourceType_Patient) + if (isFirst && !isAnonymization) { - isNewStudy = RetrieveMappedUid(original, DicomRootLevel_Study, replacements, uidMap); + // If modifying a study or a series, keep the original patient ID. + std::string patientId = originalHasher.GetPatientId(); + uidMap[std::make_pair(DicomRootLevel_Patient, patientId)] = patientId; } + bool isNewSeries = RetrieveMappedUid(original, DicomRootLevel_Series, replacements, uidMap); + bool isNewStudy = RetrieveMappedUid(original, DicomRootLevel_Study, replacements, uidMap); + bool isNewPatient = RetrieveMappedUid(original, DicomRootLevel_Patient, replacements, uidMap); + + /** * Compute the resulting DICOM instance and store it into the Orthanc store. **/ @@ -1396,7 +1394,6 @@ **/ DicomInstanceHasher modifiedHasher = modified->GetHasher(); - DicomInstanceHasher originalHasher = original.GetHasher(); if (isNewSeries) { @@ -1410,6 +1407,12 @@ metadataType, originalHasher.HashStudy()); } + if (isNewPatient) + { + context.GetIndex().SetMetadata(modifiedHasher.HashPatient(), + metadataType, originalHasher.HashPatient()); + } + assert(*it == originalHasher.HashInstance()); assert(modifiedInstance == modifiedHasher.HashInstance()); context.GetIndex().SetMetadata(modifiedInstance, metadataType, *it); @@ -1421,9 +1424,6 @@ if (isFirst) { - context.GetIndex().SetMetadata(modifiedHasher.HashPatient(), - metadataType, originalHasher.HashPatient()); - std::string newId; switch (resourceType) @@ -1478,6 +1478,27 @@ if (ParseAnonymizationRequest(removals, replacements, removePrivateTags, call)) { + // Generate random patient ID if not specified + if (replacements.find(DICOM_TAG_PATIENT_ID) == replacements.end()) + { + replacements.insert(std::make_pair(DICOM_TAG_PATIENT_ID, + FromDcmtkBridge::GenerateUniqueIdentifier(DicomRootLevel_Patient))); + } + + // Generate random study UID if not specified + if (replacements.find(DICOM_TAG_STUDY_INSTANCE_UID) == replacements.end()) + { + replacements.insert(std::make_pair(DICOM_TAG_STUDY_INSTANCE_UID, + FromDcmtkBridge::GenerateUniqueIdentifier(DicomRootLevel_Study))); + } + + // Generate random series UID if not specified + if (replacements.find(DICOM_TAG_SERIES_INSTANCE_UID) == replacements.end()) + { + replacements.insert(std::make_pair(DICOM_TAG_SERIES_INSTANCE_UID, + FromDcmtkBridge::GenerateUniqueIdentifier(DicomRootLevel_Series))); + } + AnonymizeOrModifyInstance(removals, replacements, removePrivateTags, call); } } @@ -1491,7 +1512,7 @@ if (ParseModifyRequest(removals, replacements, removePrivateTags, call)) { - AnonymizeOrModifyResource(removals, replacements, removePrivateTags, + AnonymizeOrModifyResource(false, removals, replacements, removePrivateTags, MetadataType_ModifiedFrom, ChangeType_ModifiedSeries, ResourceType_Series, call); } @@ -1506,7 +1527,7 @@ if (ParseAnonymizationRequest(removals, replacements, removePrivateTags, call)) { - AnonymizeOrModifyResource(removals, replacements, removePrivateTags, + AnonymizeOrModifyResource(true, removals, replacements, removePrivateTags, MetadataType_AnonymizedFrom, ChangeType_AnonymizedSeries, ResourceType_Series, call); } @@ -1521,7 +1542,7 @@ if (ParseModifyRequest(removals, replacements, removePrivateTags, call)) { - AnonymizeOrModifyResource(removals, replacements, removePrivateTags, + AnonymizeOrModifyResource(false, removals, replacements, removePrivateTags, MetadataType_ModifiedFrom, ChangeType_ModifiedStudy, ResourceType_Study, call); } @@ -1536,14 +1557,14 @@ if (ParseAnonymizationRequest(removals, replacements, removePrivateTags, call)) { - AnonymizeOrModifyResource(removals, replacements, removePrivateTags, + AnonymizeOrModifyResource(true, removals, replacements, removePrivateTags, MetadataType_AnonymizedFrom, ChangeType_AnonymizedStudy, ResourceType_Study, call); } } - static void ModifyPatientInplace(RestApi::PostCall& call) + /*static void ModifyPatientInplace(RestApi::PostCall& call) { Removals removals; Replacements replacements; @@ -1551,11 +1572,11 @@ if (ParseModifyRequest(removals, replacements, removePrivateTags, call)) { - AnonymizeOrModifyResource(removals, replacements, removePrivateTags, + AnonymizeOrModifyResource(false, removals, replacements, removePrivateTags, MetadataType_ModifiedFrom, ChangeType_ModifiedPatient, ResourceType_Patient, call); } - } + }*/ static void AnonymizePatientInplace(RestApi::PostCall& call) @@ -1566,7 +1587,7 @@ if (ParseAnonymizationRequest(removals, replacements, removePrivateTags, call)) { - AnonymizeOrModifyResource(removals, replacements, removePrivateTags, + AnonymizeOrModifyResource(true, removals, replacements, removePrivateTags, MetadataType_AnonymizedFrom, ChangeType_AnonymizedPatient, ResourceType_Patient, call); } @@ -1834,7 +1855,7 @@ Register("/instances/{id}/modify", ModifyInstance); Register("/series/{id}/modify", ModifySeriesInplace); Register("/studies/{id}/modify", ModifyStudyInplace); - Register("/patients/{id}/modify", ModifyPatientInplace); + //Register("/patients/{id}/modify", ModifyPatientInplace); Register("/instances/{id}/anonymize", AnonymizeInstance); Register("/series/{id}/anonymize", AnonymizeSeriesInplace);