diff --git a/.github/workflows/testpack.yml b/.github/workflows/testpack.yml index 5842495..cd4b3b1 100644 --- a/.github/workflows/testpack.yml +++ b/.github/workflows/testpack.yml @@ -9,22 +9,20 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-dotnet@v2 with: - dotnet-version: '5.0.x' + dotnet-version: '6.0.x' + - uses: actions/cache@v2 + with: + path: ~/.nuget/packages + key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }} + restore-keys: | + ${{ runner.os }}-nuget- - name: Start MySQL for testing run: sudo systemctl start mysql.service - name: Test run: | dotnet test "./BadMedicine.Dicom.Tests/BadMedicine.Dicom.Tests.csproj" -nologo - - name: Package - run: | - dotnet pack ./BadMedicine.Dicom/BadMedicine.Dicom.csproj -c Release -p:IncludeSymbols=true -p:Version=$(grep AssemblyInformationalVersion SharedAssemblyInfo.cs | cut -d'"' -f2) -nologo - for platform in linux win - do - dotnet publish -c Release -r $platform-x64 -o $(pwd)/dist/$platform-x64 --self-contained true -nologo -v q - done - ( cd dist && zip -9r baddicom-win-x64-v$(grep AssemblyInformationalVersion SharedAssemblyInfo.cs | cut -d'"' -f2).zip ./win-x64 && tar czf baddicom-linux-x64-v$(grep AssemblyInformationalVersion SharedAssemblyInfo.cs | cut -d'"' -f2).tar.gz ./linux-x64 && cd - ) dotnet build -c Debug - cd ./BadDicom/bin/Debug/net5.0 + cd ./BadDicom/bin/Debug/net6.0 curl https://raw.githubusercontent.com/HicServices/DicomTypeTranslation/master/Templates/CT.it > ./CT.it mv BadDicom.template.yaml BadDicom.yaml dotnet ./BadDicom.dll ./ 50000 10 CT @@ -32,6 +30,16 @@ jobs: sed -i "s/DropTables: false/DropTables: true/g" ./BadDicom.yaml dotnet ./BadDicom.dll ./ 50000 10 CT cd - + - name: Package + run: | + mkdir -p dist + dotnet pack ./BadMedicine.Dicom/BadMedicine.Dicom.csproj -c Release -p:IncludeSymbols=true -p:Version=$(grep AssemblyInformationalVersion SharedAssemblyInfo.cs | cut -d'"' -f2) -nologo + for platform in linux win + do + dotnet publish -c Release -r $platform-x64 -o $platform-x64 --self-contained true -nologo -v q + done + zip -9r dist/baddicom-win-x64-v$(grep AssemblyInformationalVersion SharedAssemblyInfo.cs | cut -d'"' -f2).zip ./win-x64 + tar czf dist/baddicom-linux-x64-v$(grep AssemblyInformationalVersion SharedAssemblyInfo.cs | cut -d'"' -f2).tar.gz ./linux-x64 - name: Nuget push if: contains(github.ref,'refs/tags/') run: | diff --git a/.lgtm.yml b/.lgtm.yml new file mode 100644 index 0000000..5d99e70 --- /dev/null +++ b/.lgtm.yml @@ -0,0 +1,5 @@ +extraction: + csharp: + index: + dotnet: + version: 6.0.103 diff --git a/BadDicom/BadDicom.csproj b/BadDicom/BadDicom.csproj index d0a816d..c032e85 100644 --- a/BadDicom/BadDicom.csproj +++ b/BadDicom/BadDicom.csproj @@ -1,7 +1,7 @@  - net5.0 + net6.0 true @@ -42,7 +42,7 @@ - + diff --git a/BadDicom/Program.cs b/BadDicom/Program.cs index 28b493d..d743010 100644 --- a/BadDicom/Program.cs +++ b/BadDicom/Program.cs @@ -9,7 +9,7 @@ using System.Linq; using System.Threading.Tasks; using BadDicom.Configuration; -using Dicom; +using FellowOakDicom; using DicomTypeTranslation; using DicomTypeTranslation.TableCreation; using FAnsi.Discovery; @@ -92,12 +92,10 @@ private static void RunOptionsAndReturnExitCode(ProgramOptions opts) try { IPersonCollection identifiers = GetPeople(opts, out Random r); - using(var dicomGenerator = GetDataGenerator(opts, identifiers,r, out DirectoryInfo dir)) - { - Console.WriteLine($"{DateTime.Now} Starting file generation (to {dir.FullName})" ); - var targetFile = new FileInfo(Path.Combine(dir.FullName, "DicomFiles.csv")); - dicomGenerator.GenerateTestDataFile(identifiers,targetFile,opts.NumberOfStudies); - } + using var dicomGenerator = GetDataGenerator(opts, identifiers,r, out DirectoryInfo dir); + Console.WriteLine($"{DateTime.Now} Starting file generation (to {dir.FullName})" ); + var targetFile = new FileInfo(Path.Combine(dir.FullName, "DicomFiles.csv")); + dicomGenerator.GenerateTestDataFile(identifiers,targetFile,opts.NumberOfStudies); } catch (Exception e) { @@ -116,9 +114,9 @@ private static DicomDataGenerator GetDataGenerator(ProgramOptions opts, IPersonC dir = Directory.CreateDirectory(opts.OutputDirectory); //Generate the dicom files (of the modalities that the user requested) - string[] modalities = !string.IsNullOrWhiteSpace(opts.Modalities)? opts.Modalities.Split(",") :new string[0]; + string[] modalities = !string.IsNullOrWhiteSpace(opts.Modalities)? opts.Modalities.Split(",") :Array.Empty(); - return new DicomDataGenerator(r, dir, modalities) + return new(r, dir, modalities) { NoPixels = opts.NoPixels, Anonymise = opts.Anonymise, @@ -130,7 +128,7 @@ private static DicomDataGenerator GetDataGenerator(ProgramOptions opts, IPersonC private static IPersonCollection GetPeople(ProgramOptions opts, out Random r) { - r = opts.Seed == -1 ? new Random() : new Random(opts.Seed); + r = opts.Seed == -1 ? new() : new Random(opts.Seed); //create a cohort of people IPersonCollection identifiers = new PersonCollection(); @@ -148,7 +146,7 @@ private static int RunDatabaseTarget(TargetDatabase configDatabase, ProgramOptio opts.NoPixels = true; - Stopwatch swTotal = new Stopwatch(); + Stopwatch swTotal = new(); swTotal.Start(); @@ -293,7 +291,7 @@ private static int RunDatabaseTarget(TargetDatabase configDatabase, ProgramOptio for (int i = 0; i < batchSize; i++) { var batch = i; - tasks[i] = new Task(() => // lgtm[cs/local-not-disposed] + tasks[i] = new(() => // lgtm[cs/local-not-disposed] { RunBatch(identifiers,opts,r,batches[batch],uploaders[batch]); @@ -323,70 +321,67 @@ private static int RunDatabaseTarget(TargetDatabase configDatabase, ProgramOptio foreach (DiscoveredTable t in tables) Console.WriteLine($"{t.GetFullyQualifiedName()}: {t.GetRowCount():0,0}"); - Console.WriteLine("Total Running Time:" + swTotal.Elapsed); + Console.WriteLine($"Total Running Time:{swTotal.Elapsed}"); return 0; } private static void RunBatch(IPersonCollection identifiers, ProgramOptions opts, Random r,DataTable[] batches, IBulkCopy[] uploaders) { - Stopwatch swGeneration = new Stopwatch(); - Stopwatch swReading = new Stopwatch(); - Stopwatch swUploading = new Stopwatch(); + Stopwatch swGeneration = new(); + Stopwatch swReading = new(); + Stopwatch swUploading = new(); try { - using(var dicomGenerator = GetDataGenerator(opts, identifiers,r, out _)) + using var dicomGenerator = GetDataGenerator(opts, identifiers,r, out _); + for (int i = 0; i < opts.NumberOfStudies; i++) { - - for (int i = 0; i < opts.NumberOfStudies; i++) - { - swGeneration.Start(); + swGeneration.Start(); - var p = identifiers.People[r.Next(identifiers.People.Length)]; - var ds = dicomGenerator.GenerateStudyImages(p,out Study s); + var p = identifiers.People[r.Next(identifiers.People.Length)]; + var ds = dicomGenerator.GenerateStudyImages(p,out Study s); - swGeneration.Stop(); + swGeneration.Stop(); - foreach (DicomDataset dataset in ds) - { - var rows = new DataRow[batches.Length]; + foreach (DicomDataset dataset in ds) + { + var rows = new DataRow[batches.Length]; - for (int j = 0; j < batches.Length; j++) - rows[j] = batches[j].NewRow(); + for (int j = 0; j < batches.Length; j++) + rows[j] = batches[j].NewRow(); + + swReading.Start(); + foreach (DicomItem item in dataset) + { + var column = DicomTypeTranslaterReader.GetColumnNameForTag(item.Tag, false); + var value = DicomTypeTranslater.Flatten(DicomTypeTranslaterReader.GetCSharpValue(dataset, item)); - swReading.Start(); - foreach (DicomItem item in dataset) + foreach (DataRow row in rows) { - var column = DicomTypeTranslaterReader.GetColumnNameForTag(item.Tag, false); - var value = DicomTypeTranslater.Flatten(DicomTypeTranslaterReader.GetCSharpValue(dataset, item)); - - foreach (DataRow row in rows) - { - if (row.Table.Columns.Contains(column)) - row[column] = value ?? DBNull.Value; - } + if (row.Table.Columns.Contains(column)) + row[column] = value ?? DBNull.Value; } + } - for (int j = 0; j < batches.Length; j++) - batches[j].Rows.Add(rows[j]); + for (int j = 0; j < batches.Length; j++) + batches[j].Rows.Add(rows[j]); - swReading.Stop(); - } + swReading.Stop(); + } - //every 100 and last batch - if (i % 100 == 0 || i == opts.NumberOfStudies - 1) + //every 100 and last batch + if (i % 100 == 0 || i == opts.NumberOfStudies - 1) + { + swUploading.Start(); + for (var j = 0; j < uploaders.Length; j++) { - swUploading.Start(); - for (var j = 0; j < uploaders.Length; j++) - { - uploaders[j].Upload(batches[j]); - batches[j].Rows.Clear(); - } - swUploading.Stop(); - Console.WriteLine($"{DateTime.Now} Done {i} studies"); + uploaders[j].Upload(batches[j]); + batches[j].Rows.Clear(); } - + swUploading.Stop(); + Console.WriteLine($"{DateTime.Now} Done {i} studies"); } + } } finally @@ -398,9 +393,9 @@ private static void RunBatch(IPersonCollection identifiers, ProgramOptions opts, } } - Console.WriteLine("Total time Generating Dicoms:" + swGeneration.Elapsed); - Console.WriteLine("Total time Reading Dicoms:" + swReading.Elapsed); - Console.WriteLine("Total time Uploading Records:" + swUploading.Elapsed); + Console.WriteLine($"Total time Generating Dicoms:{swGeneration.Elapsed}"); + Console.WriteLine($"Total time Reading Dicoms:{swReading.Elapsed}"); + Console.WriteLine($"Total time Uploading Records:{swUploading.Elapsed}"); } } diff --git a/BadMedicine.Dicom.Tests/BadMedicine.Dicom.Tests.csproj b/BadMedicine.Dicom.Tests/BadMedicine.Dicom.Tests.csproj index 9ec99fe..cdd9070 100644 --- a/BadMedicine.Dicom.Tests/BadMedicine.Dicom.Tests.csproj +++ b/BadMedicine.Dicom.Tests/BadMedicine.Dicom.Tests.csproj @@ -1,8 +1,9 @@  - net5.0 + net6.0 false + false @@ -13,8 +14,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/BadMedicine.Dicom.Tests/DicomDataGeneratorTests.cs b/BadMedicine.Dicom.Tests/DicomDataGeneratorTests.cs index 1a430b9..426a044 100644 --- a/BadMedicine.Dicom.Tests/DicomDataGeneratorTests.cs +++ b/BadMedicine.Dicom.Tests/DicomDataGeneratorTests.cs @@ -1,4 +1,4 @@ -using Dicom; +using FellowOakDicom; using NUnit.Framework; using System; using System.Globalization; @@ -39,7 +39,7 @@ public void Test_CreatingOnDisk_OneFile() Assert.IsNotEmpty(datasetCreated.Dataset.GetSingleValue(DicomTag.AccessionNumber)); - Console.WriteLine("Created file "+ f.FullName); + Console.WriteLine($"Created file {f.FullName}"); generator.Dispose(); } @@ -53,20 +53,18 @@ public void ExampleUsage() var person = new Person(r); //create a generator - using (var generator = new DicomDataGenerator(r, null, "CT")) - { - //create a dataset in memory - DicomDataset dataset = generator.GenerateTestDataset(person, r); - - //values should match the patient details - Assert.AreEqual(person.CHI,dataset.GetValue(DicomTag.PatientID,0)); - Assert.GreaterOrEqual(dataset.GetValue(DicomTag.StudyDate,0),person.DateOfBirth); - - //should have a study description - Assert.IsNotNull(dataset.GetValue(DicomTag.StudyDescription,0)); - //should have a study description - Assert.IsNotNull(dataset.GetSingleValue(DicomTag.StudyTime).TimeOfDay); - } + using var generator = new DicomDataGenerator(r, null, "CT"); + //create a dataset in memory + DicomDataset dataset = generator.GenerateTestDataset(person, r); + + //values should match the patient details + Assert.AreEqual(person.CHI,dataset.GetValue(DicomTag.PatientID,0)); + Assert.GreaterOrEqual(dataset.GetValue(DicomTag.StudyDate,0),person.DateOfBirth); + + //should have a study description + Assert.IsNotNull(dataset.GetValue(DicomTag.StudyDescription,0)); + //should have a study description + Assert.IsNotNull(dataset.GetSingleValue(DicomTag.StudyTime).TimeOfDay); } [Test] @@ -75,7 +73,7 @@ public void Test_CreatingInMemory_ModalityCT() var r = new Random(23); var person = new Person(r); - var generator = new DicomDataGenerator(r,new DirectoryInfo(TestContext.CurrentContext.WorkDirectory),"CT"); + var generator = new DicomDataGenerator(r,new(TestContext.CurrentContext.WorkDirectory),"CT"); //generate 100 images for(int i = 0 ; i < 100 ; i++) @@ -94,7 +92,7 @@ public void Test_Anonymise() var r = new Random(23); var person = new Person(r); - var generator = new DicomDataGenerator(r,new DirectoryInfo(TestContext.CurrentContext.WorkDirectory),"CT"); + var generator = new DicomDataGenerator(r,new(TestContext.CurrentContext.WorkDirectory),"CT"); // without anonymisation (default) we get the normal patient ID var ds = generator.GenerateTestDataset(person, r); @@ -120,7 +118,7 @@ public void Test_CreatingInMemory_Modality_CTAndMR() var r = new Random(23); var person = new Person(r); - var generator = new DicomDataGenerator(r,new DirectoryInfo(TestContext.CurrentContext.WorkDirectory),"CT","MR"); + var generator = new DicomDataGenerator(r,new(TestContext.CurrentContext.WorkDirectory),"CT","MR"); //generate 100 images for(int i = 0 ; i < 100 ; i++) @@ -139,7 +137,7 @@ public void Test_CreatingInMemory_Modality_CTAndMR() public void TestFail_CreatingInMemory_Modality_Unknown() { var r = new Random(23); - Assert.Throws(()=>new DicomDataGenerator(r,new DirectoryInfo(TestContext.CurrentContext.WorkDirectory),"LOLZ")); + Assert.Throws(()=>new DicomDataGenerator(r,new(TestContext.CurrentContext.WorkDirectory),"LOLZ")); } @@ -160,7 +158,7 @@ public void Test_CsvOption() generator.NoPixels = true; generator.MaximumImages = 500; - generator.GenerateTestDataFile(people,new FileInfo(Path.Combine(outputDir.FullName,"index.csv")),500); + generator.GenerateTestDataFile(people,new(Path.Combine(outputDir.FullName,"index.csv")),500); } //3 csv files + index.csv (the default one @@ -168,19 +166,16 @@ public void Test_CsvOption() foreach (FileInfo f in outputDir.GetFiles()) { - using(var reader = new CsvReader(new StreamReader(f.FullName),CultureInfo.CurrentCulture)) - { - int rowcount = 0; - - //confirms that the CSV is intact (no dodgy commas, unquoted newlines etc) - while (reader.Read()) - rowcount++; + using var reader = new CsvReader(new StreamReader(f.FullName),CultureInfo.CurrentCulture); + int rowcount = 0; - //should be 1 row per image + 1 for header - if(f.Name == DicomDataGenerator.ImageCsvFilename) - Assert.AreEqual(501,rowcount); - } + //confirms that the CSV is intact (no dodgy commas, unquoted newlines etc) + while (reader.Read()) + rowcount++; + //should be 1 row per image + 1 for header + if(f.Name == DicomDataGenerator.ImageCsvFilename) + Assert.AreEqual(501,rowcount); } } } diff --git a/BadMedicine.Dicom.Tests/NuspecIsCorrectTests.cs b/BadMedicine.Dicom.Tests/NuspecIsCorrectTests.cs index 58e7214..2ca7148 100644 --- a/BadMedicine.Dicom.Tests/NuspecIsCorrectTests.cs +++ b/BadMedicine.Dicom.Tests/NuspecIsCorrectTests.cs @@ -40,10 +40,10 @@ public void TestDependencyCorrect(string csproj, string nuspec, string packagesM Assert.Fail("Could not find file {0}", packagesMarkdown); // - Regex rPackageRef = new Regex(@" - Regex rDependencyRef = new Regex(@""; } - private object BuildRecommendedMarkdownLine(string package, string version) + private static object BuildRecommendedMarkdownLine(string package, string version) { - return string.Format("| {0} | [GitHub]() | [{1}](https://www.nuget.org/packages/{0}/{1}) | | | |", package, version); + return + $"| {package} | [GitHub]() | [{version}](https://www.nuget.org/packages/{package}/{version}) | | | |"; } } } diff --git a/BadMedicine.Dicom.Tests/StudyTests.cs b/BadMedicine.Dicom.Tests/StudyTests.cs index 6630f06..d3b773f 100644 --- a/BadMedicine.Dicom.Tests/StudyTests.cs +++ b/BadMedicine.Dicom.Tests/StudyTests.cs @@ -1,4 +1,4 @@ -using Dicom; +using FellowOakDicom; using NUnit.Framework; using System; @@ -16,7 +16,7 @@ public void Test_CreatingNewStudy_HasSomeImages() var p = new Person(r); - Study study = new Study(generator,p,new ModalityStats("MR",2,0,50,0,r),r); + Study study = new(generator,p,new("MR",2,0,50,0,r),r); Assert.AreEqual(2,study.Series.Count); Assert.AreEqual(50,study.Series[0].Datasets.Count); diff --git a/BadMedicine.Dicom/BadMedicine.Dicom.csproj b/BadMedicine.Dicom/BadMedicine.Dicom.csproj index c8c049b..eaaf49a 100644 --- a/BadMedicine.Dicom/BadMedicine.Dicom.csproj +++ b/BadMedicine.Dicom/BadMedicine.Dicom.csproj @@ -1,7 +1,7 @@  - net5.0 + net6.0 false true true @@ -17,6 +17,7 @@ + @@ -36,7 +37,6 @@ - diff --git a/BadMedicine.Dicom/DicomDataGenerator.cs b/BadMedicine.Dicom/DicomDataGenerator.cs index 2a35be6..a79b3bc 100644 --- a/BadMedicine.Dicom/DicomDataGenerator.cs +++ b/BadMedicine.Dicom/DicomDataGenerator.cs @@ -1,5 +1,5 @@ using BadMedicine.Datasets; -using Dicom; +using FellowOakDicom; using System; using System.IO; using System.Linq; @@ -40,7 +40,7 @@ public class DicomDataGenerator : DataGenerator,IDisposable /// public FileSystemLayout Layout{ get => _pathProvider.Layout; - set => _pathProvider = new FileSystemLayoutProvider(value); + set => _pathProvider = new(value); } /// @@ -48,9 +48,9 @@ public FileSystemLayout Layout{ /// public int MaximumImages { get; set; } = int.MaxValue; - private FileSystemLayoutProvider _pathProvider = new FileSystemLayoutProvider(FileSystemLayout.StudyYearMonthDay); + private FileSystemLayoutProvider _pathProvider = new(FileSystemLayout.StudyYearMonthDay); - readonly PixelDrawer drawing = new PixelDrawer(); + readonly PixelDrawer drawing = new(); private readonly int[] _modalities; @@ -60,7 +60,7 @@ public FileSystemLayout Layout{ private string _lastStudyUID = ""; private string _lastSeriesUID = ""; private CsvWriter studyWriter, seriesWriter, imageWriter; - private DicomAnonymizer _anonymizer = new DicomAnonymizer(); + private DicomAnonymizer _anonymizer = new(); /// /// Name of the file that contains distinct Study level records for all images when is true @@ -101,7 +101,8 @@ public DicomDataGenerator(Random r, DirectoryInfo outputDir, params string[] mod foreach(var m in modalities) { if(!stats.ModalityIndexes.ContainsKey(m)) - throw new ArgumentException("Modality '" + m + "' was not supported, supported modalities are:" + string.Join(",",stats.ModalityIndexes.Select(kvp=>kvp.Key))); + throw new ArgumentException( + $"Modality '{m}' was not supported, supported modalities are:{string.Join(",", stats.ModalityIndexes.Select(kvp => kvp.Key))}"); } _modalities = modalities.Select(m=>stats.ModalityIndexes[m]).ToArray(); @@ -171,7 +172,7 @@ protected override string[] GetHeaders() public DicomDataset[] GenerateStudyImages(Person p, out Study study) { //generate a study - study = new Study(this,p,GetRandomModality(r),r); + study = new(this,p,GetRandomModality(r),r); return study.SelectMany(series=>series).ToArray(); } @@ -213,16 +214,16 @@ public DicomDataset GenerateTestDataset(Person p,Series series) //patient details ds.AddOrUpdate(DicomTag.PatientID, p.CHI); - ds.AddOrUpdate(DicomTag.PatientName, p.Forename + " " + p.Surname); + ds.AddOrUpdate(DicomTag.PatientName, $"{p.Forename} {p.Surname}"); ds.AddOrUpdate(DicomTag.PatientBirthDate, p.DateOfBirth); if (p.Address != null) { - string s = p.Address.Line1 + " " + p.Address.Line2 + " " + p.Address.Line3 + " " + p.Address.Line4 + - " " + p.Address.Postcode.Value; + string s = + $"{p.Address.Line1} {p.Address.Line2} {p.Address.Line3} {p.Address.Line4} {p.Address.Postcode.Value}"; ds.AddOrUpdate(DicomTag.PatientAddress, - s.Substring(0,Math.Min(s.Length,64)) //LO only allows 64 characters + s[..Math.Min(s.Length,64)] //LO only allows 64 characters ); } @@ -242,7 +243,7 @@ public DicomDataset GenerateTestDataset(Person p,Series series) var age = series.SeriesDate.Year - p.DateOfBirth.Year; // Go back to the year the person was born in case of a leap year if (p.DateOfBirth.Date > series.SeriesDate.AddYears(-age)) age--; - ds.AddOrUpdate(new DicomAgeString(DicomTag.PatientAge,age.ToString("000") + "Y")); + ds.AddOrUpdate(new DicomAgeString(DicomTag.PatientAge, $"{age:000}Y")); if(!NoPixels) drawing.DrawBlackBoxWithWhiteText(ds,500,500,sopInstanceUID.UID); @@ -298,7 +299,7 @@ private void InitialiseCSVOutput() return; csvInitialized = true; - _studyTags = new List() + _studyTags = new() { DicomTag.PatientID, DicomTag.StudyInstanceUID, @@ -311,7 +312,7 @@ private void InitialiseCSVOutput() DicomTag.PatientBirthDate }; - _seriesTags = new List() + _seriesTags = new() { DicomTag.StudyInstanceUID, DicomTag.SeriesInstanceUID, @@ -333,7 +334,7 @@ private void InitialiseCSVOutput() }; - _imageTags = new List() + _imageTags = new() { DicomTag.SeriesInstanceUID, DicomTag.SOPInstanceUID, @@ -369,9 +370,9 @@ private void InitialiseCSVOutput() if (OutputDir != null) { // Create/open CSV files - studyWriter = new CsvWriter(new StreamWriter(Path.Combine(OutputDir.FullName, StudyCsvFilename)),CultureInfo.CurrentCulture); - seriesWriter = new CsvWriter(new StreamWriter(Path.Combine(OutputDir.FullName, SeriesCsvFilename)),CultureInfo.CurrentCulture); - imageWriter = new CsvWriter(new StreamWriter(Path.Combine(OutputDir.FullName, ImageCsvFilename)),CultureInfo.CurrentCulture); + studyWriter = new(new StreamWriter(Path.Combine(OutputDir.FullName, StudyCsvFilename)),CultureInfo.CurrentCulture); + seriesWriter = new(new StreamWriter(Path.Combine(OutputDir.FullName, SeriesCsvFilename)),CultureInfo.CurrentCulture); + imageWriter = new(new StreamWriter(Path.Combine(OutputDir.FullName, ImageCsvFilename)),CultureInfo.CurrentCulture); // Write header WriteData("STUDY>>", studyWriter, _studyTags.Select(i => i.DictionaryEntry.Keyword)); diff --git a/BadMedicine.Dicom/DicomDataGeneratorStats.cs b/BadMedicine.Dicom/DicomDataGeneratorStats.cs index 978cc92..241690f 100644 --- a/BadMedicine.Dicom/DicomDataGeneratorStats.cs +++ b/BadMedicine.Dicom/DicomDataGeneratorStats.cs @@ -1,4 +1,4 @@ -using Dicom; +using FellowOakDicom; using System; using System.Collections.Generic; using System.Data; @@ -9,15 +9,15 @@ namespace BadMedicine.Dicom internal class DicomDataGeneratorStats { private static DicomDataGeneratorStats _instance; - private static readonly object InstanceLock = new object(); + private static readonly object InstanceLock = new(); /// /// Dictionary of Modality=>Tag=>FrequencyOfEachValue /// - public readonly Dictionary>> TagValuesByModalityAndTag = new Dictionary>>(); + public readonly Dictionary>> TagValuesByModalityAndTag = new(); public BucketList ModalityFrequency; - public Dictionary ModalityIndexes = new Dictionary(); + public Dictionary ModalityIndexes = new(); /// /// Distribution of time of day (in hours only) that tests were taken @@ -35,15 +35,15 @@ private DicomDataGeneratorStats(Random r) InitializeModalityFrequency(r); InitializeImageType(); - InitializeHourOfDay(r); + InitializeHourOfDay(); } - private void InitializeHourOfDay(Random r) + private static void InitializeHourOfDay() { //Provenance: //select DATEPART(HOUR,StudyTime),work.dbo.get_aggregate_value(count(*)) from CT_Godarts_StudyTable group by DATEPART(HOUR,StudyTime) - HourOfDay = new BucketList(); + HourOfDay = new(); HourOfDay.Add(1,1); HourOfDay.Add(4,1); @@ -76,10 +76,10 @@ public TimeSpan GetRandomTimeOfDay(Random r) { var ts = new TimeSpan(0,HourOfDay.GetRandom(r),r.Next(60),r.Next(60),0); - ts = ts.Subtract(new TimeSpan(ts.Days,0,0,0)); + ts = ts.Subtract(new(ts.Days,0,0,0)); if(ts.Days != 0) - throw new Exception("What!"); + throw new("What!"); return ts; } @@ -96,71 +96,66 @@ public string GetRandomImageType(Random r) /// public string GetRandomAccessionNumber(Random r) { - return 'T' + r.Next(4) + r.Next(2) + r.Next(5) + "H" + r.Next(9999999); + return $"T{r.Next(4)}{r.Next(2)}{r.Next(5)}H{r.Next(9999999)}"; } private void InitializeModalityFrequency(Random r) { - using (DataTable dt = new DataTable()) - { + using DataTable dt = new(); + dt.Columns.Add("Frequency", typeof(int)); + dt.Columns.Add("AverageSeriesPerStudy", typeof(double)); + dt.Columns.Add("StandardDeviationSeriesPerStudy", typeof(double)); + dt.Columns.Add("AverageImagesPerSeries", typeof(double)); + dt.Columns.Add("StandardDeviationImagesPerSeries", typeof(double)); + + DataGenerator.EmbeddedCsvToDataTable(typeof(DicomDataGenerator), "DicomDataGeneratorModalities.csv", dt); + + ModalityFrequency = new(); - dt.Columns.Add("Frequency", typeof(int)); - dt.Columns.Add("AverageSeriesPerStudy", typeof(double)); - dt.Columns.Add("StandardDeviationSeriesPerStudy", typeof(double)); - dt.Columns.Add("AverageImagesPerSeries", typeof(double)); - dt.Columns.Add("StandardDeviationImagesPerSeries", typeof(double)); - - DataGenerator.EmbeddedCsvToDataTable(typeof(DicomDataGenerator), "DicomDataGeneratorModalities.csv", dt); - - ModalityFrequency = new BucketList(); - - int idx = 0; - foreach (DataRow dr in dt.Rows) - { - string modality = (string)dr["Modality"]; - ModalityFrequency.Add((int)dr["Frequency"], - new ModalityStats( - modality, - (double)dr["AverageSeriesPerStudy"], - (double)dr["StandardDeviationSeriesPerStudy"], - (double)dr["AverageImagesPerSeries"], - (double)dr["StandardDeviationImagesPerSeries"], - r - )); - - ModalityIndexes.Add(modality, idx++); - } + int idx = 0; + foreach (DataRow dr in dt.Rows) + { + string modality = (string)dr["Modality"]; + ModalityFrequency.Add((int)dr["Frequency"], + new( + modality, + (double)dr["AverageSeriesPerStudy"], + (double)dr["StandardDeviationSeriesPerStudy"], + (double)dr["AverageImagesPerSeries"], + (double)dr["StandardDeviationImagesPerSeries"], + r + )); + + ModalityIndexes.Add(modality, idx++); } } private void InitializeTagValuesByModalityAndTag() { - using (DataTable dt = new DataTable()) - { - dt.Columns.Add("Frequency", typeof(int)); + using DataTable dt = new(); + dt.Columns.Add("Frequency", typeof(int)); - DataGenerator.EmbeddedCsvToDataTable(typeof(DicomDataGenerator), "DicomDataGeneratorTags.csv", dt); + DataGenerator.EmbeddedCsvToDataTable(typeof(DicomDataGenerator), "DicomDataGeneratorTags.csv", dt); - foreach (DataRow dr in dt.Rows) - { - var modality = (string)dr["Modality"]; - var tag = DicomDictionary.Default[(string)dr["Tag"]]; + foreach (DataRow dr in dt.Rows) + { + var modality = (string)dr["Modality"]; + var tag = DicomDictionary.Default[(string)dr["Tag"]]; - if (!TagValuesByModalityAndTag.ContainsKey(modality)) - TagValuesByModalityAndTag.Add(modality, new Dictionary>()); + if (!TagValuesByModalityAndTag.ContainsKey(modality)) + TagValuesByModalityAndTag.Add(modality, new()); - if (!TagValuesByModalityAndTag[modality].ContainsKey(tag)) - TagValuesByModalityAndTag[modality].Add(tag, new BucketList()); + if (!TagValuesByModalityAndTag[modality].ContainsKey(tag)) + TagValuesByModalityAndTag[modality].Add(tag, new()); - int frequency = (int)dr["Frequency"]; - TagValuesByModalityAndTag[modality][tag].Add(frequency, (string)dr["Value"]); - } + int frequency = (int)dr["Frequency"]; + TagValuesByModalityAndTag[modality][tag].Add(frequency, (string)dr["Value"]); } } - private void InitializeImageType() + private static void InitializeImageType() { - ImageType = new BucketList(); + ImageType = new(); ImageType.Add(96,"ORIGINAL\\PRIMARY\\AXIAL"); ImageType.Add(1,"ORIGINAL\\PRIMARY\\LOCALIZER"); @@ -177,7 +172,7 @@ public static DicomDataGeneratorStats GetInstance(Random r) { lock(InstanceLock) { - return _instance ?? (_instance = new DicomDataGeneratorStats(r)); + return _instance ??= new(r); } } diff --git a/BadMedicine.Dicom/FileSystemLayoutProvider.cs b/BadMedicine.Dicom/FileSystemLayoutProvider.cs index e44631c..1e94b4c 100644 --- a/BadMedicine.Dicom/FileSystemLayoutProvider.cs +++ b/BadMedicine.Dicom/FileSystemLayoutProvider.cs @@ -1,4 +1,4 @@ -using Dicom; +using FellowOakDicom; using System; using System.IO; @@ -15,19 +15,19 @@ public FileSystemLayoutProvider(FileSystemLayout layout) public FileInfo GetPath(DirectoryInfo root,DicomDataset ds) { - var filename = ds.GetSingleValue(DicomTag.SOPInstanceUID).UID+".dcm"; + var filename = $"{ds.GetSingleValue(DicomTag.SOPInstanceUID).UID}.dcm"; var date = ds.GetValues(DicomTag.StudyDate); switch(Layout) { case FileSystemLayout.Flat: - return new FileInfo(Path.Combine(root.FullName,filename)); + return new(Path.Combine(root.FullName,filename)); case FileSystemLayout.StudyYearMonthDay: if(date.Length > 0) { - return new FileInfo(Path.Combine( + return new(Path.Combine( root.FullName, date[0].Year.ToString(), date[0].Month.ToString(), @@ -43,7 +43,7 @@ public FileInfo GetPath(DirectoryInfo root,DicomDataset ds) if(date.Length > 0 && !string.IsNullOrWhiteSpace(acc)) { - return new FileInfo(Path.Combine( + return new(Path.Combine( root.FullName, date[0].Year.ToString(), date[0].Month.ToString(), @@ -56,7 +56,7 @@ public FileInfo GetPath(DirectoryInfo root,DicomDataset ds) case FileSystemLayout.StudyUID: - return new FileInfo(Path.Combine( + return new(Path.Combine( root.FullName, ds.GetSingleValue(DicomTag.StudyInstanceUID).UID, filename)); @@ -64,7 +64,7 @@ public FileInfo GetPath(DirectoryInfo root,DicomDataset ds) default: throw new ArgumentOutOfRangeException(); } - return new FileInfo(Path.Combine(root.FullName,filename)); + return new(Path.Combine(root.FullName,filename)); } } diff --git a/BadMedicine.Dicom/ModalityStats.cs b/BadMedicine.Dicom/ModalityStats.cs index 4fc31b5..a30a36b 100644 --- a/BadMedicine.Dicom/ModalityStats.cs +++ b/BadMedicine.Dicom/ModalityStats.cs @@ -32,12 +32,12 @@ public class ModalityStats /// /// The mean number of Images in a Series of this Modality /// - public double ImagesPerSeriesAverage { get => ImagesPerSeriesNormal.Mean; set => ImagesPerSeriesNormal=new Normal(value,ImagesPerSeriesNormal.StdDev, Rng); } + public double ImagesPerSeriesAverage { get => ImagesPerSeriesNormal.Mean; set => ImagesPerSeriesNormal=new(value,ImagesPerSeriesNormal.StdDev, Rng); } /// /// The standard deviation of the number of Images in a Series of this Modality /// - public double ImagesPerSeriesStandardDeviation{ get => ImagesPerSeriesNormal.StdDev; set => ImagesPerSeriesNormal=new Normal(ImagesPerSeriesNormal.Mean,value,Rng); } + public double ImagesPerSeriesStandardDeviation{ get => ImagesPerSeriesNormal.StdDev; set => ImagesPerSeriesNormal=new(ImagesPerSeriesNormal.Mean,value,Rng); } /// /// The Normal distribution of the number of Images per Series for this Modality @@ -62,8 +62,8 @@ public ModalityStats(string modality, double averageSeriesPerStudy,double standa { Rng = r; Modality = modality; - SeriesPerStudyNormal = new Normal(averageSeriesPerStudy, standardDeviationSeriesPerStudy, r); - ImagesPerSeriesNormal = new Normal(averageImagesPerSeries, standardDeviationImagesPerSeries, r); + SeriesPerStudyNormal = new(averageSeriesPerStudy, standardDeviationSeriesPerStudy, r); + ImagesPerSeriesNormal = new(averageImagesPerSeries, standardDeviationImagesPerSeries, r); } } } \ No newline at end of file diff --git a/BadMedicine.Dicom/PixelDrawer.cs b/BadMedicine.Dicom/PixelDrawer.cs index c09295f..aad03cb 100644 --- a/BadMedicine.Dicom/PixelDrawer.cs +++ b/BadMedicine.Dicom/PixelDrawer.cs @@ -1,10 +1,11 @@ -using Dicom; -using Dicom.Imaging; -using Dicom.IO.Buffer; +using FellowOakDicom; +using FellowOakDicom.IO.Buffer; using System; +using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; +using FellowOakDicom.Imaging; namespace BadMedicine.Dicom { @@ -13,36 +14,34 @@ namespace BadMedicine.Dicom /// internal class PixelDrawer { - readonly SolidBrush _blackBrush = new SolidBrush(Color.Black); - readonly SolidBrush _whiteBrush = new SolidBrush(Color.White); + readonly SolidBrush _blackBrush = new(Color.Black); + readonly SolidBrush _whiteBrush = new(Color.White); internal void DrawBlackBoxWithWhiteText(DicomDataset ds, int width, int height, string msg) { - using (var bitmap = new Bitmap(500, 500)) + using var bitmap = new Bitmap(500, 500); + using (var g = Graphics.FromImage(bitmap)) { - using (var g = Graphics.FromImage(bitmap)) - { - g.FillRectangle(_blackBrush, 0, 0, width, height); - using (var font = new Font(FontFamily.GenericMonospace, 12)) - g.DrawString(msg, font, _whiteBrush, 250, 100); - } + g.FillRectangle(_blackBrush, 0, 0, width, height); + using var font = new Font(FontFamily.GenericMonospace, 12); + g.DrawString(msg, font, _whiteBrush, 250, 100); + } - byte[] pixels = GetPixels(bitmap, out int rows, out int columns); - MemoryByteBuffer buffer = new MemoryByteBuffer(pixels); + byte[] pixels = GetPixels(bitmap, out int rows, out int columns); + MemoryByteBuffer buffer = new(pixels); - ds.Add(DicomTag.PhotometricInterpretation, PhotometricInterpretation.Rgb.Value); - ds.Add(DicomTag.Rows, (ushort)rows); - ds.Add(DicomTag.Columns, (ushort)columns); - ds.Add(DicomTag.BitsAllocated, (ushort)8); + ds.Add(DicomTag.PhotometricInterpretation, PhotometricInterpretation.Rgb.Value); + ds.Add(DicomTag.Rows, (ushort)rows); + ds.Add(DicomTag.Columns, (ushort)columns); + ds.Add(DicomTag.BitsAllocated, (ushort)8); - DicomPixelData pixelData = DicomPixelData.Create(ds, true); - pixelData.BitsStored = 8; - pixelData.SamplesPerPixel = 3; - pixelData.HighBit = 7; - pixelData.PixelRepresentation = 0; - pixelData.PlanarConfiguration = 0; - pixelData.AddFrame(buffer); - } + DicomPixelData pixelData = DicomPixelData.Create(ds, true); + pixelData.BitsStored = 8; + pixelData.SamplesPerPixel = 3; + pixelData.HighBit = 7; + pixelData.PixelRepresentation = 0; + pixelData.PlanarConfiguration = 0; + pixelData.AddFrame(buffer); } private static byte[] GetPixels(Bitmap image, out int rows, out int columns) @@ -53,7 +52,7 @@ private static byte[] GetPixels(Bitmap image, out int rows, out int columns) if (rows % 2 != 0 && columns % 2 != 0) --columns; - BitmapData data = image.LockBits(new Rectangle(0, 0, columns, rows), ImageLockMode.ReadOnly, image.PixelFormat); + BitmapData data = image.LockBits(new(0, 0, columns, rows), ImageLockMode.ReadOnly, image.PixelFormat); IntPtr bmpData = data.Scan0; try { @@ -61,7 +60,7 @@ private static byte[] GetPixels(Bitmap image, out int rows, out int columns) int size = rows * stride; byte[] pixelData = new byte[size]; for (int i = 0; i < rows; ++i) - Marshal.Copy(new IntPtr(bmpData.ToInt64() + i * data.Stride), pixelData, i * stride, stride); + Marshal.Copy(new(bmpData.ToInt64() + i * data.Stride), pixelData, i * stride, stride); //swap BGR to RGB SwapRedBlue(pixelData); @@ -72,13 +71,11 @@ private static byte[] GetPixels(Bitmap image, out int rows, out int columns) image.UnlockBits(data); } } - private static void SwapRedBlue(byte[] pixels) + private static void SwapRedBlue(IList pixels) { - for (int i = 0; i < pixels.Length; i += 3) + for (var i = 0; i < pixels.Count; i += 3) { - byte temp = pixels[i]; - pixels[i] = pixels[i + 2]; - pixels[i + 2] = temp; + (pixels[i], pixels[i + 2]) = (pixels[i + 2], pixels[i]); } } } diff --git a/BadMedicine.Dicom/Series.cs b/BadMedicine.Dicom/Series.cs index 812c534..23f8170 100644 --- a/BadMedicine.Dicom/Series.cs +++ b/BadMedicine.Dicom/Series.cs @@ -1,4 +1,4 @@ -using Dicom; +using FellowOakDicom; using System; using System.Collections; using System.Collections.Generic; @@ -13,7 +13,7 @@ public class Series : IEnumerable public IReadOnlyList Datasets{get; } - private readonly List _datasets = new List(); + private readonly List _datasets = new(); public Person person; public string Modality {get; } @@ -22,7 +22,7 @@ public class Series : IEnumerable public TimeSpan SeriesTime { get; internal set; } public int NumberOfSeriesRelatedInstances { get; } - internal Series(Study study, Person person, string modality, string imageType, int imageCount, Random r) + internal Series(Study study, Person person, string modality, string imageType, int imageCount) { SeriesUID = DicomUID.Generate(); diff --git a/BadMedicine.Dicom/Study.cs b/BadMedicine.Dicom/Study.cs index b2ffb0c..d8ecd9a 100644 --- a/BadMedicine.Dicom/Study.cs +++ b/BadMedicine.Dicom/Study.cs @@ -1,4 +1,4 @@ -using Dicom; +using FellowOakDicom; using System; using System.Collections; using System.Collections.Generic; @@ -49,7 +49,7 @@ public class Study : IEnumerable /// public int NumberOfStudyRelatedInstances { get; } - private readonly List _series = new List(); + private readonly List _series = new(); /// /// Constructor for a new Study on a specified Person @@ -110,7 +110,7 @@ public Study(DicomDataGenerator parent, Person person, ModalityStats modalitySta Series = new ReadOnlyCollection(_series); for(int i=0;i