-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
116 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
using Amazon.SSOOIDC.Internal; | ||
using CsvHelper; | ||
using FellowOakDicom; | ||
using NPOI.HPSF; | ||
using Org.BouncyCastle.Tls; | ||
using Rdmp.Core.Curation.Data; | ||
using Rdmp.Core.DataFlowPipeline; | ||
using Rdmp.Core.ReusableLibraryCode.Checks; | ||
using Rdmp.Core.ReusableLibraryCode.Progress; | ||
using Rdmp.Dicom.Extraction.FoDicomBased; | ||
using Rdmp.Dicom.Extraction.FoDicomBased.DirectoryDecisions; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Data; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace Rdmp.Dicom.Extraction | ||
{ | ||
public class DicomTagToCSV : IPluginDataFlowComponent<DataTable> | ||
{ | ||
[DemandsInitialization("If the path filename contains relative file uris to images then this is the root directory")] | ||
public string ArchiveRootIfAny { get; set; } | ||
|
||
[DemandsInitialization("The column name in the extracted dataset which contains the location of the dicom files", Mandatory = true)] | ||
public string RelativeArchiveColumnName { get; set; } | ||
|
||
[DemandsInitialization("How many tries to allow for fetching the file. This setting may be useful on network drives or oversubscribed resources", DefaultValue = 0)] | ||
public int FileFetchRetryLimit { get; set; } | ||
|
||
[DemandsInitialization("How long to wait between file fetch retries in milliseconds.", DefaultValue = 100)] | ||
public int FileFetchRetryTimeout { get; set; } | ||
|
||
[DemandsInitialization("The number of errors (e.g. failed to find/anonymise file) to allow before abandoning the extraction", DefaultValue = 100)] | ||
public int ErrorThreshold { get; set; } | ||
|
||
private int _errors = 0; | ||
private IPutDicomFilesInExtractionDirectories _putter; | ||
|
||
|
||
public void Abort(IDataLoadEventListener listener) | ||
{ | ||
//throw new NotImplementedException(); | ||
} | ||
|
||
public void Check(ICheckNotifier notifier) | ||
{ | ||
//throw new NotImplementedException(); | ||
} | ||
|
||
public void Dispose(IDataLoadEventListener listener, Exception pipelineFailureExceptionIfAny) | ||
{ | ||
//throw new NotImplementedException(); | ||
} | ||
|
||
public DataTable ProcessPipelineData(DataTable toProcess, IDataLoadEventListener listener, GracefulCancellationToken cancellationToken) | ||
{ | ||
|
||
var fileRows = new Dictionary<string, DataRow>(); | ||
var releaseIDs = new Dictionary<string, string>(); | ||
var dicomFiles = new List<(string, string)>(); | ||
foreach (DataRow processRow in toProcess.Rows) | ||
{ | ||
var file = (string)processRow[RelativeArchiveColumnName]; | ||
fileRows.Add(file, processRow); | ||
dicomFiles.Add((file, file)); | ||
} | ||
|
||
var dicomFilePaths = new AmbiguousFilePath(ArchiveRootIfAny, dicomFiles).GetDataset(FileFetchRetryLimit, FileFetchRetryTimeout, listener); | ||
foreach (var dcm in dicomFilePaths) | ||
{ | ||
var filepath = Path.Combine("C:\\temp\\csvtest", dcm.Item1); | ||
var sw = new StreamWriter(filepath); | ||
using var w = new CsvWriter(sw, System.Globalization.CultureInfo.InvariantCulture); | ||
w.WriteRecord( | ||
dcm.Item2.Dataset.SelectMany(t => Entry.ProcessTag(dcm.Item1, t)) | ||
); | ||
} | ||
|
||
return toProcess; | ||
} | ||
} | ||
|
||
internal class Entry | ||
{ | ||
public string Id { get; } | ||
public string Name { get; } | ||
public string Value { get; } | ||
|
||
public Entry(string id, string name, string value) | ||
{ | ||
Id = id; | ||
Name = name; | ||
Value = value; | ||
} | ||
|
||
public static IEnumerable<Entry> ProcessTag(string id, DicomItem item) | ||
{ | ||
return item switch | ||
{ | ||
DicomAttributeTag aTag => aTag.Values.Select(v => new Entry(id, aTag.Tag.DictionaryEntry.Name, v.DictionaryEntry.Name)), | ||
DicomStringElement s => StringEntries(id, s.Tag.DictionaryEntry.Name, s), | ||
DicomSequence seq => seq.Items.SelectMany(ds => ds.SelectMany(i => ProcessTag(id, i))), | ||
_ => new[] { new Entry(id, item.Tag.DictionaryEntry.Name, item.ToString()) } | ||
}; | ||
} | ||
private static IEnumerable<Entry> StringEntries(string id, string tag, DicomStringElement e) | ||
{ | ||
for (int i = 0; i < e.Count; i++) | ||
yield return new Entry(id, tag, e.Get<string>(i)); | ||
} | ||
} | ||
} |