public void TestValidatePatientsNameAllowEmpty() { Initialize(); _file.DataSet[DicomTags.PatientsName].SetStringValue("Patient^Anonymous^Mr"); StudyData studyPrototype = CreateStudyPrototype(); studyPrototype.PatientsNameRaw = ""; DicomAnonymizer anonymizer = new DicomAnonymizer(); anonymizer.ValidationOptions = ValidationOptions.AllowEmptyPatientName; anonymizer.StudyDataPrototype = studyPrototype; anonymizer.Anonymize(_file); }
public void TestFileMetaInformation() { Initialize(); string oldUid = _file.DataSet[DicomTags.SopInstanceUid].ToString(); StudyData studyPrototype = CreateStudyPrototype(); DicomAnonymizer anonymizer = new DicomAnonymizer(); anonymizer.StudyDataPrototype = studyPrototype; anonymizer.Anonymize(_file); Assert.AreNotEqual(oldUid, _file.DataSet[DicomTags.SopInstanceUid].ToString(), "Patient Confidentiality Issue - SOP Instance Uid is not anonymized."); Assert.AreNotEqual(oldUid, _file.MetaInfo[DicomTags.MediaStorageSopInstanceUid].ToString(), "Patient Confidentiality Issue - Media Storage SOP Instance Uid is not anonymized."); Assert.AreNotEqual(oldUid, _file.MediaStorageSopInstanceUid, "Patient Confidentiality Issue - Media Storage SOP Instance Uid is not anonymized."); Assert.AreEqual(_file.DataSet[DicomTags.SopInstanceUid].ToString(), _file.MetaInfo[DicomTags.MediaStorageSopInstanceUid].ToString(), "MetaInfo Media Storage SOP Instance doesn't match DataSet SOP Instance."); Assert.AreEqual(_file.DataSet[DicomTags.SopClassUid].ToString(), _file.MetaInfo[DicomTags.MediaStorageSopClassUid].ToString(), "MetaInfo Media Storage SOP Class doesn't match DataSet SOP Class."); }
public void Anonymize_UsePredefinedPatientNameAndId_ShouldBeSetInAnonymizedDataset() { const string fileName = "CT1_J2KI"; var dataset = DicomFile.Open($"./Test Data/{fileName}").Dataset; const string expectedName = "fo-dicom"; const string expectedId = "GH-575"; var anonymizer = new DicomAnonymizer(); anonymizer.Profile.PatientName = expectedName; anonymizer.Profile.PatientID = expectedId; var newDataset = anonymizer.Anonymize(dataset); var actualName = newDataset.GetSingleValue <string>(DicomTag.PatientName); var actualId = newDataset.GetSingleValue <string>(DicomTag.PatientID); Assert.Equal(expectedName, actualName); Assert.Equal(expectedId, actualId); }
public void Anonymize_PatientName_ShouldUseOriginalDicomEncoding() { const string fileName = "GH064.dcm"; var originalDicom = DicomFile.Open($"./Test Data/{fileName}"); var securityProfile = DicomAnonymizer.SecurityProfile.LoadProfile(null, DicomAnonymizer.SecurityProfileOptions.BasicProfile); securityProfile.PatientName = "kökö"; var dicomAnonymizer = new DicomAnonymizer(securityProfile); var anonymizedDicom = dicomAnonymizer.Anonymize(originalDicom); // Ensure that we are using valid input data for test. Assert.Equal(Encoding.ASCII, DicomEncoding.Default); Assert.NotEqual(DicomEncoding.GetEncoding(originalDicom.Dataset.GetString(DicomTag.SpecificCharacterSet)), DicomEncoding.Default); // Ensure DICOM encoding same as original. Assert.Equal(originalDicom.Dataset.GetString(DicomTag.SpecificCharacterSet), anonymizedDicom.Dataset.GetString(DicomTag.SpecificCharacterSet)); Assert.Equal("kökö", anonymizedDicom.Dataset.GetString(DicomTag.PatientName)); }
private void SaveFile(string filename) { if (_anonymizer != null) { DicomFile dicomFile = new DicomFile(filename); dicomFile.Load(); _anonymizer.Anonymize(dicomFile); //anonymize first, then audit, since this is what gets exported. _exportedInstances.AddInstance( dicomFile.DataSet[DicomTags.PatientId].ToString(), dicomFile.DataSet[DicomTags.PatientsName].ToString(), dicomFile.DataSet[DicomTags.StudyInstanceUid].ToString(), filename); string fileName = System.IO.Path.Combine(OutputPath, dicomFile.MediaStorageSopInstanceUid); fileName += ".dcm"; CheckFileExists(fileName); // this will never happen for anonymized images. if (_canceled) { return; } dicomFile.Save(fileName); } else { _exportedInstances.AddPath(filename, false); string destination = Path.Combine(OutputPath, Path.GetFileName(filename)); CheckFileExists(destination); if (_canceled) { return; } File.Copy(filename, destination, true); } }
public void TestStrict() { DicomFile file = CreateTestFile(); DicomAnonymizer anonymizer = new DicomAnonymizer(); anonymizer.ValidationOptions = ValidationOptions.RelaxAllChecks; try { //this ought to work. anonymizer.Anonymize(file); } catch (Exception) { Assert.Fail("Not strict - no exception expected."); } anonymizer = new DicomAnonymizer(); Assert.IsTrue(anonymizer.ValidationOptions == ValidationOptions.Default); //strict by default //should throw. anonymizer.Anonymize(CreateTestFile()); }
private void OnClickAnonymize(object sender, EventArgs e) { var file = _anonymizer.Anonymize(_file); OpenFile(file); }
public void TestValidatePatientsNameNotEqual() { Initialize(); _file.DataSet[DicomTags.PatientsName].SetStringValue("Patient^Anonymous^Mr"); StudyData studyPrototype = CreateStudyPrototype(); studyPrototype.PatientsNameRaw = "PATIENT^ANONYMOUS"; DicomAnonymizer anonymizer = new DicomAnonymizer(); anonymizer.StudyDataPrototype = studyPrototype; anonymizer.Anonymize(_file); }
public void TestRemappedReferencedSopUids() { // setup some files with unique "uids" DicomFile[] originals = new DicomFile[8]; for (int n = 0; n < originals.Length; n++) { originals[n] = new DicomFile(); originals[n].DataSet[DicomTags.StudyInstanceUid].SetStringValue((1000 + (n >> 2)).ToString()); originals[n].DataSet[DicomTags.SeriesInstanceUid].SetStringValue((100 + (n >> 1)).ToString()); originals[n].DataSet[DicomTags.SopInstanceUid].SetStringValue((10 + n).ToString()); originals[n].DataSet[DicomTags.SopClassUid].SetStringValue((11111111111).ToString()); } // setup up some cyclic and self references for (int n = 0; n < originals.Length; n++) { DicomSequenceItem sq; DicomFile n0File = originals[n]; DicomFile n1File = originals[(n + 1)%originals.Length]; DicomFile n2File = originals[(n + 2)%originals.Length]; DicomFile n4File = originals[(n + 4)%originals.Length]; n0File.DataSet[DicomTags.Uid].SetStringValue(n0File.DataSet[DicomTags.SopInstanceUid].ToString()); n0File.DataSet[DicomTags.ReferencedSopInstanceUid].SetStringValue(n1File.DataSet[DicomTags.SopInstanceUid].ToString()); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.Uid].SetStringValue(DicomUid.GenerateUid().UID); sq[DicomTags.TextString].SetStringValue("UID of something not in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.Uid].SetStringValue(n0File.DataSet[DicomTags.SopInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("UID of self"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.Uid].SetStringValue(n1File.DataSet[DicomTags.SopInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("UID of next file in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.Uid].SetStringValue(n1File.DataSet[DicomTags.SeriesInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("UID of next file series in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.Uid].SetStringValue(n1File.DataSet[DicomTags.StudyInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("UID of next file study in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.Uid].SetStringValue(n2File.DataSet[DicomTags.SopInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("UID of 2nd next file in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.Uid].SetStringValue(n2File.DataSet[DicomTags.SeriesInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("UID of 2nd next file series in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.Uid].SetStringValue(n2File.DataSet[DicomTags.StudyInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("UID of 2nd next file study in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.Uid].SetStringValue(n4File.DataSet[DicomTags.SopInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("UID of 4th next file in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.Uid].SetStringValue(n4File.DataSet[DicomTags.SeriesInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("UID of 4th next file series in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.Uid].SetStringValue(n4File.DataSet[DicomTags.StudyInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("UID of 4th next file study in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.ReferencedSopInstanceUid].SetStringValue(DicomUid.GenerateUid().UID); sq[DicomTags.TextString].SetStringValue("Sop UID of something not in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.ReferencedSopInstanceUid].SetStringValue(n0File.DataSet[DicomTags.SopInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("Sop UID of self"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.ReferencedSopInstanceUid].SetStringValue(n1File.DataSet[DicomTags.SopInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("Sop UID of next file in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.ReferencedSopInstanceUid].SetStringValue(n2File.DataSet[DicomTags.SopInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("Sop UID of 2nd next file in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.ReferencedSopInstanceUid].SetStringValue(n4File.DataSet[DicomTags.SopInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("Sop UID of 4th next file in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.SeriesInstanceUid].SetStringValue(DicomUid.GenerateUid().UID); sq[DicomTags.TextString].SetStringValue("Series UID of something not in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.SeriesInstanceUid].SetStringValue(n0File.DataSet[DicomTags.SeriesInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("Series UID of self series"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.SeriesInstanceUid].SetStringValue(n1File.DataSet[DicomTags.SeriesInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("Series UID of next file series in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.SeriesInstanceUid].SetStringValue(n2File.DataSet[DicomTags.SeriesInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("Series UID of 2nd next file series in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.SeriesInstanceUid].SetStringValue(n4File.DataSet[DicomTags.SeriesInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("Series UID of 4th next file series in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.StudyInstanceUid].SetStringValue(DicomUid.GenerateUid().UID); sq[DicomTags.TextString].SetStringValue("Study UID of something not in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.StudyInstanceUid].SetStringValue(n0File.DataSet[DicomTags.StudyInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("Study UID of self study"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.StudyInstanceUid].SetStringValue(n1File.DataSet[DicomTags.StudyInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("Study UID of next file study in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.StudyInstanceUid].SetStringValue(n2File.DataSet[DicomTags.StudyInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("Study UID of 2nd next file study in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.StudyInstanceUid].SetStringValue(n4File.DataSet[DicomTags.StudyInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("Study UID of 4th next file study in data set"); n0File.DataSet[DicomTags.ReferencedStudySequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.TextString].SetStringValue("A more typical hierarchical sop reference to self"); sq[DicomTags.StudyInstanceUid].SetStringValue(n0File.DataSet[DicomTags.StudyInstanceUid].ToString()); sq[DicomTags.ReferencedSeriesSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.SeriesInstanceUid].SetStringValue(n0File.DataSet[DicomTags.SeriesInstanceUid].ToString()); sq[DicomTags.ReferencedSopSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.ReferencedSopInstanceUid].SetStringValue(n0File.DataSet[DicomTags.SopInstanceUid].ToString()); n0File.DataSet[DicomTags.ReferencedStudySequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.TextString].SetStringValue("A more typical hierarchical sop reference to next"); sq[DicomTags.StudyInstanceUid].SetStringValue(n1File.DataSet[DicomTags.StudyInstanceUid].ToString()); sq[DicomTags.ReferencedSeriesSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.SeriesInstanceUid].SetStringValue(n1File.DataSet[DicomTags.SeriesInstanceUid].ToString()); sq[DicomTags.ReferencedSopSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.ReferencedSopInstanceUid].SetStringValue(n1File.DataSet[DicomTags.SopInstanceUid].ToString()); n0File.DataSet[DicomTags.ReferencedStudySequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.TextString].SetStringValue("A more typical hierarchical sop reference to 2nd next"); sq[DicomTags.StudyInstanceUid].SetStringValue(n2File.DataSet[DicomTags.StudyInstanceUid].ToString()); sq[DicomTags.ReferencedSeriesSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.SeriesInstanceUid].SetStringValue(n2File.DataSet[DicomTags.SeriesInstanceUid].ToString()); sq[DicomTags.ReferencedSopSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.ReferencedSopInstanceUid].SetStringValue(n2File.DataSet[DicomTags.SopInstanceUid].ToString()); n0File.DataSet[DicomTags.ReferencedStudySequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.TextString].SetStringValue("A more typical hierarchical sop reference to 4th next"); sq[DicomTags.StudyInstanceUid].SetStringValue(n4File.DataSet[DicomTags.StudyInstanceUid].ToString()); sq[DicomTags.ReferencedSeriesSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.SeriesInstanceUid].SetStringValue(n4File.DataSet[DicomTags.SeriesInstanceUid].ToString()); sq[DicomTags.ReferencedSopSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.ReferencedSopInstanceUid].SetStringValue(n4File.DataSet[DicomTags.SopInstanceUid].ToString()); } // copy the originals and anonymize them DicomFile[] anonymized = new DicomFile[originals.Length]; DicomAnonymizer anonymizer = new DicomAnonymizer(); anonymizer.ValidationOptions = ValidationOptions.RelaxAllChecks; for (int n = 0; n < anonymized.Length; n++) { anonymized[n] = new DicomFile(string.Empty, originals[n].MetaInfo.Copy(true, true, true), originals[n].DataSet.Copy(true, true, true)); anonymizer.Anonymize(anonymized[n]); } // generate validation dump strings - unique uids are mapped to sequential numbers string originalDumpValidationString = GenerateHierarchicalUidValidationDumpString(originals); string anonymizedDumpValidationString = GenerateHierarchicalUidValidationDumpString(anonymized); // if the hierarchical structure and pattern of uids is the same, then the relationships have been preserved. Assert.AreEqual(originalDumpValidationString, anonymizedDumpValidationString, "Relationships of anonymized data set differ compared to those of original data set."); }
public DicomCStoreResponse OnCStoreRequest(DicomCStoreRequest request) { Console.WriteLine("received cstore request " + request.ToString()); if (File.Exists("singleImage.txt")) { Console.WriteLine("now save on ./images/file.jpg"); File.Delete("./images/file.dcm"); var dicomFile = new DicomFile(request.File.Dataset); // dicomFile.ChangeTransferSyntax(DicomTransferSyntax.JPEGProcess14SV1); dicomFile.Save("./images/file.dcm"); var image = new DicomImage("./images/file.dcm"); File.Delete("./images/file.jpg"); image.RenderImage().AsClonedBitmap().Save("./images/file.jpg"); } else // else save image to database { Console.WriteLine("now save in database" + Environment.NewLine); try { // get parameters string dateString = ""; request.Dataset.TryGetSingleValue(DicomTag.StudyDate, out dateString); DateTime date = DateTime.ParseExact(dateString, "yyyyMMdd", CultureInfo.InvariantCulture); string StudyInstanceUID = ""; request.Dataset.TryGetSingleValue(DicomTag.StudyInstanceUID, out StudyInstanceUID); string SeriesInstanceUID = ""; request.Dataset.TryGetSingleValue(DicomTag.SeriesInstanceUID, out SeriesInstanceUID); string SOPInstanceUID = ""; request.Dataset.TryGetSingleValue(DicomTag.SOPInstanceUID, out SOPInstanceUID); // save in database folder var pathInDatabase = Path.GetFullPath("./databaseFolder"); // take last two numbers, for examples seriesinstanceuid ends with .150.0 var seriesUIDs = SeriesInstanceUID.Split('.'); string seriesUID = seriesUIDs[seriesUIDs.Length - 2] + "." + seriesUIDs[seriesUIDs.Length - 1]; var sopUIDs = SOPInstanceUID.Split('.'); string sopUID = sopUIDs[sopUIDs.Length - 2] + "." + sopUIDs[sopUIDs.Length - 1]; pathInDatabase = Path.Combine(pathInDatabase, date.Year.ToString(), date.Month.ToString(), date.Day.ToString(), StudyInstanceUID, seriesUID); if (!Directory.Exists(pathInDatabase)) { Directory.CreateDirectory(pathInDatabase); } string imagePath = Path.Combine(pathInDatabase, sopUID + ".dcm"); if (!File.Exists(imagePath)) { request.File.Save(imagePath); Console.WriteLine("received and saved a file in database"); } else { Console.WriteLine("File already present in database"); } //DicomAnonymizer.SecurityProfileOptions. var profile = new DicomAnonymizer.SecurityProfile(); profile.PatientName = "random"; DicomAnonymizer anonymizer = new DicomAnonymizer(profile); DicomDataset anonymizedDataset = anonymizer.Anonymize(request.Dataset); // DICOMANONYMYZER + DICOMDIR DATABASE DicomDirectoryTest s = new DicomDirectoryTest(); // // get more data string PatientName = ""; anonymizedDataset.TryGetSingleValue(DicomTag.PatientName, out PatientName); Console.WriteLine("patient name " + PatientName); string PatientID = ""; anonymizedDataset.TryGetSingleValue(DicomTag.PatientID, out PatientID); // add entry in database var study = new StudyQueryOut { StudyInstanceUID = StudyInstanceUID, PatientID = PatientID, PatientName = PatientName, StudyDate = date }; using (var db = new LiteDatabase("./databaseFolder/database.db")) { var studies = db.GetCollection <StudyQueryOut>("studies"); if (studies.FindById(StudyInstanceUID) == null) { studies.Insert(study); } } } catch (Exception ec) { Console.WriteLine(ec.Message + " " + ec.ToString()); } } return(new DicomCStoreResponse(request, DicomStatus.Success)); }
public void TestValidateStudyIdNotEqual() { Initialize(); _file.DataSet[DicomTags.StudyId].SetStringValue("123"); StudyData studyPrototype = CreateStudyPrototype(); studyPrototype.StudyId = "123"; DicomAnonymizer anonymizer = new DicomAnonymizer(); anonymizer.StudyDataPrototype = studyPrototype; anonymizer.Anonymize(_file); }
private List <SopInstanceNode> DoBuildTree() { bool doAnonymize = _anonymize; Dictionary <string, string> uidMap = new Dictionary <string, string>(); List <SopInstanceNode> sops = new List <SopInstanceNode>(); // TODO: perform some performance tests to adjust these weights float aweight = doAnonymize ? 0.45f : 0; // portion of the work to anonymize the instances float pweight = (1 - aweight) * 0.75f; // portion of the work to reassign uids float mweight = 1 - pweight - aweight; // portion of the work to remap related uids int count = _patients.Count; int now = 0; this.Progress = 0; // traverse the tree assign new instance uids foreach (PatientNode patient in _patients) { if (patient.Parent != _rootNode) { throw new NullReferenceException("Unsynchronized parent-child relationship"); } now++; foreach (StudyNode study in patient.Studies) { if (study.Parent != patient) { throw new NullReferenceException("Unsynchronized parent-child relationship"); } string studyUid = NewUid(); uidMap.Add(study.InstanceUid, studyUid); study.InstanceUid = studyUid; foreach (SeriesNode series in study.Series) { if (series.Parent != study) { throw new NullReferenceException("Unsynchronized parent-child relationship"); } string seriesUid = NewUid(); uidMap.Add(series.InstanceUid, seriesUid); series.InstanceUid = seriesUid; foreach (SopInstanceNode sop in series.Images) { if (sop.Parent != series) { throw new NullReferenceException("Unsynchronized parent-child relationship"); } string sopUid = NewUid(); uidMap.Add(sop.InstanceUid, sopUid); sop.InstanceUid = sopUid; patient.Update(sop.DicomData); study.Update(sop.DicomData, true); series.Update(sop.DicomData, true); sop.Update(sop.DicomData, true); sops.Add(sop); } } } this.Progress = mweight * now / count; } // map any uids that point to an instance that was just reassigned count = sops.Count; now = 0; foreach (SopInstanceNode sop in sops) { MapKnownUids(sop.DicomData, uidMap); now++; this.Progress = mweight * now / count; } // run the anonymizer if required if (doAnonymize) { DicomAnonymizer anonymizer = new DicomAnonymizer(); anonymizer.ValidationOptions = ValidationOptions.RelaxAllChecks; count = sops.Count; now = 0; foreach (SopInstanceNode sop in sops) { anonymizer.Anonymize(sop.DicomFile); SeriesNode series = sop.Parent; StudyNode study = series.Parent; PatientNode patient = study.Parent; // overwrite the anonymized data with any edited properties // anonymizer writes in new anonymized uids based on the new structure, so don't overwrite them! // instead, get the new uids and put them back into the node patient.Update(sop.DicomData); study.Update(sop.DicomData, false); study.InstanceUid = sop.DicomData[DicomTags.StudyInstanceUid].GetString(0, ""); series.Update(sop.DicomData, false); series.InstanceUid = sop.DicomData[DicomTags.SeriesInstanceUid].GetString(0, ""); sop.Update(sop.DicomData, false); sop.InstanceUid = sop.DicomData[DicomTags.SopInstanceUid].GetString(0, ""); now++; this.Progress = mweight * now / count; } } return(sops); }
string WorkerFunc(Tuple <string, Tuple <int, int, int, int>, List <string> > param, BackgroundWorker worker, DoWorkEventArgs e) { List <string> lFailed = new List <string>(); string strPath = param.Item1; Tuple <int, int, int, int> lCrop = param.Item2; List <string> files = param.Item3; bool bCrop = lCrop.Item1 + lCrop.Item2 + lCrop.Item3 + lCrop.Item4 > 0 ? true : false; DicomUIDGenerator uidGen = new DicomUIDGenerator(); List <Tuple <string, string, string, string> > listDCM = new List <Tuple <string, string, string, string> >(); int i = 0, k = 0; // Randomize input list Random rand = new Random(); // For each spot in the array, pick // a random item to swap into that spot. for (k = 0; k < files.Count - 1; k++) { int j = rand.Next(k, files.Count); string temp = files[k]; files[k] = files[j]; files[j] = temp; } DateTime dt = DateTime.Now; int nSuccess = 0; foreach (string strFile in files) { i++; DicomFile file; try { file = DicomFile.Open(strFile); } catch (Exception ex) { // Transmit message back with worker? lFailed.Add(strFile); System.Diagnostics.Debug.WriteLine(ex.ToString()); continue; } string strOriginalPatientID = ""; try { strOriginalPatientID = file.Dataset.GetValue <string>(DicomTag.PatientID, 0); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.ToString()); } DicomAnonymizer anon = new DicomAnonymizer(); DicomFile fileAnon; try { fileAnon = anon.Anonymize(file); } catch (Exception ex) { // Transmit message back with worker? lFailed.Add(strFile); System.Diagnostics.Debug.WriteLine(ex.ToString()); continue; } DicomTag[] tagsToRemove = { DicomTag.StudyDate, DicomTag.StudyTime, DicomTag.PatientID, DicomTag.StudyID, DicomTag.StudyInstanceUID }; foreach (DicomTag d in tagsToRemove) { try { fileAnon.Dataset.Remove(d); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine("Error removing element: " + ex.ToString()); } } fileAnon.Dataset.Add(DicomTag.StudyInstanceUID, DicomUID.Generate()); fileAnon.Dataset.Add(DicomTag.StudyDate, dt.Year.ToString("0000") + dt.Month.ToString("00") + dt.Day.ToString("00")); fileAnon.Dataset.Add(DicomTag.StudyTime, dt.Hour.ToString("00") + dt.Minute.ToString("00") + dt.Second.ToString("00")); fileAnon.Dataset.Add(DicomTag.PatientID, i.ToString()); fileAnon.Dataset.Add(DicomTag.StudyID, i.ToString()); string strStudyID = fileAnon.Dataset.GetValue <string>(DicomTag.StudyInstanceUID, 0); try { var header = DicomPixelData.Create(fileAnon.Dataset); var pixelData = PixelDataFactory.Create(header, header.NumberOfFrames - 1); int rows = header.Height; int columns = header.Width; Array a; byte[] result; bool b16bit = false; if (pixelData is GrayscalePixelDataU16) { ushort[] pixels = ((GrayscalePixelDataU16)pixelData).Data; a = pixels; b16bit = true; } else if (pixelData is GrayscalePixelDataS16) { short[] pixels = ((GrayscalePixelDataS16)pixelData).Data; a = pixels; b16bit = true; } else if (pixelData is GrayscalePixelDataU32) { uint[] pixels = ((GrayscalePixelDataU32)pixelData).Data; a = pixels; } else if (pixelData is GrayscalePixelDataS32) { int[] pixels = ((GrayscalePixelDataS32)pixelData).Data; a = pixels; } else if (pixelData is GrayscalePixelDataU8) { byte[] pixels = ((GrayscalePixelDataU8)pixelData).Data; a = pixels; } else { throw new Exception("DICOM image format not supported (this program only supports greyscale)."); } // Can't seem to figure out the byte formatting between 16-bit greyscale DCM versus C#'s 16-bit greyscale. //b16bit = false; if (bCrop) { // Top if (lCrop.Item1 > 0) { Array cropped = Array.CreateInstance(a.GetValue(0).GetType(), a.Length - (columns * lCrop.Item1)); Array.Copy(a, columns * lCrop.Item1, cropped, 0, cropped.Length); a = cropped; rows -= lCrop.Item1; } // Right if (lCrop.Item2 > 0) { Array cropped = Array.CreateInstance(a.GetValue(0).GetType(), a.Length - (rows * lCrop.Item2)); for (k = 0; k < rows; k++) { Array.Copy(a, k * columns, cropped, k * (columns - lCrop.Item2), columns - lCrop.Item2); } a = cropped; columns -= lCrop.Item2; } // Bottom if (lCrop.Item3 > 0) { Array cropped = Array.CreateInstance(a.GetValue(0).GetType(), a.Length - (columns * lCrop.Item3)); Array.Copy(a, 0, cropped, 0, cropped.Length); a = cropped; rows -= lCrop.Item3; } // Left if (lCrop.Item4 > 0) { Array cropped = Array.CreateInstance(a.GetValue(0).GetType(), a.Length - (rows * lCrop.Item4)); for (k = 0; k < rows; k++) { Array.Copy(a, k * columns + lCrop.Item4, cropped, k * (columns - lCrop.Item4), columns - lCrop.Item4); } a = cropped; columns -= lCrop.Item4; } // Now we need to copy the Array "a" into a byte array. // But first! Should we make sure that it's actually a 16-bit array? int nBytes = a.Length * System.Runtime.InteropServices.Marshal.SizeOf(a.GetValue(0)); result = new byte[nBytes]; Buffer.BlockCopy(a, 0, result, 0, nBytes); Dicom.IO.Buffer.MemoryByteBuffer buffer = new Dicom.IO.Buffer.MemoryByteBuffer(result); DicomDataset dataset = new DicomDataset(); dataset = fileAnon.Dataset.Clone(); dataset.AddOrUpdate(DicomTag.Rows, (ushort)rows); dataset.AddOrUpdate(DicomTag.Columns, (ushort)columns); DicomPixelData newPixelData = DicomPixelData.Create(dataset, true); newPixelData.BitsStored = header.BitsStored; newPixelData.SamplesPerPixel = header.SamplesPerPixel; newPixelData.HighBit = header.HighBit; newPixelData.PhotometricInterpretation = header.PhotometricInterpretation; newPixelData.PixelRepresentation = header.PixelRepresentation; newPixelData.PlanarConfiguration = header.PlanarConfiguration; newPixelData.Height = (ushort)rows; newPixelData.Width = (ushort)columns; newPixelData.AddFrame(buffer); fileAnon = new DicomFile(dataset); } // Only do this if it's a 16bit file that we want a 16bit png for if (b16bit) { int nBytes = a.Length * System.Runtime.InteropServices.Marshal.SizeOf(a.GetValue(0)); result = new byte[nBytes]; // If we're using a format that's "16bit" but actually less, scale the values? if (header.BitsStored < header.BitsAllocated) { int nShift = header.BitsAllocated - header.BitsStored; int nFlag = (0x1 << header.BitsStored) - 1; for (k = 0; k < a.Length; k++) { a.SetValue((ushort)(((nFlag - ((ushort)a.GetValue(k) & nFlag)) << nShift) & 0xFFFF), k); } } Buffer.BlockCopy(a, 0, result, 0, nBytes); unsafe { fixed(byte *ptr = result) { using (Bitmap img16 = new Bitmap(columns, rows, 4 * ((2 * columns + 3) / 4), System.Drawing.Imaging.PixelFormat.Format16bppGrayScale, new IntPtr(ptr))) { SaveBmp(img16, strPath + "/Anonymised/" + strStudyID + "-16bitGreyscale.tif"); //img16.Save(strPath + "/Anonymised/" + strStudyID + "-16bitGreyscale.png"); } } } } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine("Failed to crop image"); System.Diagnostics.Debug.WriteLine(ex.ToString()); } fileAnon.Save(strPath + "/Anonymised/" + strStudyID + ".dcm"); listDCM.Add(new Tuple <string, string, string, string>(i.ToString(), strStudyID, strFile, strOriginalPatientID)); var img = new DicomImage(strPath + "/Anonymised/" + strStudyID + ".dcm"); // Convert DCM to a 32-bit per pixel (8-bit per each color RGB + 8-bit unused) PNG file try { Dicom.IO.PinnedIntArray px = img.RenderImage().Pixels; int[] pxi = px.Data; byte[] result = new byte[px.ByteSize]; Buffer.BlockCopy(pxi, 0, result, 0, result.Length); unsafe { fixed(byte *ptr = result) { using (Bitmap image = new Bitmap(img.Width, img.Height, img.Width * 4, System.Drawing.Imaging.PixelFormat.Format32bppRgb, new IntPtr(ptr))) { image.Save(strPath + "/Anonymised/" + strStudyID + ".png"); } } } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.ToString()); } worker.ReportProgress(i * 100 / files.Count); nSuccess++; //Console.WriteLine("Anonymized image " + i + " (of " + nFrames + " frame" + (nFrames == 1 ? "" : "s") + "): " + strFile); } // Create a map file using (System.IO.StreamWriter file = new System.IO.StreamWriter(new FileStream(strPath + "/Anonymised/Map.csv", FileMode.Create, FileAccess.ReadWrite), Encoding.UTF8)) { file.WriteLine("NewPatientID,NewStudyInstanceUID,OriginalFile,OriginalPatientID"); foreach (Tuple <string, string, string, string> line in listDCM) { file.WriteLine(line.Item1 + "," + line.Item2 + "," + line.Item3 + "," + line.Item4); } } string strRet = nSuccess.ToString() + " images successfully anonymised, Map.csv created.\nOutput at:\n" + strPath + "\\Anonymised"; if (lFailed.Count > 0) { strRet += "\nThese files failed to anonymise:"; foreach (string sf in lFailed) { strRet += "\n" + sf; } } return(strRet); }
public void TestStrict() { DicomFile file = CreateTestFile(); DicomAnonymizer anonymizer = new DicomAnonymizer(); anonymizer.ValidationOptions = ValidationOptions.RelaxAllChecks; try { //this ought to work. anonymizer.Anonymize(file); } catch(Exception) { Assert.Fail("Not strict - no exception expected."); } anonymizer = new DicomAnonymizer(); Assert.IsTrue(anonymizer.ValidationOptions == ValidationOptions.Default); //strict by default //should throw. anonymizer.Anonymize(CreateTestFile()); }
public void TestPrototypes() { Initialize(); StudyData studyPrototype = new StudyData(); studyPrototype.PatientId = "123"; studyPrototype.PatientsBirthDateRaw = "19760810"; studyPrototype.PatientsNameRaw = "Patient^Anonymous"; studyPrototype.PatientsSex = "M"; studyPrototype.StudyDateRaw = "20080220"; studyPrototype.StudyDescription= "Test"; studyPrototype.StudyId = "Test"; SeriesData seriesPrototype = new SeriesData(); seriesPrototype.SeriesDescription = "Series"; seriesPrototype.ProtocolName = "Protocol"; seriesPrototype.SeriesNumber = "1"; DicomAnonymizer anonymizer = new DicomAnonymizer(); anonymizer.StudyDataPrototype = studyPrototype; anonymizer.SeriesDataPrototype = seriesPrototype; anonymizer.Anonymize(_file); AfterAnonymize(studyPrototype, seriesPrototype); //validate the adjusted dates. Assert.AreEqual("20080220", _anonymizedDateData.InstanceCreationDate, "Anonymized InstanceCreationDate doesn't match StudyDate"); Assert.AreEqual("20080220", _anonymizedDateData.SeriesDate, "Anonymized SeriesDate doesn't match StudyDate"); Assert.AreEqual("20080220", _anonymizedDateData.ContentDate, "Anonymized ContentDate doesn't match StudyDate"); Assert.AreEqual("20080220100406", _anonymizedDateData.AcquisitionDatetime, "Anonymized AcquisitionDatetime doesn't match StudyDate/Time"); }
public void TestSimple() { Initialize(); DicomAnonymizer anonymizer = new DicomAnonymizer(); anonymizer.ValidationOptions = ValidationOptions.RelaxAllChecks; anonymizer.Anonymize(_file); AfterAnonymize(new StudyData(), new SeriesData()); ValidateNullDates(_anonymizedDateData); }
public void TestRemappedReferencedSopUids() { // setup some files with unique "uids" DicomFile[] originals = new DicomFile[8]; for (int n = 0; n < originals.Length; n++) { originals[n] = new DicomFile(); originals[n].DataSet[DicomTags.StudyInstanceUid].SetStringValue((1000 + (n >> 2)).ToString()); originals[n].DataSet[DicomTags.SeriesInstanceUid].SetStringValue((100 + (n >> 1)).ToString()); originals[n].DataSet[DicomTags.SopInstanceUid].SetStringValue((10 + n).ToString()); originals[n].DataSet[DicomTags.SopClassUid].SetStringValue((11111111111).ToString()); } // setup up some cyclic and self references for (int n = 0; n < originals.Length; n++) { DicomSequenceItem sq; DicomFile n0File = originals[n]; DicomFile n1File = originals[(n + 1) % originals.Length]; DicomFile n2File = originals[(n + 2) % originals.Length]; DicomFile n4File = originals[(n + 4) % originals.Length]; n0File.DataSet[DicomTags.Uid].SetStringValue(n0File.DataSet[DicomTags.SopInstanceUid].ToString()); n0File.DataSet[DicomTags.ReferencedSopInstanceUid].SetStringValue(n1File.DataSet[DicomTags.SopInstanceUid].ToString()); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.Uid].SetStringValue(DicomUid.GenerateUid().UID); sq[DicomTags.TextString].SetStringValue("UID of something not in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.Uid].SetStringValue(n0File.DataSet[DicomTags.SopInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("UID of self"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.Uid].SetStringValue(n1File.DataSet[DicomTags.SopInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("UID of next file in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.Uid].SetStringValue(n1File.DataSet[DicomTags.SeriesInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("UID of next file series in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.Uid].SetStringValue(n1File.DataSet[DicomTags.StudyInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("UID of next file study in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.Uid].SetStringValue(n2File.DataSet[DicomTags.SopInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("UID of 2nd next file in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.Uid].SetStringValue(n2File.DataSet[DicomTags.SeriesInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("UID of 2nd next file series in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.Uid].SetStringValue(n2File.DataSet[DicomTags.StudyInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("UID of 2nd next file study in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.Uid].SetStringValue(n4File.DataSet[DicomTags.SopInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("UID of 4th next file in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.Uid].SetStringValue(n4File.DataSet[DicomTags.SeriesInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("UID of 4th next file series in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.Uid].SetStringValue(n4File.DataSet[DicomTags.StudyInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("UID of 4th next file study in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.ReferencedSopInstanceUid].SetStringValue(DicomUid.GenerateUid().UID); sq[DicomTags.TextString].SetStringValue("Sop UID of something not in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.ReferencedSopInstanceUid].SetStringValue(n0File.DataSet[DicomTags.SopInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("Sop UID of self"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.ReferencedSopInstanceUid].SetStringValue(n1File.DataSet[DicomTags.SopInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("Sop UID of next file in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.ReferencedSopInstanceUid].SetStringValue(n2File.DataSet[DicomTags.SopInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("Sop UID of 2nd next file in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.ReferencedSopInstanceUid].SetStringValue(n4File.DataSet[DicomTags.SopInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("Sop UID of 4th next file in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.SeriesInstanceUid].SetStringValue(DicomUid.GenerateUid().UID); sq[DicomTags.TextString].SetStringValue("Series UID of something not in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.SeriesInstanceUid].SetStringValue(n0File.DataSet[DicomTags.SeriesInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("Series UID of self series"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.SeriesInstanceUid].SetStringValue(n1File.DataSet[DicomTags.SeriesInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("Series UID of next file series in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.SeriesInstanceUid].SetStringValue(n2File.DataSet[DicomTags.SeriesInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("Series UID of 2nd next file series in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.SeriesInstanceUid].SetStringValue(n4File.DataSet[DicomTags.SeriesInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("Series UID of 4th next file series in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.StudyInstanceUid].SetStringValue(DicomUid.GenerateUid().UID); sq[DicomTags.TextString].SetStringValue("Study UID of something not in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.StudyInstanceUid].SetStringValue(n0File.DataSet[DicomTags.StudyInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("Study UID of self study"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.StudyInstanceUid].SetStringValue(n1File.DataSet[DicomTags.StudyInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("Study UID of next file study in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.StudyInstanceUid].SetStringValue(n2File.DataSet[DicomTags.StudyInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("Study UID of 2nd next file study in data set"); n0File.DataSet[DicomTags.ContentSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.StudyInstanceUid].SetStringValue(n4File.DataSet[DicomTags.StudyInstanceUid].ToString()); sq[DicomTags.TextString].SetStringValue("Study UID of 4th next file study in data set"); n0File.DataSet[DicomTags.ReferencedStudySequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.TextString].SetStringValue("A more typical hierarchical sop reference to self"); sq[DicomTags.StudyInstanceUid].SetStringValue(n0File.DataSet[DicomTags.StudyInstanceUid].ToString()); sq[DicomTags.ReferencedSeriesSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.SeriesInstanceUid].SetStringValue(n0File.DataSet[DicomTags.SeriesInstanceUid].ToString()); sq[DicomTags.ReferencedSopSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.ReferencedSopInstanceUid].SetStringValue(n0File.DataSet[DicomTags.SopInstanceUid].ToString()); n0File.DataSet[DicomTags.ReferencedStudySequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.TextString].SetStringValue("A more typical hierarchical sop reference to next"); sq[DicomTags.StudyInstanceUid].SetStringValue(n1File.DataSet[DicomTags.StudyInstanceUid].ToString()); sq[DicomTags.ReferencedSeriesSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.SeriesInstanceUid].SetStringValue(n1File.DataSet[DicomTags.SeriesInstanceUid].ToString()); sq[DicomTags.ReferencedSopSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.ReferencedSopInstanceUid].SetStringValue(n1File.DataSet[DicomTags.SopInstanceUid].ToString()); n0File.DataSet[DicomTags.ReferencedStudySequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.TextString].SetStringValue("A more typical hierarchical sop reference to 2nd next"); sq[DicomTags.StudyInstanceUid].SetStringValue(n2File.DataSet[DicomTags.StudyInstanceUid].ToString()); sq[DicomTags.ReferencedSeriesSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.SeriesInstanceUid].SetStringValue(n2File.DataSet[DicomTags.SeriesInstanceUid].ToString()); sq[DicomTags.ReferencedSopSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.ReferencedSopInstanceUid].SetStringValue(n2File.DataSet[DicomTags.SopInstanceUid].ToString()); n0File.DataSet[DicomTags.ReferencedStudySequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.TextString].SetStringValue("A more typical hierarchical sop reference to 4th next"); sq[DicomTags.StudyInstanceUid].SetStringValue(n4File.DataSet[DicomTags.StudyInstanceUid].ToString()); sq[DicomTags.ReferencedSeriesSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.SeriesInstanceUid].SetStringValue(n4File.DataSet[DicomTags.SeriesInstanceUid].ToString()); sq[DicomTags.ReferencedSopSequence].AddSequenceItem(sq = new DicomSequenceItem()); sq[DicomTags.ReferencedSopInstanceUid].SetStringValue(n4File.DataSet[DicomTags.SopInstanceUid].ToString()); } // copy the originals and anonymize them DicomFile[] anonymized = new DicomFile[originals.Length]; DicomAnonymizer anonymizer = new DicomAnonymizer(); anonymizer.ValidationOptions = ValidationOptions.RelaxAllChecks; for (int n = 0; n < anonymized.Length; n++) { anonymized[n] = new DicomFile(string.Empty, originals[n].MetaInfo.Copy(true, true, true), originals[n].DataSet.Copy(true, true, true)); anonymizer.Anonymize(anonymized[n]); } // generate validation dump strings - unique uids are mapped to sequential numbers string originalDumpValidationString = GenerateHierarchicalUidValidationDumpString(originals); string anonymizedDumpValidationString = GenerateHierarchicalUidValidationDumpString(anonymized); // if the hierarchical structure and pattern of uids is the same, then the relationships have been preserved. Assert.AreEqual(originalDumpValidationString, anonymizedDumpValidationString, "Relationships of anonymized data set differ compared to those of original data set."); }
public DataTable ProcessPipelineData(DataTable toProcess, IDataLoadEventListener listener, GracefulCancellationToken cancellationToken) { //Things we ignore, Lookups, SupportingSql etc if (_extractCommand == null) { listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Ignoring non dataset command ")); return(toProcess); } //if it isn't a dicom dataset don't process it if (!toProcess.Columns.Contains(RelativeArchiveColumnName)) { listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Warning, "Dataset " + _extractCommand.DatasetBundle.DataSet + " did not contain field '" + RelativeArchiveColumnName + "' so we will not attempt to extract images")); return(toProcess); } if (_putter == null) { _putter = (IPutDicomFilesInExtractionDirectories) new ObjectConstructor().Construct(PutterType); } var projectNumber = _extractCommand.Configuration.Project.ProjectNumber.Value; var mappingServer = new MappingRepository(UIDMappingServer); var destinationDirectory = new DirectoryInfo(Path.Combine(_extractCommand.GetExtractionDirectory().FullName, "Images")); var releaseCol = _extractCommand.QueryBuilder.SelectColumns.Select(c => c.IColumn).Single(c => c.IsExtractionIdentifier); // See: ftp://medical.nema.org/medical/dicom/2011/11_15pu.pdf var flags = DicomAnonymizer.SecurityProfileOptions.BasicProfile | DicomAnonymizer.SecurityProfileOptions.CleanStructdCont | DicomAnonymizer.SecurityProfileOptions.CleanDesc | DicomAnonymizer.SecurityProfileOptions.RetainUIDs; if (RetainDates) { flags |= DicomAnonymizer.SecurityProfileOptions.RetainLongFullDates; } var profile = DicomAnonymizer.SecurityProfile.LoadProfile(null, flags); var anonymiser = new DicomAnonymizer(profile); using (var pool = new ZipPool()) { _sw.Start(); foreach (DataRow row in toProcess.Rows) { if (_errors > 0 && _errors > ErrorThreshold) { throw new Exception($"Number of errors reported ({_errors}) reached the threshold ({ErrorThreshold})"); } cancellationToken.ThrowIfAbortRequested(); var path = new AmbiguousFilePath(ArchiveRootIfAny, (string)row[RelativeArchiveColumnName]); DicomFile dicomFile; try { dicomFile = path.GetDataset(pool); } catch (Exception e) { listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Error, $"Failed to get image at path '{path.FullPath}'", e)); _errors++; continue; } //get the new patient ID var releaseId = row[releaseCol.GetRuntimeName()].ToString(); DicomDataset ds; try { ds = anonymiser.Anonymize(dicomFile.Dataset); } catch (Exception e) { listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Error, $"Failed to anonymize image at path '{path.FullPath}'", e)); _errors++; continue; } //now we want to explicitly use our own release Id regardless of what FoDicom said ds.AddOrUpdate(DicomTag.PatientID, releaseId); //rewrite the UIDs foreach (var kvp in UIDMapping.SupportedTags) { if (!ds.Contains(kvp.Key)) { continue; } var value = ds.GetValue <string>(kvp.Key, 0); //if it has a value for this UID if (value == null) { continue; } var releaseValue = mappingServer.GetOrAllocateMapping(value, projectNumber, kvp.Value); //change value in dataset ds.AddOrUpdate(kvp.Key, releaseValue); //and change value in DataTable if (toProcess.Columns.Contains(kvp.Key.DictionaryEntry.Keyword)) { row[kvp.Key.DictionaryEntry.Keyword] = releaseValue; } } var newPath = _putter.WriteOutDataset(destinationDirectory, releaseId, ds); row[RelativeArchiveColumnName] = newPath; _anonymisedImagesCount++; listener.OnProgress(this, new ProgressEventArgs("Writing ANO images", new ProgressMeasurement(_anonymisedImagesCount, ProgressType.Records), _sw.Elapsed)); } _sw.Stop(); } return(toProcess); }
public void TestValidateAccessionNotEqual() { Initialize(); _file.DataSet[DicomTags.AccessionNumber].SetStringValue("1234"); StudyData studyPrototype = CreateStudyPrototype(); studyPrototype.AccessionNumber = "1234"; DicomAnonymizer anonymizer = new DicomAnonymizer(); anonymizer.StudyDataPrototype = studyPrototype; anonymizer.Anonymize(_file); }
private void Anonymize(IBackgroundTaskContext context) { //TODO (Marmot) This probably should be its own WorkItem type and have it done in the background there. var study = (StudyTableItem)context.UserState; var anonymizedInstances = new AuditedInstances(); try { context.ReportProgress(new BackgroundTaskProgress(0, SR.MessageAnonymizingStudy)); var loader = study.Server.GetService <IStudyLoader>(); int numberOfSops = loader.Start(new StudyLoaderArgs(study.StudyInstanceUid, null)); if (numberOfSops <= 0) { return; } var anonymizer = new DicomAnonymizer { StudyDataPrototype = _component.AnonymizedData }; if (_component.PreserveSeriesData) { //The default anonymizer removes the series data, so we just clone the original. anonymizer.AnonymizeSeriesDataDelegate = original => original.Clone(); } // Setup the ImportFilesUtility to perform the import var configuration = DicomServer.GetConfiguration(); // setup auditing information var result = EventResult.Success; string patientsSex = null; for (int i = 0; i < numberOfSops; ++i) { using (var sop = loader.LoadNextSop()) { if (sop != null && (_component.KeepReportsAndAttachments || !IsReportOrAttachmentSopClass(sop.SopClassUid))) { //preserve the patient sex. if (patientsSex == null) { anonymizer.StudyDataPrototype.PatientsSex = patientsSex = sop.PatientsSex ?? ""; } var localSopDataSource = sop.DataSource as ILocalSopDataSource; if (localSopDataSource != null) { string filename = string.Format("{0}.dcm", i); DicomFile file = (localSopDataSource).File; // make sure we anonymize a new instance, not the same instance that the Sop cache holds!! file = new DicomFile(filename, file.MetaInfo.Copy(), file.DataSet.Copy()); anonymizer.Anonymize(file); // TODO (CR Jun 2012): Importing each file separately? Platform.GetService((IPublishFiles w) => w.PublishLocal(new List <DicomFile> { file })); string studyInstanceUid = file.DataSet[DicomTags.StudyInstanceUid].ToString(); string patientId = file.DataSet[DicomTags.PatientId].ToString(); string patientsName = file.DataSet[DicomTags.PatientsName].ToString(); anonymizedInstances.AddInstance(patientId, patientsName, studyInstanceUid); var progressPercent = (int)Math.Floor((i + 1) / (float)numberOfSops * 100); var progressMessage = String.Format(SR.MessageAnonymizingStudy, file.MediaStorageSopInstanceUid); context.ReportProgress(new BackgroundTaskProgress(progressPercent, progressMessage)); } } } } AuditHelper.LogCreateInstances(new[] { configuration.AETitle }, anonymizedInstances, EventSource.CurrentUser, result); context.Complete(); } catch (Exception e) { AuditHelper.LogCreateInstances(new[] { string.Empty }, anonymizedInstances, EventSource.CurrentUser, EventResult.MajorFailure); context.Error(e); } }
public void TestValidatePatientsBirthDateAllowEqual() { Initialize(); _file.DataSet[DicomTags.PatientsBirthDate].SetStringValue("19760810"); StudyData studyPrototype = CreateStudyPrototype(); studyPrototype.PatientsBirthDateRaw = "19760810"; DicomAnonymizer anonymizer = new DicomAnonymizer(); anonymizer.ValidationOptions = ValidationOptions.AllowEqualBirthDate; anonymizer.StudyDataPrototype = studyPrototype; anonymizer.Anonymize(_file); }