├── .gitattributes ├── .github └── workflows │ └── main.yml ├── .gitignore ├── .gitmodules ├── CODE_OF_CONDUCT.md ├── GeoPol.xml ├── LICENSE ├── README.md ├── SECURITY.md ├── Source ├── NuGet.Config ├── build │ ├── ApplyVersionToAssemblies.ps1 │ └── config.runsettings └── projects │ ├── CreateDataset.TestHelpers │ ├── CreateDataset.TestHelpers.csproj │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── TestHelpers.cs │ ├── VolumeAssert.cs │ ├── app.config │ └── packages.config │ ├── CreateDataset.sln │ ├── CreateDataset.sln.DotSettings │ ├── ImageProcessing │ ├── AlignmentAllocator.h │ ├── GaussianKernel1D.cpp │ ├── GaussianKernel1D.h │ ├── ImageProcessing.vcxproj │ ├── SseConvolver.h │ ├── Stopwatch.cpp │ ├── Stopwatch.h │ ├── connectedComponents.cpp │ ├── connectedComponents.h │ ├── convolution.h │ ├── stdafx.cpp │ ├── stdafx.h │ └── targetver.h │ ├── ImageProcessingClr │ ├── ConnectedComponentsClr.cpp │ ├── ConnectedComponentsClr.h │ ├── ConvolutionClr.cpp │ ├── ConvolutionClr.h │ └── ImageProcessingClr.vcxproj │ ├── ImageProcessingClrTest │ ├── ConnectedComponentsTest.cs │ ├── ConvolutionTests.cs │ ├── ImageProcessingClrTest.csproj │ ├── Properties │ │ └── AssemblyInfo.cs │ └── packages.config │ ├── InnerEye.CreateDataset.Common │ ├── DatasetReader.cs │ ├── Extensions.cs │ ├── GeometricNormalizationParameters.cs │ ├── InnerEye.CreateDataset.Common.csproj │ ├── LocalFileSystem.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── StatisticsCalculator.cs │ ├── StreamsFromFileSystem.cs │ ├── VolumeIO.cs │ ├── app.config │ └── packages.config │ ├── InnerEye.CreateDataset.Contours │ ├── ContourPolygon.cs │ ├── ContourSimplifier.cs │ ├── ContourSmoothingType.cs │ ├── ContourStatistics.cs │ ├── ContoursPerSlice.cs │ ├── ExtractContours.cs │ ├── ExtractSlice.cs │ ├── FillPolygon.cs │ ├── GlobalSuppressions.cs │ ├── InnerEye.CreateDataset.Contours.csproj │ ├── InnerEye.CreateDataset.Contours_NetStandard.csproj │ ├── InnerOuterPolygon.cs │ ├── PointExtensions.cs │ ├── PolygonHelpers.cs │ ├── PolygonPoints.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── SmoothPolygon.cs │ ├── VoxelCounts.cs │ └── packages.config │ ├── InnerEye.CreateDataset.Core │ ├── Commandline │ │ ├── CommandlineAnalyzeDataset.cs │ │ ├── CommandlineCreateDataset.cs │ │ ├── CommandlineCreateDatasetRecipes.cs │ │ └── CommandlineShared.cs │ ├── ConvertDicomToNifti.cs │ ├── DatasetAnalysisFromConvertedDataset.cs │ ├── DatasetLoader.cs │ ├── DatasetWriter.cs │ ├── GeometricNormalization.cs │ ├── InnerEye.CreateDataset.Core.csproj │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── SimpleItkConverters.cs │ ├── VolumeAndStructures.cs │ ├── VolumeMetadata.cs │ ├── VolumeWriteInfo.cs │ ├── app.config │ └── packages.config │ ├── InnerEye.CreateDataset.Data │ ├── ActivePatterns.fs │ ├── AssemblyInfo.fs │ ├── Dataset.fs │ ├── DatasetFile.fs │ ├── InnerEye.CreateDataset.Data.fsproj │ ├── SubjectFiles.fs │ ├── VolumeDimensions.fs │ └── packages.config │ ├── InnerEye.CreateDataset.Extended.ruleset │ ├── InnerEye.CreateDataset.Math.Tests │ ├── CommonExtensionsTests.cs │ ├── ContourExtensionsTests.cs │ ├── ContourSimplifierTests.cs │ ├── ContourStatisticsTests.cs │ ├── EuclideanDistanceTests.cs │ ├── GeometryComparisonsTests.cs │ ├── InnerEye.CreateDataset.Math.Tests.csproj │ ├── LinearInterpolationTests.cs │ ├── Morphology │ │ ├── MorphologicalTests.cs │ │ ├── StructuringElementTests.cs │ │ └── TestData │ │ │ ├── Structures │ │ │ ├── ParentVolume.nii.gz │ │ │ ├── Structure1.nii.gz │ │ │ ├── Structure1IntersectStructure2.nii.gz │ │ │ ├── Structure1MinusStructure2.nii.gz │ │ │ ├── Structure1UnionStructure2.nii.gz │ │ │ └── Structure2.nii.gz │ │ │ └── triangle.png │ ├── Point3DTests.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── ReadOnlyVolumeTests.cs │ ├── Region3DTests.cs │ ├── ResamplingTests.cs │ ├── TestData │ │ ├── DilateTest1 │ │ │ ├── result.png │ │ │ └── triangle.png │ │ ├── ErodeTest1 │ │ │ ├── result.png │ │ │ ├── resultErode1.png │ │ │ └── triangle.png │ │ └── LoadTest1 │ │ │ └── triangle.png │ ├── TestingExtensions.cs │ ├── Transform3Tests.cs │ ├── VolumeExtensionTests.cs │ ├── VolumeTests.cs │ ├── app.config │ └── packages.config │ ├── InnerEye.CreateDataset.Math │ ├── AutoWindowLevelHelper.cs │ ├── ContourExtensions.cs │ ├── ContourGeometryOperations.cs │ ├── EuclideanDistance2D.cs │ ├── EuclideanDistance3D.cs │ ├── GenericExtensions.cs │ ├── GeometryComparisons.cs │ ├── Index3D.cs │ ├── InnerEye.CreateDataset.Math.csproj │ ├── LinearInterpolationHelpers.cs │ ├── Morphology │ │ ├── MorphologicalExtensions.cs │ │ └── StructuringElement.cs │ ├── Point3DExtensions.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── VolumeExtensions │ │ ├── GenericResampling.cs │ │ ├── RegionExtensions.cs │ │ ├── ResamplingExtensions.tt │ │ ├── ResamplingExtensions1.cs │ │ ├── TemplatedExtensions.cs │ │ ├── TemplatedExtensions.tt │ │ └── VolumeExtensions.cs │ ├── app.config │ └── packages.config │ ├── InnerEye.CreateDataset.Runner │ ├── App.config │ ├── InnerEye.CreateDataset.Runner.csproj │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── packages.config │ ├── InnerEye.CreateDataset.Volumes │ ├── Contour │ │ ├── Contour.cs │ │ ├── ContourExtensions.cs │ │ ├── ContourSimplifier.cs │ │ ├── ContourStats.cs │ │ ├── ContoursBySlice.cs │ │ ├── ExtractPolygonHelpers.cs │ │ ├── FillPolygonHelpers.cs │ │ ├── PolygonHelpers.cs │ │ └── SmoothPolygonHelpers.cs │ ├── InnerEye.CreateDataset.Volumes.csproj │ ├── Matrix2.cs │ ├── Matrix3.cs │ ├── Matrix4.cs │ ├── MinMax.cs │ ├── ModelConstants.cs │ ├── Point2D.cs │ ├── Point3D.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── ReadOnlyVolume2D.cs │ ├── ReadOnlyVolume3D.cs │ ├── Region2D.cs │ ├── Region3D.cs │ ├── SliceType.cs │ ├── SmoothingType.cs │ ├── Transform3.cs │ ├── Volume.cs │ ├── Volume2D.cs │ ├── Volume3D.cs │ ├── VolumeTransform.cs │ └── packages.config │ ├── InnerEye.CreateDataset.ruleset │ ├── MedLib.IO.Tests │ ├── AssemblyInitialize.cs │ ├── DicomDatsetExtensionsTests.cs │ ├── DicomSeriesMetadataReaderTests.cs │ ├── DicomSeriesReaderTests.cs │ ├── FastParallelTests.cs │ ├── LoadAndSaveErrorHandlingTests.cs │ ├── MaskBoundariesTest.cs │ ├── MedLib.IO.Tests.csproj │ ├── MedProcTests.cs │ ├── NiftiIOTests.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── TestData.cs │ ├── TestData │ │ ├── sample_dicom │ │ │ ├── 1_mod.dcm │ │ │ ├── 2_mod.dcm │ │ │ └── rtstruct_mod.dcm │ │ ├── vol_int16.nii.gz │ │ └── vol_uint16.nii.gz │ ├── TestDicomRTTest.cs │ ├── VolumeToDicomTests.cs │ ├── app.config │ └── packages.config │ ├── MedLib.IO │ ├── ContourRenderingInformation.cs │ ├── DicomRtHelpers.cs │ ├── Extensions │ │ ├── DicomConstants.cs │ │ ├── DicomDatasetExtensions.cs │ │ ├── DicomExtensions.cs │ │ ├── VolumeRescaleConvert.cs │ │ └── VolumeRescaleConvert.tt │ ├── FastParallel.cs │ ├── MedIO.cs │ ├── MedLib.IO.csproj │ ├── Models │ │ ├── BaseInformation.cs │ │ ├── DICOMRT │ │ │ ├── RadiotherapyContour.cs │ │ │ └── RadiotherapyStruct.cs │ │ ├── Hdf5Object.cs │ │ ├── MedicalVolume.cs │ │ ├── SliceInformation.cs │ │ └── VolumeInformation.cs │ ├── NiftiIO.cs │ ├── NiiToDicomHelpers.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── RGBValue.cs │ ├── RT │ │ ├── DicomCommonImage.cs │ │ ├── DicomEquipment.cs │ │ ├── DicomFrameOfReference.cs │ │ ├── DicomPatient.cs │ │ ├── DicomPersonNameConverter.cs │ │ ├── DicomRTContour.cs │ │ ├── DicomRTContourImageItem.cs │ │ ├── DicomRTContourItem.cs │ │ ├── DicomRTFrameOFReference.cs │ │ ├── DicomRTObservation.cs │ │ ├── DicomRTReferencedSeries.cs │ │ ├── DicomRTReferencedStudy.cs │ │ ├── DicomRTSeries.cs │ │ ├── DicomRTStructureSet.cs │ │ ├── DicomRTStructureSetROI.cs │ │ ├── DicomSOPCommon.cs │ │ ├── DicomSeries.cs │ │ └── DicomStudy.cs │ ├── Readers │ │ ├── DicomFileAndPath.cs │ │ ├── DicomFolderContents.cs │ │ ├── DicomIdentifiers.cs │ │ ├── DicomSeriesContent.cs │ │ ├── DicomSeriesImageReader.cs │ │ ├── DicomSeriesInformationValidator.cs │ │ ├── DicomSeriesReader.cs │ │ ├── IVolumeGeometricAcceptanceTest.cs │ │ ├── NonStrictGeometricAcceptanceTest.cs │ │ ├── RTStructReader.cs │ │ └── StrictGeometricAcceptanceTest.cs │ ├── StreamingExtensions.cs │ ├── Writers │ │ ├── RTStructCreator.cs │ │ └── RTStructWriter.cs │ ├── app.config │ └── packages.config │ └── build.yml ├── THIRDPARTYNOTICES.md ├── commandline_args.md └── global.json /.gitattributes: -------------------------------------------------------------------------------- 1 | *.gz filter=lfs diff=lfs merge=lfs -text 2 | *.zip filter=lfs diff=lfs merge=lfs -text 3 | *.msdf5 filter=lfs diff=lfs merge=lfs -text 4 | *.png filter=lfs diff=lfs merge=lfs -text 5 | *.dcm filter=lfs diff=lfs merge=lfs -text 6 | *.dll filter=lfs diff=lfs merge=lfs -text 7 | *.rar filter=lfs diff=lfs merge=lfs -text 8 | *.tgz filter=lfs diff=lfs merge=lfs -text 9 | *.lib filter=lfs diff=lfs merge=lfs -text 10 | *.nii filter=lfs diff=lfs merge=lfs -text 11 | *.lz4 filter=lfs diff=lfs merge=lfs -text 12 | *.nii.gz filter=lfs diff=lfs merge=lfs -text 13 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Add Issues to InnerEye-OSS project 2 | on: 3 | issues: 4 | types: 5 | - opened 6 | jobs: 7 | track_issue: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Get project data 11 | env: 12 | GITHUB_TOKEN: ${{ secrets.INNEREYE_OSS_PROJECT_ACCESS_TOKEN }} 13 | ORGANIZATION: Microsoft 14 | PROJECT_NUMBER: 320 15 | run: | 16 | gh api graphql -f query=' 17 | query($org: String!, $number: Int!) { 18 | organization(login: $org){ 19 | projectNext(number: $number) { 20 | id 21 | fields(first:20) { 22 | nodes { 23 | id 24 | name 25 | settings 26 | } 27 | } 28 | } 29 | } 30 | }' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json 31 | 32 | echo 'PROJECT_ID='$(jq '.data.organization.projectNext.id' project_data.json) >> $GITHUB_ENV 33 | 34 | - name: Add issue to project 35 | env: 36 | GITHUB_TOKEN: ${{ secrets.INNEREYE_OSS_PROJECT_ACCESS_TOKEN }} 37 | ISSUE_ID: ${{ github.event.issue.node_id }} 38 | run: | 39 | item_id="$( gh api graphql -f query=' 40 | mutation($project:ID!, $issue:ID!) { 41 | addProjectNextItem(input: {projectId: $project, contentId: $issue}) { 42 | projectNextItem { 43 | id 44 | } 45 | } 46 | }' -f project=$PROJECT_ID -f issue=$ISSUE_ID --jq '.data.addProjectNextItem.projectNextItem.id')" 47 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/InnerEye-CreateDataset/8561e8cedc5f1aeb4af43c86a7796a1fe12c1892/.gitmodules -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /GeoPol.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | ]> 7 | 8 | 9 | 10 | &GitReposFolder;\github\&GitRepoName; 11 | &GitRepoName; 12 | 13 | 14 | . 15 | 16 | 17 | .gitignore 18 | GeoPol.xml 19 | THIRDPARTYNOTICES.md 20 | *.nii.gz 21 | *.dcm 22 | 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | -------------------------------------------------------------------------------- /Source/NuGet.Config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Source/build/config.runsettings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 8 | 10 | x64 11 | 12 | 13 | Framework45 14 | 15 | 16 | 0 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Source/projects/CreateDataset.TestHelpers/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | using System.Reflection; 7 | using System.Runtime.CompilerServices; 8 | using System.Runtime.InteropServices; 9 | 10 | // General Information about an assembly is controlled through the following 11 | // set of attributes. Change these attribute values to modify the information 12 | // associated with an assembly. 13 | [assembly: AssemblyTitle("CreateDataset.TestHelpers")] 14 | [assembly: AssemblyDescription("")] 15 | [assembly: AssemblyConfiguration("")] 16 | [assembly: AssemblyCompany("")] 17 | [assembly: AssemblyProduct("CreateDataset.TestHelpers")] 18 | [assembly: AssemblyCopyright("Copyright © 2017")] 19 | [assembly: AssemblyTrademark("")] 20 | [assembly: AssemblyCulture("")] 21 | 22 | // Setting ComVisible to false makes the types in this assembly not visible 23 | // to COM components. If you need to access a type in this assembly from 24 | // COM, set the ComVisible attribute to true on that type. 25 | [assembly: ComVisible(false)] 26 | 27 | // The following GUID is for the ID of the typelib if this project is exposed to COM 28 | [assembly: Guid("9255769c-41f4-47f9-a8e2-97b18d0971f5")] 29 | 30 | // Version information for an assembly consists of the following four values: 31 | // 32 | // Major Version 33 | // Minor Version 34 | // Build Number 35 | // Revision 36 | // 37 | // You can specify all the values or you can default the Build and Revision Numbers 38 | // by using the '*' as shown below: 39 | // [assembly: AssemblyVersion("1.0.*")] 40 | [assembly: AssemblyVersion("1.0.0.0")] 41 | [assembly: AssemblyFileVersion("1.0.0.0")] 42 | -------------------------------------------------------------------------------- /Source/projects/CreateDataset.TestHelpers/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Source/projects/CreateDataset.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | Named 3 | False 4 | True 5 | IO 6 | XY -------------------------------------------------------------------------------- /Source/projects/ImageProcessing/AlignmentAllocator.h: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------------------------------------------------------ 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | * ------------------------------------------------------------------------------------------ 5 | */ 6 | 7 | #pragma once 8 | 9 | namespace createdataset 10 | { 11 | template 12 | class AlignmentAllocator { 13 | public: 14 | typedef T value_type; 15 | typedef std::size_t size_type; 16 | typedef std::ptrdiff_t difference_type; 17 | 18 | typedef T * pointer; 19 | typedef const T * const_pointer; 20 | 21 | typedef T & reference; 22 | typedef const T & const_reference; 23 | 24 | public: 25 | inline AlignmentAllocator() throw () { } 26 | 27 | template 28 | inline AlignmentAllocator(const AlignmentAllocator &) throw () { } 29 | 30 | inline ~AlignmentAllocator() throw () { } 31 | 32 | inline pointer adress(reference r) { 33 | return &r; 34 | } 35 | 36 | inline const_pointer adress(const_reference r) const { 37 | return &r; 38 | } 39 | 40 | inline pointer allocate(size_type n) { 41 | return (pointer)_aligned_malloc(n*sizeof(value_type), N); 42 | } 43 | 44 | inline void deallocate(pointer p, size_type) { 45 | _aligned_free(p); 46 | } 47 | 48 | inline void construct(pointer p, const value_type & wert) { 49 | new (p) value_type(wert); 50 | } 51 | 52 | inline void destroy(pointer p) { 53 | p->~value_type(); 54 | } 55 | 56 | inline size_type max_size() const throw () { 57 | return size_type(-1) / sizeof(value_type); 58 | } 59 | 60 | template 61 | struct rebind { 62 | typedef AlignmentAllocator other; 63 | }; 64 | 65 | bool operator!=(const AlignmentAllocator& other) const { 66 | return !(*this == other); 67 | } 68 | 69 | // Returns true if and only if storage allocated from *this 70 | // can be deallocated from other, and vice versa. 71 | // Always returns true for stateless allocators. 72 | bool operator==(const AlignmentAllocator& other) const { 73 | return true; 74 | } 75 | }; 76 | } -------------------------------------------------------------------------------- /Source/projects/ImageProcessing/GaussianKernel1D.cpp: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------------------------------------------------------ 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | * ------------------------------------------------------------------------------------------ 5 | */ 6 | 7 | #include "StdAfx.h" 8 | #include "GaussianKernel1D.h" 9 | 10 | #include 11 | #include 12 | 13 | namespace createdataset 14 | { 15 | GaussianKernel1D::GaussianKernel1D(float sigma, float tol) 16 | { 17 | if (sigma < 0.0f) 18 | sigma = -sigma; 19 | 20 | if (tol < 0.0f) 21 | tol = -tol; 22 | 23 | // Because the chances are high that someone has #define'd PI. 24 | const float PACKAGE_PI = 3.141592f; 25 | 26 | _radius = static_cast(floor(sigma * sqrt(2 * log(1 / tol)))); 27 | _data.resize(2 * _radius + 1); 28 | 29 | float sum = 0.0; 30 | for (int x = -_radius; x <= _radius; x++) 31 | { 32 | _data[_radius + x] 33 | = static_cast((1 / (sigma*sqrt(2 * PACKAGE_PI))) * exp(-0.5 * pow(x / sigma, 2))); 34 | 35 | sum += _data[_radius + x]; 36 | } 37 | } 38 | 39 | int GaussianKernel1D::getRadius() const 40 | { 41 | return _radius; 42 | } 43 | 44 | const float* GaussianKernel1D::getData() const 45 | { 46 | return &_data[0]; 47 | } 48 | } -------------------------------------------------------------------------------- /Source/projects/ImageProcessing/GaussianKernel1D.h: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------------------------------------------------------ 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | * ------------------------------------------------------------------------------------------ 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | namespace createdataset 12 | { 13 | class GaussianKernel1D 14 | { 15 | public: 16 | // Creates a Gaussian kernel with the specified sigma, truncates coefficients less than faction tol of max. 17 | GaussianKernel1D(float sigma, float tol = 0.001); 18 | 19 | // The radius of the kernel (array length size is 2*radius + 1) 20 | int getRadius() const; 21 | 22 | // A pointer to the beginning of the array of kernel coefficients. 23 | const float* getData() const; 24 | 25 | // Implementation 26 | private: 27 | int _radius; 28 | std::vector _data; 29 | }; 30 | } -------------------------------------------------------------------------------- /Source/projects/ImageProcessing/Stopwatch.cpp: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------------------------------------------------------ 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | * ------------------------------------------------------------------------------------------ 5 | */ 6 | 7 | #include "stdafx.h" 8 | 9 | #include "Stopwatch.h" 10 | 11 | namespace createdataset 12 | { 13 | Stopwatch::Stopwatch() { 14 | if (!::QueryPerformanceFrequency(&frequency_)) throw "Error with QueryPerformanceFrequency"; 15 | } 16 | 17 | void Stopwatch::Start() { 18 | ::QueryPerformanceCounter(&startTime_); 19 | } 20 | 21 | void Stopwatch::Stop() { 22 | ::QueryPerformanceCounter(&stopTime_); 23 | } 24 | 25 | float Stopwatch::MilliSeconds() const { 26 | return (float)(stopTime_.QuadPart - startTime_.QuadPart) / (float)frequency_.QuadPart * 1000; 27 | } 28 | } -------------------------------------------------------------------------------- /Source/projects/ImageProcessing/Stopwatch.h: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------------------------------------------------------ 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | * ------------------------------------------------------------------------------------------ 5 | */ 6 | 7 | #pragma once 8 | 9 | #include // TODO: Preferable to remove this from header 10 | 11 | namespace createdataset 12 | { 13 | class Stopwatch { 14 | LARGE_INTEGER frequency_; 15 | LARGE_INTEGER startTime_; 16 | LARGE_INTEGER stopTime_; 17 | 18 | public: 19 | Stopwatch(); 20 | 21 | void Start(); 22 | void Stop(); 23 | 24 | float MilliSeconds() const; 25 | }; 26 | } -------------------------------------------------------------------------------- /Source/projects/ImageProcessing/connectedComponents.cpp: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------------------------------------------------------ 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | * ------------------------------------------------------------------------------------------ 5 | */ 6 | 7 | #include "stdafx.h" 8 | #include "connectedComponents.h" 9 | 10 | namespace createdataset 11 | { 12 | void test_Set() 13 | { 14 | Set s1, s2, s3, s4; 15 | 16 | // Sets are initially unique 17 | if (s1.find() == s2.find()) 18 | throw std::exception("Internal error in Set."); 19 | 20 | // The union of two sets contains all members of both sets 21 | Set::unite(&s1, &s2); 22 | if (s1.find() != s2.find()) 23 | throw std::exception("Internal error in Set."); 24 | 25 | // Union is transitive 26 | 27 | Set::unite(&s2, &s3); 28 | if (s2.find() != s1.find() || s3.find() != s2.find()) 29 | throw std::exception("Internal error in Set."); 30 | 31 | Set::unite(&s4, &s3); 32 | if (s4.find() != s3.find() || s3.find() != s1.find() || s3.find() != s2.find()) 33 | throw std::exception("Internal error in Set."); 34 | } 35 | 36 | 37 | template<> 38 | void printImage(int width, int height, void* buffer, int stride) 39 | { 40 | for (int v = 0; v < height; v++) 41 | { 42 | unsigned char* p = (unsigned char*)(buffer)+v*stride; 43 | for (int u = 0; u < width; u++) 44 | { 45 | std::cout << (int)p[0]; 46 | if (u != width - 1) 47 | std::cout << "\t"; 48 | p++; 49 | } 50 | std::cout << std::endl; 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /Source/projects/ImageProcessing/stdafx.cpp: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------------------------------------------------------ 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | * ------------------------------------------------------------------------------------------ 5 | */ 6 | 7 | // stdafx.cpp : source file that includes just the standard includes 8 | // ImageProcessing.pch will be the pre-compiled header 9 | // stdafx.obj will contain the pre-compiled type information 10 | 11 | #include "stdafx.h" 12 | 13 | // TODO: reference any additional headers you need in STDAFX.H 14 | // and not in this file 15 | -------------------------------------------------------------------------------- /Source/projects/ImageProcessing/stdafx.h: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------------------------------------------------------ 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | * ------------------------------------------------------------------------------------------ 5 | */ 6 | 7 | // stdafx.h : include file for standard system include files, 8 | // or project specific include files that are used frequently, but 9 | // are changed infrequently 10 | // 11 | 12 | #pragma once 13 | 14 | #include "targetver.h" 15 | 16 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 17 | 18 | 19 | 20 | // TODO: reference additional headers your program requires here 21 | -------------------------------------------------------------------------------- /Source/projects/ImageProcessing/targetver.h: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------------------------------------------------------ 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | * ------------------------------------------------------------------------------------------ 5 | */ 6 | 7 | #pragma once 8 | 9 | // Including SDKDDKVer.h defines the highest available Windows platform. 10 | 11 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 12 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 13 | 14 | #include 15 | -------------------------------------------------------------------------------- /Source/projects/ImageProcessingClr/ConnectedComponentsClr.cpp: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------------------------------------------------------ 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | * ------------------------------------------------------------------------------------------ 5 | */ 6 | 7 | #include "ConnectedComponentsClr.h" 8 | 9 | #include 10 | 11 | #pragma managed(push, off) 12 | #include "connectedComponents.h" 13 | #pragma managed(pop) 14 | 15 | namespace InnerEye { namespace CreateDataset { namespace ImageProcessing { 16 | int ConnectedComponents::Find3d( 17 | array^ image, 18 | int width, int height, int depth, 19 | unsigned char backgroundColour, 20 | array^ output) 21 | { 22 | try 23 | { 24 | pin_ptr inputBuffer = &image[0]; 25 | pin_ptr outputBuffer = &output[0]; 26 | 27 | int inputLeap = width*height*sizeof(unsigned char), inputStride = width*sizeof(unsigned char); 28 | int outputLeap = width*height*sizeof(unsigned short), outputStride = width*sizeof(unsigned short); 29 | 30 | auto result = createdataset::findConnectedComponents3d( 31 | width, height, depth, 32 | inputBuffer, inputLeap, inputStride, backgroundColour, 33 | outputBuffer, outputLeap, outputStride, 34 | 0); 35 | 36 | return (int)(result.size()); 37 | } 38 | catch (std::exception& oops) 39 | { 40 | throw gcnew System::Exception(gcnew System::String(oops.what())); 41 | } 42 | } 43 | 44 | array^ ConnectedComponents::Find3dWithStatistics( 45 | array^ image, 46 | int width, int height, int depth, 47 | unsigned char backgroundColour, 48 | array^ output) 49 | { 50 | try 51 | { 52 | pin_ptr inputBuffer = &image[0]; 53 | pin_ptr outputBuffer = &output[0]; 54 | 55 | int inputLeap = width*height*sizeof(unsigned char), inputStride = width*sizeof(unsigned char); 56 | int outputLeap = width*height*sizeof(unsigned short), outputStride = width*sizeof(unsigned short); 57 | 58 | auto result_ = createdataset::findConnectedComponents3d( 59 | width, height, depth, 60 | inputBuffer, inputLeap, inputStride, backgroundColour, 61 | outputBuffer, outputLeap, outputStride, 62 | 0); 63 | 64 | auto result = gcnew array(result_.size()); 65 | pin_ptr p = &result[0]; 66 | ::memcpy(p, &result_[0], result_.size()*sizeof(createdataset::ComponentStatistics)); 67 | 68 | return result; 69 | } 70 | catch (std::exception& oops) 71 | { 72 | throw gcnew System::Exception(gcnew System::String(oops.what())); 73 | } 74 | } 75 | } } } -------------------------------------------------------------------------------- /Source/projects/ImageProcessingClr/ConnectedComponentsClr.h: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------------------------------------------------------ 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | * ------------------------------------------------------------------------------------------ 5 | */ 6 | 7 | #pragma once 8 | 9 | namespace InnerEye { namespace CreateDataset { namespace ImageProcessing 10 | { 11 | public value struct ComponentStatistics 12 | { 13 | public: 14 | unsigned long PixelCount; 15 | unsigned char InputLabel; 16 | }; 17 | 18 | public ref class ConnectedComponents 19 | { 20 | public: 21 | // Find connected components in 3D volume using one pass unite-find approach and 22 | // label associated voxels in output volume. Voxels with the specified background colour 23 | // are all assigned the background label. 24 | // Returns the number of connected components (6-connected (aka face) components ie: diagnoal points are considered separate components) found, including the background class. 25 | static int Find3d(array^ image, int width, int height, int depth, unsigned char backgroundColour, array^ result); 26 | 27 | static array^ Find3dWithStatistics(array^ image, int width, int height, int depth, unsigned char backgroundColour, array^ result); 28 | // NB could easily extend to support different pixel types, image padding, etc. 29 | }; 30 | } } } -------------------------------------------------------------------------------- /Source/projects/ImageProcessingClr/ConvolutionClr.cpp: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------------------------------------------------------ 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | * ------------------------------------------------------------------------------------------ 5 | */ 6 | 7 | #include "ConvolutionClr.h" 8 | 9 | #pragma managed(push, off) 10 | #include "convolution.h" 11 | #include "GaussianKernel1D.h" 12 | #pragma managed(pop) 13 | 14 | namespace InnerEye { 15 | namespace CreateDataset { 16 | namespace ImageProcessing { 17 | 18 | void Convolution::Convolve(array^ data, int width, int height, int depth, array^ directions, array^ sigmas) 19 | { 20 | if (directions->Length != sigmas->Length) 21 | throw gcnew System::Exception("Arrays of directions and sigmas should be of the same length."); 22 | 23 | int leap = width*height*sizeof(float), stride = width*sizeof(float), hop=sizeof(float); 24 | 25 | pin_ptr buffer = &data[0]; 26 | 27 | try 28 | { 29 | for (int d = 0; d < directions->Length; d++) 30 | { 31 | createdataset::GaussianKernel1D kernel(sigmas[d]); 32 | Direction direction = directions[d]; 33 | createdataset::convolve1d(width, height, depth, (unsigned char*)buffer, leap, stride, hop, (int)direction, kernel.getData(), kernel.getRadius()); 34 | } 35 | } 36 | catch (std::exception& oops) 37 | { 38 | throw gcnew System::Exception(gcnew System::String(oops.what())); 39 | } 40 | } 41 | 42 | void Convolution::Convolve(array^ data, int width, int height, int depth, array^ directions, array^ sigmas) 43 | { 44 | if (directions->Length != sigmas->Length) 45 | throw gcnew System::Exception("Arrays of directions and sigmas should be of the same length."); 46 | 47 | int leap = width*height*sizeof(unsigned char), stride = width*sizeof(unsigned char), hop = sizeof(unsigned char); 48 | 49 | pin_ptr buffer = &data[0]; 50 | 51 | try 52 | { 53 | for (int d = 0; d < directions->Length; d++) 54 | { 55 | createdataset::GaussianKernel1D kernel(sigmas[d]); 56 | Direction direction = directions[d]; 57 | createdataset::convolve1d(width, height, depth, (unsigned char*)buffer, leap, stride, hop, (int)direction, kernel.getData(), kernel.getRadius()); 58 | } 59 | } 60 | catch (std::exception& oops) 61 | { 62 | throw gcnew System::Exception(gcnew System::String(oops.what())); 63 | } 64 | } 65 | 66 | void Convolution::Convolve(array^ data, int width, int height, int depth, array^ directions, array^ sigmas) 67 | { 68 | if (directions->Length != sigmas->Length) 69 | throw gcnew System::Exception("Arrays of directions and sigmas should be of the same length."); 70 | 71 | int leap = width*height*sizeof(short), stride = width*sizeof(short), hop = sizeof(short); 72 | 73 | pin_ptr buffer = &data[0]; 74 | 75 | try 76 | { 77 | for (int d = 0; d < directions->Length; d++) 78 | { 79 | createdataset::GaussianKernel1D kernel(sigmas[d]); 80 | Direction direction = directions[d]; 81 | createdataset::convolve1d(width, height, depth, (unsigned char*)buffer, leap, stride, hop, (int)direction, kernel.getData(), kernel.getRadius()); 82 | } 83 | } 84 | catch (std::exception& oops) 85 | { 86 | throw gcnew System::Exception(gcnew System::String(oops.what())); 87 | } 88 | } 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /Source/projects/ImageProcessingClr/ConvolutionClr.h: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------------------------------------------------------ 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | * ------------------------------------------------------------------------------------------ 5 | */ 6 | 7 | #pragma once 8 | 9 | namespace InnerEye { namespace CreateDataset { namespace ImageProcessing { 10 | 11 | public enum class Direction 12 | { 13 | DirectionX=0, DirectionY=1, DirectionZ=2 14 | }; 15 | 16 | public ref class Convolution 17 | { 18 | public: 19 | // TODO: Various improvements are possible: 20 | // * Take a ROI as argument to avoid the need to extract subregion from managed array. 21 | // * Support out-of-place convolution too? 22 | // * Support arbtirary kernel in array. 23 | 24 | static void Convolve(array^ data, int width, int height, int depth, array^ directions, array^ sigmas); 25 | 26 | static void Convolve(array^ data, int width, int height, int depth, array^ directions, array^ sigmas); 27 | 28 | static void Convolve(array^ data, int width, int height, int depth, array^ directions, array^ sigmas); 29 | }; 30 | } } } -------------------------------------------------------------------------------- /Source/projects/ImageProcessingClrTest/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | using System.Reflection; 7 | using System.Runtime.CompilerServices; 8 | using System.Runtime.InteropServices; 9 | 10 | // General Information about an assembly is controlled through the following 11 | // set of attributes. Change these attribute values to modify the information 12 | // associated with an assembly. 13 | [assembly: AssemblyTitle("ImageProcessingClrTest")] 14 | [assembly: AssemblyDescription("")] 15 | [assembly: AssemblyConfiguration("")] 16 | [assembly: AssemblyCompany("")] 17 | [assembly: AssemblyProduct("ImageProcessingClrTest")] 18 | [assembly: AssemblyCopyright("Copyright © 2016")] 19 | [assembly: AssemblyTrademark("")] 20 | [assembly: AssemblyCulture("")] 21 | 22 | // Setting ComVisible to false makes the types in this assembly not visible 23 | // to COM components. If you need to access a type in this assembly from 24 | // COM, set the ComVisible attribute to true on that type. 25 | [assembly: ComVisible(false)] 26 | 27 | // The following GUID is for the ID of the typelib if this project is exposed to COM 28 | [assembly: Guid("f7604598-10f9-41cc-bbf4-805c67f48263")] 29 | 30 | // Version information for an assembly consists of the following four values: 31 | // 32 | // Major Version 33 | // Minor Version 34 | // Build Number 35 | // Revision 36 | // 37 | // You can specify all the values or you can default the Build and Revision Numbers 38 | // by using the '*' as shown below: 39 | // [assembly: AssemblyVersion("1.0.*")] 40 | [assembly: AssemblyVersion("1.0.0.0")] 41 | [assembly: AssemblyFileVersion("1.0.0.0")] 42 | -------------------------------------------------------------------------------- /Source/projects/ImageProcessingClrTest/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Common/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | using System.Reflection; 7 | using System.Runtime.InteropServices; 8 | 9 | // General Information about an assembly is controlled through the following 10 | // set of attributes. Change these attribute values to modify the information 11 | // associated with an assembly. 12 | [assembly: AssemblyTitle("InnerEye.CreateDataset.Common")] 13 | [assembly: AssemblyDescription("")] 14 | [assembly: AssemblyConfiguration("")] 15 | [assembly: AssemblyCompany("")] 16 | [assembly: AssemblyProduct("InnerEye.CreateDataset.Common")] 17 | [assembly: AssemblyCopyright("Copyright © 2016")] 18 | [assembly: AssemblyTrademark("")] 19 | [assembly: AssemblyCulture("")] 20 | 21 | // Setting ComVisible to false makes the types in this assembly not visible 22 | // to COM components. If you need to access a type in this assembly from 23 | // COM, set the ComVisible attribute to true on that type. 24 | [assembly: ComVisible(false)] 25 | 26 | // The following GUID is for the ID of the typelib if this project is exposed to COM 27 | [assembly: Guid("8db64d15-3241-44d8-805d-cdfd7a5623a8")] 28 | 29 | // Version information for an assembly consists of the following four values: 30 | // 31 | // Major Version 32 | // Minor Version 33 | // Build Number 34 | // Revision 35 | // 36 | // You can specify all the values or you can default the Build and Revision Numbers 37 | // by using the '*' as shown below: 38 | // [assembly: AssemblyVersion("1.0.*")] 39 | [assembly: AssemblyVersion("1.0.0.0")] 40 | [assembly: AssemblyFileVersion("1.0.0.0")] 41 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Common/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Common/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Contours/ContourSmoothingType.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Contours 7 | { 8 | /// 9 | /// Describes the different ways how a contour can be smoothed. 10 | /// 11 | public enum ContourSmoothingType 12 | { 13 | /// 14 | /// The contour is not smoothed, and traces the outside of the pixels. 15 | /// Pixels are drawn with their centers at integer coordinates, the contour will 16 | /// hence run as lines in between the integer coordinates. 17 | /// 18 | None, 19 | 20 | /// 21 | /// The contour is first tracing pixel outsides, and then corners are smoothed. 22 | /// 23 | Small 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Contours/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | // This file is used by Code Analysis to maintain SuppressMessage 7 | // attributes that are applied to this project. 8 | // Project-level suppressions either have no target or are given 9 | // a specific target and scoped to a namespace, type, member, etc. 10 | 11 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:Field names must not use Hungarian notation", Justification = "Plenty of legacy code uses constructs like zDimX, which CA mistakes for Hungarian notation.")] 12 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Contours/InnerEye.CreateDataset.Contours_NetStandard.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net462 5 | x64 6 | $(ProjectDir)..\InnerEye.CreateDataset.Extended.ruleset 7 | true 8 | 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | all 20 | runtime; build; native; contentfiles; analyzers 21 | 22 | 23 | 24 | all 25 | runtime; build; native; contentfiles; analyzers 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Contours/InnerOuterPolygon.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Contours 7 | { 8 | using System; 9 | using System.Collections.Generic; 10 | 11 | /// 12 | /// Describes a region of a binary mask via the points that make up the outer rim of a contiguous region, 13 | /// and possibly the inner rim if the region has holes (doughnut shape). 14 | /// 15 | public class InnerOuterPolygon 16 | { 17 | /// 18 | /// Creates a new instance of the class. 19 | /// 20 | /// The points that make up the outer rim of the region, traversed clockwise. 21 | public InnerOuterPolygon(PolygonPoints outer) 22 | { 23 | Outer = outer ?? throw new ArgumentNullException(nameof(outer)); 24 | Inner = new List(); 25 | TotalPixels = outer.VoxelCounts.Total; 26 | } 27 | 28 | /// 29 | /// Gets the points that describe the outer rim of region, traversed in clockwise order, with no gaps 30 | /// (each point must be in the 8-neighborhood of its successor), wrapping around at the end. 31 | /// 32 | public PolygonPoints Outer { get; } 33 | 34 | /// 35 | /// Gets the points that describe the inner rim of region, traversed in counter-clockwise order, with no gaps 36 | /// (each point must be in the 8-neighborhood of its successor), wrapping around at the end. There can 37 | /// be multiple such inner rims if a contour has multiple "holes". 38 | /// 39 | public List Inner { get; } 40 | 41 | /// 42 | /// Gets the number of pixels that make up the region described by the present object. The number of pixels 43 | /// are the points that are on the outer rim, the points on the inner rim, and all points in between. 44 | /// 45 | public uint TotalPixels { get; private set; } 46 | 47 | /// 48 | /// Gets if the region has a non-empty inner rim. 49 | /// 50 | public bool HasInnerPolygon => Inner.Count > 0; 51 | 52 | /// 53 | /// Adds an inner contour to the present object. The inner contour should contain 54 | /// the points on the inner rim of the region of interest (innermost points that are 55 | /// still foreground). 56 | /// 57 | /// The points on the inner rim of the region, surrounding any "holes". 58 | public void AddInnerContour(PolygonPoints inner) 59 | { 60 | Inner.Add(inner ?? throw new ArgumentNullException(nameof(inner))); 61 | TotalPixels -= inner.VoxelCounts.Total; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Contours/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | using System.Reflection; 7 | using System.Runtime.CompilerServices; 8 | using System.Runtime.InteropServices; 9 | 10 | // General Information about an assembly is controlled through the following 11 | // set of attributes. Change these attribute values to modify the information 12 | // associated with an assembly. 13 | [assembly: AssemblyTitle("InnerEye.CreateDataset.Contours")] 14 | [assembly: AssemblyDescription("")] 15 | [assembly: AssemblyConfiguration("")] 16 | [assembly: AssemblyCompany("")] 17 | [assembly: AssemblyProduct("InnerEye.CreateDataset.Contours")] 18 | [assembly: AssemblyCopyright("Copyright © 2019")] 19 | [assembly: AssemblyTrademark("")] 20 | [assembly: AssemblyCulture("")] 21 | 22 | // Setting ComVisible to false makes the types in this assembly not visible 23 | // to COM components. If you need to access a type in this assembly from 24 | // COM, set the ComVisible attribute to true on that type. 25 | [assembly: ComVisible(false)] 26 | 27 | // The following GUID is for the ID of the typelib if this project is exposed to COM 28 | [assembly: Guid("a27fa639-8a1d-40cc-8bc8-7bea28e615b2")] 29 | 30 | // Version information for an assembly consists of the following four values: 31 | // 32 | // Major Version 33 | // Minor Version 34 | // Build Number 35 | // Revision 36 | // 37 | // You can specify all the values or you can default the Build and Revision Numbers 38 | // by using the '*' as shown below: 39 | // [assembly: AssemblyVersion("1.0.*")] 40 | [assembly: AssemblyVersion("1.0.0.0")] 41 | [assembly: AssemblyFileVersion("1.0.0.0")] 42 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Contours/VoxelCounts.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Contours 7 | { 8 | /// 9 | /// Contains statistics about the set of voxel values found in a region. 10 | /// 11 | public class VoxelCounts 12 | { 13 | /// 14 | /// Creates a new instance of the class, with all counters set to 0. 15 | /// 16 | public VoxelCounts() 17 | { 18 | Foreground = 0; 19 | Other = 0; 20 | } 21 | 22 | /// 23 | /// Creates a new instance of the class, with all counters set to the given values. 24 | /// 25 | public VoxelCounts(uint foreground, uint other) 26 | { 27 | Foreground = foreground; 28 | Other = other; 29 | } 30 | 31 | /// 32 | /// Gets the number of voxels that have the foreground value. 33 | /// 34 | public uint Foreground { get; set; } 35 | 36 | /// 37 | /// Gets the number of voxels that have a value that is different from the foreground 38 | /// (background and any other, possibly unexpected values). 39 | /// 40 | public uint Other { get; set; } 41 | 42 | /// 43 | /// Gets the total number of voxels that the present object is tracking. 44 | /// 45 | public uint Total => Foreground + Other; 46 | 47 | /// 48 | /// Add up the corresponding fields of the two arguments. 49 | /// 50 | /// 51 | /// 52 | /// 53 | public static VoxelCounts operator +(VoxelCounts left, VoxelCounts right) 54 | { 55 | return new VoxelCounts( 56 | left.Foreground + right.Foreground, 57 | left.Other + right.Other); 58 | } 59 | 60 | public static VoxelCounts Add(VoxelCounts left, VoxelCounts right) 61 | { 62 | return left + right; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Contours/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Core/Commandline/CommandlineAnalyzeDataset.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Core 7 | { 8 | using CommandLine; 9 | 10 | [Verb("analyze", HelpText = "Analyzes a converted dataset in NIFTI format by deriving statistics.")] 11 | public class CommandlineAnalyzeDataset : CommandlineShared 12 | { 13 | /// 14 | /// Gets or sets the un-processed commandline arguments that have been passed into the CreateDataset runner. 15 | /// 16 | public string[] RawCommandlineArguments { get; set; } 17 | 18 | /// 19 | /// The full path to the dataset folder to be analyzed. 20 | /// 21 | [Option('d', "datasetFolder", HelpText = "Location of the nifti dataset to be analyzed")] 22 | public string DatasetFolder { get; set; } 23 | 24 | [Option('s', "statisticsFolder", Default="statistics", HelpText = "Name of subfolder to receive statistics files (must not already exist)")] 25 | public string StatisticsFolder { get; set; } 26 | 27 | /// 28 | /// Include "external" (if present) in the pairwise comparisons. 29 | /// 30 | [Option('e', "includePairwiseExternal", Default = false, HelpText = "Whether to calculate pairwise statistics involving the \"external\" structure (time consuming!)")] 31 | public bool PairwiseExternal { get; set; } 32 | 33 | [Option('a', "subjectsToAnalyze", Default = "", HelpText = "Comma-separated list of subject IDs and ranges to analyze, e.g. 3,13,17-20")] 34 | public string SubjectsToAnalyze { get; set; } 35 | 36 | /// 37 | /// Creates a new command line option instance, with all properties set to their default values. 38 | /// 39 | public CommandlineAnalyzeDataset() { } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Core/Commandline/CommandlineShared.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Core 7 | { 8 | /// 9 | /// Contains commandline options that are shared across all operation models of the runner: 10 | /// dataset creation, analysis. 11 | /// 12 | public class CommandlineShared 13 | { 14 | /// 15 | /// Creates a new command line option instance, with all properties set to their default values. 16 | /// 17 | public CommandlineShared() { } 18 | 19 | /// 20 | /// Checks if the command line options are valid. Throws exceptions if any issues are found. 21 | /// 22 | virtual public void Validate() { } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Core/DatasetLoader.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | using MedLib.IO; 7 | using MedLib.IO.Readers; 8 | using System.Diagnostics; 9 | using System.IO; 10 | using System.Collections.Generic; 11 | using System.Linq; 12 | using System; 13 | using MedLib.IO.Models; 14 | 15 | namespace InnerEye.CreateDataset.Core 16 | { 17 | class DatasetLoader 18 | { 19 | private string _datasetPath; 20 | 21 | public DatasetLoader(string datasetPath) 22 | { 23 | _datasetPath = datasetPath; 24 | } 25 | 26 | /// 27 | /// Iterates through all subfolders (non recursive) and reads a Dicom series from each one. 28 | /// 29 | /// 30 | public IEnumerable> LoadAllDicomSeries() 31 | { 32 | 33 | // TODO group by SubjectID 34 | var acceptanceTest = new NonStrictGeometricAcceptanceTest("Non square pixels", "Orientation unsupported"); 35 | var subjectIdsToIndices = new List(); 36 | 37 | foreach (var folder in Directory.EnumerateDirectories(_datasetPath)) 38 | { 39 | var subjectVolumes = new List(); 40 | var stopWatch = Stopwatch.StartNew(); 41 | var volume = MedIO.LoadSingleDicomSeriesAsync(folder, acceptanceTest).Result; 42 | var seriesId = getSeriesId(volume); 43 | var subjectId = getSubjectId(volume); 44 | if (!volume.IsCT) 45 | { 46 | throw new InvalidOperationException("Only CT supported"); 47 | } 48 | var channel = "ct"; 49 | var id = subjectIdsToIndices.IndexOf(subjectId); 50 | if (id == -1) 51 | { 52 | subjectIdsToIndices.Add(subjectId); 53 | id = subjectIdsToIndices.Count() - 1; 54 | } 55 | var info = new VolumeMetadata(seriesId, id, channel); 56 | subjectVolumes.Add(new VolumeAndMetadata(info, volume)); 57 | yield return subjectVolumes; 58 | } 59 | } 60 | 61 | /// 62 | /// Returns the series ID of the volume 63 | /// 64 | /// 65 | private string getSeriesId(MedicalVolume volume) 66 | { 67 | return volume.Struct.Study.StudyInstanceUid; 68 | } 69 | 70 | /// 71 | /// Returns the subject ID of the volume 72 | /// 73 | /// 74 | private string getSubjectId(MedicalVolume volume) 75 | { 76 | return volume.Struct.Patient.Id; 77 | } 78 | 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Core/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | using System.Reflection; 7 | using System.Runtime.InteropServices; 8 | 9 | // General Information about an assembly is controlled through the following 10 | // set of attributes. Change these attribute values to modify the information 11 | // associated with an assembly. 12 | [assembly: AssemblyTitle("InnerEye.CreateDataset.Core")] 13 | [assembly: AssemblyDescription("")] 14 | [assembly: AssemblyConfiguration("")] 15 | [assembly: AssemblyCompany("")] 16 | [assembly: AssemblyProduct("InnerEye.CreateDataset.Core")] 17 | [assembly: AssemblyCopyright("Copyright © 2017")] 18 | [assembly: AssemblyTrademark("")] 19 | [assembly: AssemblyCulture("")] 20 | 21 | // Setting ComVisible to false makes the types in this assembly not visible 22 | // to COM components. If you need to access a type in this assembly from 23 | // COM, set the ComVisible attribute to true on that type. 24 | [assembly: ComVisible(false)] 25 | 26 | // The following GUID is for the ID of the typelib if this project is exposed to COM 27 | [assembly: Guid("99e3572c-9636-4101-995b-9c0642930f2d")] 28 | 29 | // Version information for an assembly consists of the following four values: 30 | // 31 | // Major Version 32 | // Minor Version 33 | // Build Number 34 | // Revision 35 | // 36 | // You can specify all the values or you can default the Build and Revision Numbers 37 | // by using the '*' as shown below: 38 | // [assembly: AssemblyVersion("1.0.*")] 39 | [assembly: AssemblyVersion("1.0.0.0")] 40 | [assembly: AssemblyFileVersion("1.0.0.0")] 41 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Core/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Data/ActivePatterns.fs: -------------------------------------------------------------------------------- 1 | module InnerEye.CreateDataset.Data.ActivePatterns 2 | 3 | /// ------------------------------------------------------------------------------------------ 4 | /// Copyright (c) Microsoft Corporation. All rights reserved. 5 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 6 | /// ------------------------------------------------------------------------------------------ 7 | 8 | open System 9 | 10 | /// An active pattern to match strings that start with the given prefix string. Matching result 11 | /// is the string with the prefix stripped off 12 | let (|StartsWith|_|) startString (s: string) = 13 | if s.StartsWith startString then 14 | s.Substring startString.Length 15 | |> Some 16 | else 17 | None 18 | 19 | /// An active pattern to match strings that end with the given postfix string. Matching result 20 | /// is the string with the postfix stripped off 21 | let (|EndsWith|_|) endString (s: string) = 22 | if s.EndsWith endString then 23 | s.Substring(0, s.Length - endString.Length) 24 | |> Some 25 | else 26 | None 27 | 28 | /// An active pattern to recognize strings that are null or empty. 29 | let (|IsNullOrEmpty|NonEmptyString|) (s: string) = 30 | if String.IsNullOrEmpty s then 31 | IsNullOrEmpty s 32 | else 33 | NonEmptyString s 34 | 35 | /// An active pattern to recognize strings that are null or whitespace. 36 | let (|IsNullOrWhiteSpace|NonTrivialString|) (s: string) = 37 | if String.IsNullOrWhiteSpace s then 38 | IsNullOrWhiteSpace s 39 | else 40 | NonTrivialString s 41 | 42 | /// Splits a string at the last ccurrence of a given character. Returns the string 43 | /// up to the character, and the string after the character. Returns None if the character 44 | /// does not occur in the string. 45 | let (|SplitByLastIndexOf|_|) (splitChar: char) (s: string) = 46 | match s.LastIndexOf splitChar with 47 | | index when index < 0 -> 48 | None 49 | | index -> 50 | Some(s.Substring(0, index), s.Substring(index + 1)) 51 | 52 | /// Splits a string at the first occurrence of a given character. Returns the string 53 | /// up to the character. Returns None if the character does not occur in the string. 54 | let (|UpToFirstIndexOf|_|) (splitChar: char) (s: string) = 55 | match s.IndexOf splitChar with 56 | | index when index < 0 -> 57 | None 58 | | index -> 59 | Some(s.Substring(0, index)) 60 | 61 | /// Splits a string at the first occurrence of a given character. Returns the string 62 | /// starting after the character. Returns None if the character does not occur in the string. 63 | let (|AfterFirstIndexOf|_|) (splitChar: char) (s: string) = 64 | match s.IndexOf splitChar with 65 | | index when index < 0 -> 66 | None 67 | | index -> 68 | Some(s.Substring(index + 1)) 69 | 70 | /// Splits a string at the first occurrence of a given string. Returns the string 71 | /// up to the split, and the string after the split. Returns None if the splitting 72 | /// string is not found. 73 | let (|SplitByString|_|) (splitString: string) (s: string) = 74 | match s.IndexOf splitString with 75 | | index when index < 0 -> 76 | None 77 | | index -> 78 | Some(s.Substring(0, index), s.Substring(index + splitString.Length)) 79 | 80 | 81 | /// An active pattern to match values in a System.Nullable, or check for it being null. 82 | let (|HasValue|IsNull|) (n: Nullable<_>) = 83 | if n.HasValue then 84 | HasValue n.Value 85 | else 86 | IsNull 87 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Data/AssemblyInfo.fs: -------------------------------------------------------------------------------- 1 | namespace InnerEye.CreateDataset.Data.AssemblyInfo 2 | 3 | /// ------------------------------------------------------------------------------------------ 4 | /// Copyright (c) Microsoft Corporation. All rights reserved. 5 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 6 | /// ------------------------------------------------------------------------------------------ 7 | 8 | open System.Reflection 9 | open System.Runtime.CompilerServices 10 | open System.Runtime.InteropServices 11 | 12 | // General Information about an assembly is controlled through the following 13 | // set of attributes. Change these attribute values to modify the information 14 | // associated with an assembly. 15 | [] 16 | [] 17 | [] 18 | [] 19 | [] 20 | [] 21 | [] 22 | [] 23 | 24 | // Setting ComVisible to false makes the types in this assembly not visible 25 | // to COM components. If you need to access a type in this assembly from 26 | // COM, set the ComVisible attribute to true on that type. 27 | [] 28 | 29 | // The following GUID is for the ID of the typelib if this project is exposed to COM 30 | [] 31 | 32 | // Version information for an assembly consists of the following four values: 33 | // 34 | // Major Version 35 | // Minor Version 36 | // Build Number 37 | // Revision 38 | // 39 | // You can specify all the values or you can default the Build and Revision Numbers 40 | // by using the '*' as shown below: 41 | // [] 42 | [] 43 | [] 44 | 45 | do 46 | () -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Data/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/ContourExtensionsTests.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Math.Tests 7 | { 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using InnerEye.CreateDataset.Volumes; 12 | using InnerEye.CreateDataset.Contours; 13 | using System.Drawing; 14 | using NUnit.Framework; 15 | 16 | [TestFixture] 17 | public class ContourExtensionsTests 18 | { 19 | [Description("Tests getting the region from a collection of contours on a slice returns the correct result.")] 20 | [Test] 21 | public void GetRegionContoursTest() 22 | { 23 | var contours = new List() 24 | { 25 | new ContourPolygon(new PointF[] 26 | { 27 | new PointF(5, 10), 28 | new PointF(12, 45), 29 | new PointF(87, 2), 30 | new PointF(234, 5) 31 | }, 32 | 0), 33 | new ContourPolygon(new PointF[] 34 | { 35 | new PointF(5, 10), 36 | new PointF(12, 45), 37 | new PointF(1, 23), 38 | new PointF(12, 44), 39 | new PointF(15, 48), 40 | }, 41 | 0), 42 | new ContourPolygon(new PointF[] 43 | { 44 | new PointF(5, 10), 45 | new PointF(12, 45), 46 | }, 47 | 0) 48 | }; 49 | 50 | var region = contours.GetRegion(); 51 | 52 | Assert.AreEqual(1, region.MinimumX); 53 | Assert.AreEqual(2, region.MinimumY); 54 | Assert.AreEqual(234, region.MaximumX); 55 | Assert.AreEqual(48, region.MaximumY); 56 | 57 | Assert.Throws(() => new List().GetRegion()); 58 | } 59 | 60 | [Description("Tests that getting min/ max slices returns the correct result.")] 61 | [Test] 62 | public void GetMinMaxSlicesTest() 63 | { 64 | var contoursBySlice = new Contours.ContoursPerSlice(new Dictionary>() 65 | { 66 | { 5, new List() }, 67 | { 7, new List() }, 68 | { 10, new List() }, 69 | { 15, new List() }, 70 | { 6, new List() }, 71 | { 8, new List() }, 72 | { 12, new List() }, 73 | { 90, new List() }, 74 | }); 75 | 76 | var minMax = contoursBySlice.GetMinMaxSlices(); 77 | 78 | Assert.AreEqual(5, minMax.Min); 79 | Assert.AreEqual(90, minMax.Max); 80 | } 81 | 82 | [Description("Tests that getting min/ max intensities of a volume3d returns correct values")] 83 | [Test] 84 | public void GetMinMaxOfVolume3D() 85 | { 86 | var array = Enumerable.Range(0, 100).Select(x => (short)x).ToArray(); 87 | var volume = new Volume3D(array, array.Length, 1, 1, 1, 1, 1); 88 | 89 | var minMax = volume.GetMinMax(); 90 | 91 | Assert.AreEqual(0, minMax.Minimum); 92 | Assert.AreEqual(99, minMax.Maximum); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/ContourStatisticsTests.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Math.Tests 7 | { 8 | using InnerEye.CreateDataset.Contours; 9 | using InnerEye.CreateDataset.Volumes; 10 | 11 | using NUnit.Framework; 12 | 13 | using System.Linq; 14 | 15 | [TestFixture] 16 | public class ContourStatisticsTests 17 | { 18 | private Volume3D CreateVolume(T[] array, int dimX, int dimY, int dimZ) => 19 | new Volume3D(array, dimX, dimY, dimZ, 1, 1, 1, new Point3D(), Matrix3.CreateIdentity()); 20 | 21 | [Test()] 22 | public void CheckBasicVolumeStats() 23 | { 24 | var volumeArray = new short[] 25 | { 26 | 10, 10, 10, 27 | 10, 20, 0, 28 | 10, 0, 20 29 | }; 30 | 31 | var volume = CreateVolume(volumeArray, 3, 3, 1); 32 | 33 | var contourVolumeArray = new byte[] 34 | { 35 | 0, 0, 0, 36 | 0, 1, 1, 37 | 0, 1, 1 38 | }; 39 | 40 | var contourVolume = CreateVolume(contourVolumeArray, 3, 3, 1); 41 | 42 | var stats = ContourStatistics.FromVolumeAndMask(new ReadOnlyVolume3D(volume), contourVolume); 43 | 44 | Assert.AreEqual(10, stats.VoxelValueMean); 45 | Assert.AreEqual(10, stats.VoxelValueStandardDeviation); 46 | Assert.AreEqual(0.004, stats.SizeInCubicCentimeters); 47 | } 48 | 49 | [Test()] 50 | public void EmptyContour() 51 | { 52 | var volumeArray = new short[] 53 | { 54 | 10, 10, 10, 55 | 10, 20, 0, 56 | 10, 0, 20 57 | }; 58 | 59 | var volume = CreateVolume(volumeArray, 3, 3, 1); 60 | 61 | var contourVolumeArray = new byte[] 62 | { 63 | 0, 0, 0, 64 | 0, 0, 0, 65 | 0, 0, 0 66 | }; 67 | 68 | var contourVolume = CreateVolume(contourVolumeArray, 3, 3, 1); 69 | 70 | var stats = ContourStatistics.FromVolumeAndMask(new ReadOnlyVolume3D(volume), contourVolume); 71 | 72 | Assert.AreEqual(0, stats.VoxelValueMean); 73 | Assert.AreEqual(0, stats.VoxelValueStandardDeviation); 74 | Assert.AreEqual(0, stats.SizeInCubicCentimeters); 75 | } 76 | 77 | [Test()] 78 | public void HugeContour() 79 | { 80 | var dimX = 256; 81 | var dimY = 256; 82 | var dimZ = 512; 83 | var totalSize = dimX * dimY * dimZ; 84 | var volumeArray = Enumerable.Range(0, totalSize).Select(x => (short)(x % 2 == 0 ? 0 : 20)).ToArray(); 85 | 86 | var volume = CreateVolume(volumeArray, dimX, dimY, 512); 87 | 88 | var contourVolumeArray = Enumerable.Range(0, totalSize).Select(x => (byte)1).ToArray(); 89 | 90 | var contourVolume = CreateVolume(contourVolumeArray, dimX, dimY, 512); 91 | 92 | var stats = ContourStatistics.FromVolumeAndMask(new ReadOnlyVolume3D(volume), contourVolume); 93 | 94 | Assert.AreEqual(10, stats.VoxelValueMean); 95 | Assert.AreEqual(10, stats.VoxelValueStandardDeviation); 96 | Assert.AreEqual(totalSize / 1000d, stats.SizeInCubicCentimeters); 97 | } 98 | 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/EuclideanDistanceTests.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace MedLib.IO.Tests 7 | { 8 | using System; 9 | using System.Drawing; 10 | using System.IO; 11 | using System.Linq; 12 | using InnerEye.CreateDataset.Math; 13 | using InnerEye.CreateDataset.Volumes; 14 | 15 | using NUnit.Framework; 16 | 17 | [TestFixture] 18 | public class EuclideanDistanceTests 19 | { 20 | [TestCase(@"LoadTest1\\triangle.png")] 21 | public void EuclideanDistanceTest(string filename) 22 | { 23 | string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TestData", filename); 24 | string resultPath = Path.GetDirectoryName(filePath) + @"\\result.png"; 25 | 26 | var image = new Bitmap(filePath); 27 | byte[] mask = ImageToByte(image); 28 | 29 | var mask2d = new InnerEye.CreateDataset.Volumes.Volume2D(mask, image.Width, image.Height, 1, 1, new Point2D(), Matrix2.CreateIdentity()); 30 | 31 | var contours = mask2d.ContoursWithHoles(); 32 | mask2d.Fill(contours, (byte)1); 33 | 34 | var contourMask = new InnerEye.CreateDataset.Volumes.Volume2D(image.Width, image.Height, 1, 1, new Point2D(), Matrix2.CreateIdentity()); 35 | 36 | foreach (var point in contours.SelectMany(x => x.ContourPoints)) 37 | { 38 | var index = contourMask.GetIndex((int)point.X, (int)point.Y); 39 | contourMask[index] = 1; 40 | } 41 | 42 | var distanceMap = contourMask.EuclideanDistance(); 43 | #if DEBUG 44 | PrintByteArray(distanceMap.Array, image.Width, image.Height, resultPath); 45 | #endif 46 | } 47 | 48 | public static void PrintByteArray(float[] img, int dimX, int dimY, string resultPath) 49 | { 50 | Bitmap plane = new Bitmap(dimX, dimY); 51 | 52 | for (int y = 0; y < dimY; y++) 53 | { 54 | for (int x = 0; x < dimX; x++) 55 | { 56 | var index = x + y * dimX; 57 | var colorValue = (int)img[index] == 1 ? 255 : 0; 58 | plane.SetPixel(x, y, Color.FromArgb(colorValue, colorValue, colorValue)); 59 | } 60 | } 61 | 62 | plane.Save(resultPath); 63 | } 64 | 65 | public static byte[] ImageToByte(Bitmap img) 66 | { 67 | var array = new byte[img.Width * img.Height]; 68 | 69 | for (int y = 0; y < img.Height; y++) 70 | { 71 | for (int x = 0; x < img.Width; x++) 72 | { 73 | // Get the color of a pixel within myBitmap. 74 | Color pixelColor = img.GetPixel(x, y); 75 | var index = x + y * img.Width; 76 | array[index] = (byte)(pixelColor.R == 0 ? 1 : 0); 77 | } 78 | } 79 | 80 | return array; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/Morphology/StructuringElementTests.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | using InnerEye.CreateDataset.Math.Morphology; 7 | using InnerEye.CreateDataset.Volumes; 8 | 9 | using NUnit.Framework; 10 | 11 | namespace InnerEye.CreateDataset.Math.Tests.Morphology 12 | { 13 | [TestFixture] 14 | public class StructuringElementTests 15 | { 16 | /// 17 | /// Test to capture encoding of the structuring element 18 | /// 19 | [Test] 20 | public void StructuringElementEncodingTest() 21 | { 22 | var result = new StructuringElement(1, 1, 0).Mask; 23 | var expected = new Volume3D(3, 3, 1, 1, 1, 1); 24 | expected[1, 0, 0] = 1; 25 | expected[0, 1, 0] = 1; 26 | expected[1, 1, 0] = 1; 27 | expected[2, 1, 0] = 1; 28 | expected[1, 2, 0] = 1; 29 | CollectionAssert.AreEqual(expected.Array, result.Array); 30 | } 31 | 32 | /// 33 | /// Test to capture encoding of the structuring element with zero margin 34 | /// (which is not possible for dilation but can be possible for erosion). 35 | /// The expected behaviour is to generate a mask with only the center voxel 36 | /// in the foreground. 37 | /// 38 | [Test] 39 | public void StructuringElementEncodingZeroMarginTest() 40 | { 41 | var result = new StructuringElement(0, 0, 0).Mask; 42 | var expected = new Volume3D(1, 1, 1, 1, 1, 1); 43 | expected[0, 0, 0] = 1; 44 | CollectionAssert.AreEqual(expected.Array, result.Array); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/Morphology/TestData/Structures/ParentVolume.nii.gz: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:0c538b3653a20f35c9d77971ffc96504bad3e4d78abc5ed1a628f5dd882ca405 3 | size 92 4 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/Morphology/TestData/Structures/Structure1.nii.gz: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:c166393cb8fd9daded0c1b5ca68af343c1fde64095751cdd3ff041e23e98d204 3 | size 108 4 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/Morphology/TestData/Structures/Structure1IntersectStructure2.nii.gz: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:ed04fde5808cc871a2b382b747616c2e450c1df8ddf54b943a2d8620b608da63 3 | size 123 4 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/Morphology/TestData/Structures/Structure1MinusStructure2.nii.gz: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:e5543758a8a1d77380e35f182acff729929696b6e5286597e5169b3e434f5a31 3 | size 126 4 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/Morphology/TestData/Structures/Structure1UnionStructure2.nii.gz: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:cdd0d0aa69e98a0d3d825cf79b851ebc3fefa7f7657bb6eb87b6b73fc9f39275 3 | size 137 4 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/Morphology/TestData/Structures/Structure2.nii.gz: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:e45dfa43a1a4688b19eaa3e9f20a773b8cf68be4f36566d7c5acf6fc8f24a143 3 | size 108 4 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/Morphology/TestData/triangle.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:99fd89b1e7dfb8847d362ac289b48b733d12e28ec1f084e203899c41474bd477 3 | size 181 4 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/Point3DTests.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Math.Tests 7 | { 8 | using System.Collections.Generic; 9 | 10 | using InnerEye.CreateDataset.Volumes; 11 | 12 | using NUnit.Framework; 13 | 14 | [TestFixture] 15 | public class Point3DTests 16 | { 17 | private static IEnumerable Set3Dimensions(double value) 18 | { 19 | yield return new Point3D(value, 0, 0); 20 | yield return new Point3D(0, value, 0); 21 | yield return new Point3D(0, 0, value); 22 | } 23 | 24 | [Test] 25 | public void Point3DIsInfinity() 26 | { 27 | var zero = Point3D.Zero(); 28 | Assert.IsFalse(zero.IsInfinity()); 29 | Assert.IsFalse(zero.IsNaN()); 30 | Assert.IsTrue(zero.IsValid()); 31 | foreach (var infinity in new[] { double.PositiveInfinity, double.NegativeInfinity }) 32 | { 33 | foreach (var point in Set3Dimensions(infinity)) 34 | { 35 | Assert.IsTrue(point.IsInfinity()); 36 | Assert.IsFalse(point.IsNaN()); 37 | Assert.IsFalse(point.IsValid()); 38 | } 39 | } 40 | } 41 | 42 | [Test] 43 | public void Point3DIsNaN() 44 | { 45 | foreach (var point in Set3Dimensions(double.NaN)) 46 | { 47 | Assert.IsTrue(point.IsNaN()); 48 | Assert.IsFalse(point.IsInfinity()); 49 | Assert.IsFalse(point.IsValid()); 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | using System.Reflection; 7 | using System.Runtime.CompilerServices; 8 | using System.Runtime.InteropServices; 9 | 10 | // General Information about an assembly is controlled through the following 11 | // set of attributes. Change these attribute values to modify the information 12 | // associated with an assembly. 13 | [assembly: AssemblyTitle("InnerEye.CreateDataset.Math.Tests")] 14 | [assembly: AssemblyDescription("")] 15 | [assembly: AssemblyConfiguration("")] 16 | [assembly: AssemblyCompany("")] 17 | [assembly: AssemblyProduct("InnerEye.CreateDataset.Math.Tests")] 18 | [assembly: AssemblyCopyright("Copyright © 2017")] 19 | [assembly: AssemblyTrademark("")] 20 | [assembly: AssemblyCulture("")] 21 | 22 | // Setting ComVisible to false makes the types in this assembly not visible 23 | // to COM components. If you need to access a type in this assembly from 24 | // COM, set the ComVisible attribute to true on that type. 25 | [assembly: ComVisible(false)] 26 | 27 | // The following GUID is for the ID of the typelib if this project is exposed to COM 28 | [assembly: Guid("e56ba5c6-640b-4591-819f-aed8d41eaad7")] 29 | 30 | // Version information for an assembly consists of the following four values: 31 | // 32 | // Major Version 33 | // Minor Version 34 | // Build Number 35 | // Revision 36 | // 37 | // You can specify all the values or you can default the Build and Revision Numbers 38 | // by using the '*' as shown below: 39 | // [assembly: AssemblyVersion("1.0.*")] 40 | [assembly: AssemblyVersion("1.0.0.0")] 41 | [assembly: AssemblyFileVersion("1.0.0.0")] 42 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/ReadOnlyVolumeTests.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | using InnerEye.CreateDataset.Volumes; 7 | 8 | using NUnit.Framework; 9 | 10 | using System; 11 | 12 | namespace InnerEye.CreateDataset.Math.Tests 13 | { 14 | [TestFixture] 15 | public class ReadOnlyVolumeTests 16 | { 17 | [Test] 18 | public void Test3D() 19 | { 20 | var readonlyVolume3d = new ReadOnlyVolume3D(new Volume3D(1, 1, 1)); 21 | 22 | Assert.Throws(() => readonlyVolume3d[0] = 0); 23 | } 24 | 25 | [Test] 26 | public void Test2D() 27 | { 28 | var readonlyVolume2d = new ReadOnlyVolume2D(new Volume2D(1, 1, 1, 1, new Point2D(0, 0), Matrix2.CreateIdentity())); 29 | 30 | Assert.Throws(() => readonlyVolume2d[0] = 0); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/Region3DTests.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | using InnerEye.CreateDataset.Volumes; 7 | 8 | using NUnit.Framework; 9 | 10 | namespace InnerEye.CreateDataset.Math.Tests 11 | { 12 | [TestFixture] 13 | public class Region3DTests 14 | { 15 | [Test] 16 | public void EqualityCheck() 17 | { 18 | Assert.AreNotEqual(new Region3D(0, 0, 0, 1, 1, 1),new Region3D(1, 1, 1, 0, 0, 0)); 19 | Assert.AreNotEqual(new Region3D(0, 0, 0, 1, 1, 1), new Region3D(0, 1, 0, 1, 1, 1)); 20 | Assert.AreNotEqual(new Region3D(0, 0, 0, 1, 1, 1), new Region3D(0, 0, 1, 1, 1, 1)); 21 | Assert.AreNotEqual(new Region3D(0, 0, 0, 1, 1, 1), new Region3D(0, 1, 1, 1, 1, 1)); 22 | Assert.AreNotEqual(new Region3D(0, 0, 0, 1, 1, 1), new Region3D(1, 0, 1, 1, 1, 1)); 23 | 24 | 25 | Assert.AreNotEqual(new Region3D(0, 0, 0, 1, 1, 1), new Region3D(0, 0, 0, 0, 1, 0)); 26 | Assert.AreNotEqual(new Region3D(0, 0, 0, 1, 1, 1), new Region3D(0, 1, 0, 0, 0, 1)); 27 | Assert.AreNotEqual(new Region3D(0, 0, 0, 1, 1, 1), new Region3D(0, 0, 1, 1, 1, 1)); 28 | Assert.AreNotEqual(new Region3D(0, 0, 0, 1, 1, 1), new Region3D(0, 1, 1, 0, 1, 1)); 29 | Assert.AreNotEqual(new Region3D(0, 0, 0, 1, 1, 1), new Region3D(1, 0, 1, 1, 0, 1)); 30 | Assert.AreEqual(new Region3D(0, 0, 0, 1, 1, 1), new Region3D(0, 0, 0, 1, 1, 1)); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/ResamplingTests.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Math.Tests 7 | { 8 | using System.Linq; 9 | using InnerEye.CreateDataset.Contours; 10 | using InnerEye.CreateDataset.Math; 11 | using InnerEye.CreateDataset.Volumes; 12 | 13 | using NUnit.Framework; 14 | 15 | [TestFixture] 16 | public class ResamplingTests 17 | { 18 | [TestCase(0.5)] 19 | [TestCase(0.8)] 20 | [TestCase(0.6)] 21 | [TestCase(1.0)] 22 | [TestCase(2.0)] 23 | 24 | public void CheckResamplingNearestAndLinear(double factorXY) 25 | { 26 | int dimX = 100; 27 | int dimY = 100; 28 | int dimZ = 3; 29 | int spacingX = 1; 30 | int spacingY = 1; 31 | int spacingZ = 3; 32 | var volume = new Volume3D(dimX, dimY, dimZ, spacingX, spacingY, spacingZ); 33 | FillHalf(volume); 34 | PrintToPng(volume, $"input{factorXY}"); 35 | var output = volume.ResampleNearest((int)(dimX * factorXY), (int)(dimY * factorXY), dimZ, 0); 36 | PrintToPng(output, $"outputNearest{factorXY}"); 37 | 38 | var expectedReduction = volume.Array.Sum() * factorXY * factorXY; 39 | 40 | Assert.AreEqual(expectedReduction, output.Array.Sum(), $"{output.Array.Sum()}"); 41 | 42 | output = volume.ResampleLinear((int)(dimX * factorXY), (int)(dimY * factorXY), dimZ); 43 | PrintToPng(output, $"outputLinea{factorXY}"); 44 | Assert.AreEqual(expectedReduction, output.Array.Sum(), $"{output.Array.Sum()}"); 45 | } 46 | 47 | private static void PrintToPng(Volume3D output, string name) 48 | { 49 | #if DEBUG 50 | var outputByte = output.CreateSameSize(); 51 | for (int i = 0; i < outputByte.Length; i++) 52 | { 53 | outputByte[i] = (byte)output[i]; 54 | } 55 | 56 | for (int i = 0; i < output.DimZ; i++) 57 | { 58 | outputByte.Slice(Volumes.SliceType.Axial, 1).SaveBrushVolumeToPng($@"C:\temp\{i}{name}.png"); 59 | } 60 | #endif 61 | } 62 | 63 | private void FillHalf(Volume3D volume) 64 | { 65 | for (int i = 0; i < volume.Length; i = i + 2) 66 | { 67 | volume[i] = 3; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/TestData/DilateTest1/result.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:2f966c9045aad37f1d9b4f4b48100deca147d7e49ddaf1d778a7997a1efe841b 3 | size 185 4 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/TestData/DilateTest1/triangle.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:99fd89b1e7dfb8847d362ac289b48b733d12e28ec1f084e203899c41474bd477 3 | size 181 4 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/TestData/ErodeTest1/result.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:74f929e10044e5f8c69fa6cf49967ffd7b264a289064c9325d5c3dcac7dec11f 3 | size 179 4 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/TestData/ErodeTest1/resultErode1.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:f4b84a1554c336c90b8f43576673790ece80926e91beb72ac82d37976af4e7cb 3 | size 191 4 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/TestData/ErodeTest1/triangle.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:99fd89b1e7dfb8847d362ac289b48b733d12e28ec1f084e203899c41474bd477 3 | size 181 4 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/TestData/LoadTest1/triangle.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:99fd89b1e7dfb8847d362ac289b48b733d12e28ec1f084e203899c41474bd477 3 | size 181 4 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/TestingExtensions.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | using NUnit.Framework; 7 | using System; 8 | 9 | namespace InnerEye.Tests.Common 10 | { 11 | public static class TestingExtension 12 | { 13 | public static void Throws(Action task, string expectedMessage = "") where T : Exception 14 | { 15 | try 16 | { 17 | task(); 18 | } 19 | catch (Exception ex) 20 | { 21 | if (expectedMessage != "") 22 | { 23 | Assert.AreEqual(expectedMessage, ex.Message); 24 | } 25 | Assert.AreEqual(typeof(T), ex.GetType()); 26 | return; 27 | } 28 | 29 | if (typeof(T).Equals(new Exception().GetType())) 30 | { 31 | Assert.Fail("Expected exception but no exception was thrown."); 32 | } 33 | else 34 | { 35 | Assert.Fail(string.Format("Expected exception of type {0} but no exception was thrown.", typeof(T))); 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/Transform3Tests.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Math.Tests 7 | { 8 | using InnerEye.CreateDataset.Volumes; 9 | 10 | using NUnit.Framework; 11 | 12 | [TestFixture] 13 | public class Transform3Tests 14 | { 15 | [Test] 16 | public void TestTransform3() 17 | { 18 | var transform = new Transform3( 19 | new Matrix3(new double[] 20 | { 21 | 5, 0, 0, 22 | 0, 5, 0, 23 | 0, 0, 5 24 | }), 25 | new Point3D(6, 7, 8)); 26 | 27 | var result1 = transform.Transform(new Point3D(6, 7, 8)); 28 | var result2 = transform * new Point3D(6, 7, 8); 29 | 30 | Assert.AreEqual(36, result1.X); 31 | Assert.AreEqual(42, result1.Y); 32 | Assert.AreEqual(48, result1.Z); 33 | 34 | Assert.AreEqual(result1.X, result2.X); 35 | Assert.AreEqual(result1.Y, result2.Y); 36 | Assert.AreEqual(result1.Z, result2.Z); 37 | 38 | var inverseTransform = transform.Inverse(); 39 | result1 = inverseTransform.Transform(new Point3D(200, 200, 200)); 40 | 41 | Assert.AreEqual(38.8, result1.X); 42 | Assert.AreEqual(38.6, result1.Y); 43 | Assert.AreEqual(38.4, result1.Z); 44 | 45 | transform = inverseTransform.Inverse(); 46 | result1 = transform.Transform(new Point3D(6, 7, 8)); 47 | 48 | Assert.AreEqual(36, result1.X); 49 | Assert.AreEqual(42, result1.Y); 50 | Assert.AreEqual(48, result1.Z); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/VolumeTests.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Math.Tests 7 | { 8 | using System; 9 | using System.Linq; 10 | using InnerEye.CreateDataset.Volumes; 11 | 12 | using NUnit.Framework; 13 | 14 | [TestFixture] 15 | public class VolumeTests 16 | { 17 | [Test] 18 | public void VoxelVolume() 19 | { 20 | var spacingX = 2.0; 21 | var spacingY = 3.0; 22 | var spacingZ = 4.0; 23 | var volume = new Volume3D(2, 3, 4, spacingX, spacingY, spacingZ); 24 | Assert.AreEqual(24.0, volume.VoxelVolume, 1.0e-10); 25 | } 26 | 27 | 28 | [TestCase(1, 1)] 29 | [TestCase(1, 10)] 30 | [TestCase(10, 1)] 31 | [TestCase(7, 8)] 32 | public void Volume2DGetCoordinates(int dimX, int dimY) 33 | { 34 | var volume = new Volume2D(dimX, dimY, 1, 1, new Point2D(), new Matrix2()); 35 | foreach (var x in Enumerable.Range(0, dimX)) 36 | { 37 | foreach (var y in Enumerable.Range(0, dimY)) 38 | { 39 | var index = volume.GetIndex(x, y); 40 | var (x2, y2) = volume.GetCoordinates(index); 41 | Assert.AreEqual(x, x2, "coordinates-index-coordindates roundtrip failed"); 42 | Assert.AreEqual(y, y2, "coordinates-index-coordindates roundtrip failed"); 43 | } 44 | } 45 | Assert.Throws(() => volume.GetCoordinates(-1)); 46 | Assert.Throws(() => volume.GetCoordinates(volume.Length)); 47 | } 48 | 49 | [Test] 50 | public void VoxelIndex() 51 | { 52 | var volume = new Volume3D(3, 3, 3); 53 | volume.ParallelIterateSlices(p => 54 | { 55 | var expected = p.x + p.y * volume.DimX + p.z * volume.DimXY; 56 | Assert.AreEqual(expected, volume.GetIndex(p.x, p.y, p.z)); 57 | }); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math/ContourGeometryOperations.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Math 7 | { 8 | using System.Threading.Tasks; 9 | using InnerEye.CreateDataset.Volumes; 10 | using InnerEye.CreateDataset.Contours; 11 | 12 | public static class ContourGeometryOperations 13 | { 14 | public static Volume3D GeometryUnion(this ContoursPerSlice contour1, ContoursPerSlice contour2, Volume3D parentVolume) 15 | { 16 | var volume1 = contour1.ToVolume3D(parentVolume); 17 | var volume2 = contour2.ToVolume3D(parentVolume); 18 | 19 | Parallel.For(0, volume1.Length, i => 20 | { 21 | if (volume2[i] > 0) 22 | { 23 | volume1[i] = ModelConstants.MaskForegroundIntensity; 24 | } 25 | }); 26 | 27 | return volume1; 28 | } 29 | 30 | public static Volume3D GeometryIntersect(this ContoursPerSlice contour1, ContoursPerSlice contour2, Volume3D parentVolume) 31 | { 32 | var volume1 = contour1.ToVolume3D(parentVolume); 33 | var volume2 = contour2.ToVolume3D(parentVolume); 34 | 35 | Parallel.For(0, volume1.Length, i => 36 | { 37 | volume1[i] = volume1[i] > 0 && volume2[i] > 0 ? ModelConstants.MaskForegroundIntensity : ModelConstants.MaskBackgroundIntensity; 38 | }); 39 | 40 | return volume1; 41 | } 42 | 43 | public static Volume3D GeometryExclude(this ContoursPerSlice contour1, ContoursPerSlice contour2, Volume3D parentVolume) 44 | { 45 | var volume1 = contour1.ToVolume3D(parentVolume); 46 | var volume2 = contour2.ToVolume3D(parentVolume); 47 | 48 | Parallel.For(0, volume1.Length, i => 49 | { 50 | volume1[i] = volume1[i] > 0 && volume2[i] == 0 ? ModelConstants.MaskForegroundIntensity : ModelConstants.MaskBackgroundIntensity; 51 | }); 52 | 53 | return volume1; 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math/GenericExtensions.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Math 7 | { 8 | using System; 9 | 10 | public static class GenericExtensions 11 | { 12 | /// 13 | /// Sets all entries in the array to the given value. 14 | /// 15 | public static void Fill(this T[] array, T value) 16 | { 17 | if (array == null) 18 | { 19 | throw new ArgumentNullException(nameof(array)); 20 | } 21 | 22 | for (int i = 0; i < array.Length; i++) 23 | { 24 | array[i] = value; 25 | } 26 | } 27 | 28 | /// 29 | /// Creates an array of the given size, and fills all elements with 30 | /// the provided value. 31 | /// 32 | /// 33 | /// The length of the array that should be returned. 34 | /// The value to use for each element in the returned array. 35 | /// 36 | public static T[] CreateArray(int size, T value) 37 | { 38 | if (size < 0) 39 | { 40 | throw new ArgumentException("The array size must be non-negative.", nameof(size)); 41 | } 42 | 43 | var array = new T[size]; 44 | Fill(array, value); 45 | return array; 46 | } 47 | 48 | /// 49 | /// Copies all values from an array to the destination. 50 | /// 51 | public static void CopyTo(this T[] array, T[] destination) 52 | { 53 | if (array == null) 54 | { 55 | throw new ArgumentNullException(nameof(array)); 56 | } 57 | 58 | if (destination == null) 59 | { 60 | throw new ArgumentNullException(nameof(destination)); 61 | } 62 | 63 | if (array.Length != destination.Length) 64 | { 65 | throw new ArgumentException("Both arrays need to have the same length."); 66 | } 67 | 68 | for (int i = 0; i < array.Length; i++) 69 | { 70 | destination[i] = array[i]; 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math/Index3D.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Math 7 | { 8 | /// 9 | /// Represents the coordinates of a point, and its index with respect to the dimensions of 10 | /// a structure which is handed to the constructor but not stored. 11 | /// 12 | public struct Index3D 13 | { 14 | /// 15 | /// Location of the point on the x-axis 16 | /// 17 | public int X { get; } 18 | 19 | /// 20 | /// Location of the point on the y-axis 21 | /// 22 | public int Y { get; } 23 | 24 | /// 25 | /// Location of the point on the z-axis 26 | /// 27 | public int Z { get; } 28 | 29 | /// 30 | /// Index of the point in a Volume3D structure 31 | /// 32 | public int Index { get; } 33 | 34 | public Index3D((int x, int y, int z) p, int index) 35 | { 36 | Index = index; 37 | X = p.x; 38 | Y = p.y; 39 | Z = p.z; 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math/Point3DExtensions.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Math 7 | { 8 | using InnerEye.CreateDataset.Volumes; 9 | 10 | public static class Point3DExtensions 11 | { 12 | /// 13 | /// Gets whether the point has any component that is infinity. 14 | /// 15 | /// 16 | /// 17 | public static bool IsInfinity(this Point3D point) 18 | { 19 | return double.IsInfinity(point.X) || double.IsInfinity(point.Y) || double.IsInfinity(point.Z); 20 | } 21 | 22 | /// 23 | /// Gets whether the point has any component that is Not A Number (NaN). 24 | /// 25 | /// 26 | /// 27 | public static bool IsNaN(this Point3D point) 28 | { 29 | return double.IsNaN(point.X) || double.IsNaN(point.Y) || double.IsNaN(point.Z); 30 | } 31 | 32 | /// 33 | /// If true, all 3 components of the point are numbers that are not Infinity, and 34 | /// not NaN. 35 | /// 36 | /// 37 | /// 38 | public static bool IsValid(this Point3D point) 39 | { 40 | return !(point.IsInfinity() || point.IsNaN()); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | using System.Reflection; 7 | using System.Runtime.InteropServices; 8 | 9 | // General Information about an assembly is controlled through the following 10 | // set of attributes. Change these attribute values to modify the information 11 | // associated with an assembly. 12 | [assembly: AssemblyTitle("InnerEye.CreateDataset.Math")] 13 | [assembly: AssemblyDescription("")] 14 | [assembly: AssemblyConfiguration("")] 15 | [assembly: AssemblyCompany("")] 16 | [assembly: AssemblyProduct("InnerEye.CreateDataset.Math")] 17 | [assembly: AssemblyCopyright("Copyright © 2016")] 18 | [assembly: AssemblyTrademark("")] 19 | [assembly: AssemblyCulture("")] 20 | 21 | // Setting ComVisible to false makes the types in this assembly not visible 22 | // to COM components. If you need to access a type in this assembly from 23 | // COM, set the ComVisible attribute to true on that type. 24 | [assembly: ComVisible(false)] 25 | 26 | // The following GUID is for the ID of the typelib if this project is exposed to COM 27 | [assembly: Guid("d8e303da-8713-411d-a909-fe507f39a0ae")] 28 | 29 | // Version information for an assembly consists of the following four values: 30 | // 31 | // Major Version 32 | // Minor Version 33 | // Build Number 34 | // Revision 35 | // 36 | // You can specify all the values or you can default the Build and Revision Numbers 37 | // by using the '*' as shown below: 38 | // [assembly: AssemblyVersion("1.0.*")] 39 | [assembly: AssemblyVersion("1.0.0.0")] 40 | [assembly: AssemblyFileVersion("1.0.0.0")] 41 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math/VolumeExtensions/GenericResampling.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Math 7 | { 8 | using InnerEye.CreateDataset.Volumes; 9 | using System; 10 | using System.Threading.Tasks; 11 | 12 | public static class GenericResampling 13 | { 14 | private static T Nearest(this Volume3D input, Point3D pixel, T outsideValue) 15 | { 16 | return input.Nearest(pixel.X, pixel.Y, pixel.Z, outsideValue); 17 | } 18 | 19 | // Expects pixel coordinates. 20 | // antonsc: using a fixed default value for outside can lead to artefacts 21 | // https://innereye.visualstudio.com/InnerEye/_workitems/edit/2116 22 | private static T Nearest(this Volume3D input, double pixelX, double pixelY, double pixelZ, T outsideValue) 23 | { 24 | if (pixelX < -0.5 || pixelY < -0.5 || pixelZ < -0.5 25 | || pixelX >= input.DimX - 0.5 26 | || pixelY >= input.DimY - 0.5 27 | || pixelZ >= input.DimZ - 0.5) 28 | { 29 | return outsideValue; 30 | } 31 | 32 | return input[(int)(pixelX + 0.5), (int)(pixelY + 0.5), (int)(pixelZ + 0.5)]; 33 | } 34 | 35 | // https://innereye.visualstudio.com/InnerEye/_workitems/edit/2116 36 | public static Volume3D ResampleNearest(this Volume3D input, int dimX, int dimY, int dimZ, T outsideValue = default(T)) 37 | { 38 | double spacingX = input.SpacingX * (input.DimX - 1) / (dimX - 1); 39 | double spacingY = input.SpacingY * (input.DimY - 1) / (dimY - 1); 40 | double spacingZ = input.SpacingZ * (input.DimZ - 1) / (dimZ - 1); 41 | var output = new Volume3D(dimX, dimY, dimZ, spacingX, spacingY, spacingZ, input.Origin, input.Direction); 42 | ResampleImage(input, output, outsideValue, null); 43 | return output; 44 | } 45 | 46 | // https://innereye.visualstudio.com/InnerEye/_workitems/edit/2116 47 | public static void ResampleImage(Volume3D input, Volume3D output, T outsideValue, Func interpolationFunc) 48 | { 49 | int dimX = output.DimX; 50 | int dimY = output.DimY; 51 | int dimZ = output.DimZ; 52 | int dimXy = output.DimXY; 53 | 54 | double factorX = output.SpacingX / input.SpacingX; 55 | double factorY = output.SpacingY / input.SpacingY; 56 | double factorZ = output.SpacingZ / input.SpacingZ; 57 | 58 | var shift = input.Transform.PhysicalToPixel(output.Origin); 59 | 60 | Parallel.For(0, dimZ, z => 61 | { 62 | double inputZ = z * factorZ + shift.Z; 63 | int index = dimXy * z - 1; 64 | for (int y = 0; y < dimY; y++) 65 | { 66 | double inputY = y * factorY + shift.Y; 67 | for (int x = 0; x < dimX; x++) 68 | { 69 | double inputX = x * factorX + shift.X; 70 | if (interpolationFunc != null) 71 | { 72 | output[++index] = interpolationFunc(inputX, inputY, inputZ); 73 | } 74 | else 75 | { 76 | output[++index] = input.Nearest(inputX, inputY, inputZ, outsideValue); 77 | } 78 | } 79 | } 80 | }); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Math/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Runner/Program.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Runner 7 | { 8 | using System; 9 | using System.Net; 10 | using System.Threading; 11 | using CommandLine; 12 | using InnerEye.CreateDataset.Core; 13 | 14 | public static class Program 15 | { 16 | private static void Main(string[] args) 17 | { 18 | ThreadPool.SetMinThreads(100, 100); 19 | ServicePointManager.DefaultConnectionLimit = 100; 20 | 21 | Parser.Default.ParseArguments(args) 22 | .WithParsed(opts => RunTask(opts, DatasetAnalysisFromConvertedDataset.AnalyzeDataset)) 23 | .WithParsed(opts => 24 | { 25 | opts.RawCommandlineArguments = args; 26 | RunTask(opts, ConvertDicomToNifti.CreateDataset); 27 | }) 28 | .WithNotParsed(errs => 29 | { 30 | void action(CommandlineShared _) 31 | { 32 | foreach (var err in errs) 33 | { 34 | Console.Error.WriteLine(err.Tag); 35 | } 36 | } 37 | 38 | RunTask(null, action); 39 | Environment.Exit(-1); 40 | }); 41 | } 42 | 43 | private static void RunTask(T options, 44 | Action action) 45 | where T: CommandlineShared 46 | { 47 | if (options != null) 48 | { 49 | options.Validate(); 50 | } 51 | action(options); 52 | return; 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Runner/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | using System.Reflection; 7 | using System.Runtime.InteropServices; 8 | 9 | // General Information about an assembly is controlled through the following 10 | // set of attributes. Change these attribute values to modify the information 11 | // associated with an assembly. 12 | [assembly: AssemblyTitle("InnerEye.CreateDataset.Runner")] 13 | [assembly: AssemblyDescription("")] 14 | [assembly: AssemblyConfiguration("")] 15 | [assembly: AssemblyCompany("")] 16 | [assembly: AssemblyProduct("InnerEye.CreateDataset.Runner")] 17 | [assembly: AssemblyCopyright("Copyright © 2016")] 18 | [assembly: AssemblyTrademark("")] 19 | [assembly: AssemblyCulture("")] 20 | 21 | // Setting ComVisible to false makes the types in this assembly not visible 22 | // to COM components. If you need to access a type in this assembly from 23 | // COM, set the ComVisible attribute to true on that type. 24 | [assembly: ComVisible(false)] 25 | 26 | // The following GUID is for the ID of the typelib if this project is exposed to COM 27 | [assembly: Guid("50c74466-b659-4209-baec-aeb9a966a2c3")] 28 | 29 | // Version information for an assembly consists of the following four values: 30 | // 31 | // Major Version 32 | // Minor Version 33 | // Build Number 34 | // Revision 35 | // 36 | // You can specify all the values or you can default the Build and Revision Numbers 37 | // by using the '*' as shown below: 38 | // [assembly: AssemblyVersion("1.0.*")] 39 | [assembly: AssemblyVersion("1.0.0.0")] 40 | [assembly: AssemblyFileVersion("1.0.0.0")] 41 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Runner/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Volumes/Contour/Contour.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Volumes 7 | { 8 | using System; 9 | using System.Windows; 10 | using System.Linq; 11 | 12 | [Obsolete("All contour-related code should move to using the new classes in the InnerEye.CreateDataset.Contours namespace.")] 13 | [Serializable] 14 | public struct Contour : IEquatable 15 | { 16 | public Contour(Point[] contourPoints, int regionAreaPixels) 17 | { 18 | ContourPoints = contourPoints; 19 | RegionAreaPixels = regionAreaPixels; 20 | } 21 | 22 | public Point[] ContourPoints { get; } 23 | 24 | public int RegionAreaPixels { get; } 25 | 26 | public bool Equals(Contour other) 27 | { 28 | if (ContourPoints.Length != other.ContourPoints?.Length) 29 | { 30 | return false; 31 | } 32 | 33 | return !ContourPoints.Where((t, i) => t != other.ContourPoints[i]).Any(); 34 | } 35 | 36 | public override bool Equals(object obj) 37 | { 38 | return obj != null && Equals((Contour)obj); 39 | } 40 | 41 | public static bool operator ==(Contour c1, Contour c2) 42 | { 43 | return c1.Equals(c2); 44 | } 45 | 46 | public static bool operator !=(Contour c1, Contour c2) 47 | { 48 | return !c1.Equals(c2); 49 | } 50 | 51 | public override int GetHashCode() 52 | { 53 | unchecked 54 | { 55 | return ContourPoints.Aggregate(19, (current, foo) => current * 31 + foo.GetHashCode()); 56 | } 57 | } 58 | 59 | public object ToList() 60 | { 61 | throw new NotImplementedException(); 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Volumes/Contour/ContourStats.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Volumes 7 | { 8 | using System; 9 | 10 | [Obsolete("All contour-related code should move to using the new classes in the InnerEye.CreateDataset.Contours namespace.")] 11 | public struct ContourStats 12 | { 13 | public ContourStats(double sizeIncc, double mean, double standardDeviation) 14 | { 15 | SizeIncc = sizeIncc; 16 | Mean = mean; 17 | StandardDeviation = standardDeviation; 18 | } 19 | 20 | // cm^3 or cc 21 | public double SizeIncc { get; } 22 | 23 | public double Mean { get; } 24 | 25 | public double StandardDeviation { get; } 26 | } 27 | 28 | [Obsolete("All contour-related code should move to using the new classes in the InnerEye.CreateDataset.Contours namespace.")] 29 | public static class ContourStatsExtensions 30 | { 31 | public static ContourStats CalculateContourStats(ReadOnlyVolume3D originalVolume, Volume3D contourVolume, byte foreground = 1) 32 | { 33 | double numberOfContourPoints = 0; 34 | long sum = 0; 35 | ulong sumSqMinusMean = 0; 36 | 37 | for (int i = 0; i < originalVolume.Length; i++) 38 | { 39 | if (contourVolume[i] == foreground) 40 | { 41 | numberOfContourPoints++; 42 | sum += originalVolume[i]; 43 | } 44 | } 45 | 46 | var mean = numberOfContourPoints == 0 ? 0d : sum / numberOfContourPoints; 47 | 48 | for (int i = 0; i < originalVolume.Length; i++) 49 | { 50 | if (contourVolume[i] == foreground) 51 | { 52 | var d = originalVolume[i] - mean; 53 | sumSqMinusMean += (ulong)(d * d); 54 | } 55 | } 56 | 57 | var volumeSizeInmm = numberOfContourPoints * originalVolume.VoxelVolume / 1000d; 58 | var standardDeviation = mean == 0 ? 0 : Math.Sqrt(sumSqMinusMean / numberOfContourPoints); 59 | 60 | return new ContourStats(volumeSizeInmm, mean, standardDeviation); 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Volumes/Contour/FillPolygonHelpers.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/InnerEye-CreateDataset/8561e8cedc5f1aeb4af43c86a7796a1fe12c1892/Source/projects/InnerEye.CreateDataset.Volumes/Contour/FillPolygonHelpers.cs -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Volumes/Matrix4.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Volumes 7 | { 8 | using System; 9 | 10 | public class Matrix4 11 | { 12 | public Matrix4() 13 | { 14 | Data = new double[16]; 15 | } 16 | 17 | public Matrix4(Matrix4 matrix) 18 | { 19 | Data = new double[16]; 20 | Array.Copy(matrix.Data, this.Data, this.Data.Length); 21 | } 22 | 23 | public double this[int row, int column] 24 | { 25 | get { return Data[row + column * 4]; } 26 | set { Data[row + column * 4] = value; } 27 | } 28 | 29 | public double[] Data { get; } 30 | 31 | public void Zero() 32 | { 33 | for (var i = 0; i < 16; i++) 34 | { 35 | Data[i] = 0; 36 | } 37 | } 38 | 39 | public void Identity() 40 | { 41 | for (var i = 0; i < 16; i++) 42 | { 43 | Data[i] = 0; 44 | } 45 | 46 | Data[0] = 1; 47 | Data[5] = 1; 48 | Data[10] = 1; 49 | Data[15] = 1; 50 | } 51 | 52 | public static Matrix4 operator *(Matrix4 a, Matrix4 b) 53 | { 54 | var result = new Matrix4(); 55 | 56 | for (var i = 0; i < 4; i++) 57 | { 58 | result.Data[i * 4 + 0] = a.Data[0] * b.Data[i * 4 + 0] + a.Data[4] * b.Data[i * 4 + 1] + a.Data[8] * b.Data[i * 4 + 2] + a.Data[12] * b.Data[i * 4 + 3]; 59 | result.Data[i * 4 + 1] = a.Data[1] * b.Data[i * 4 + 0] + a.Data[5] * b.Data[i * 4 + 1] + a.Data[9] * b.Data[i * 4 + 2] + a.Data[13] * b.Data[i * 4 + 3]; 60 | result.Data[i * 4 + 2] = a.Data[2] * b.Data[i * 4 + 0] + a.Data[6] * b.Data[i * 4 + 1] + a.Data[10] * b.Data[i * 4 + 2] + a.Data[14] * b.Data[i * 4 + 3]; 61 | result.Data[i * 4 + 3] = a.Data[3] * b.Data[i * 4 + 0] + a.Data[7] * b.Data[i * 4 + 1] + a.Data[11] * b.Data[i * 4 + 2] + a.Data[15] * b.Data[i * 4 + 3]; 62 | } 63 | 64 | return result; 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Volumes/MinMax.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Volumes 7 | { 8 | /// 9 | /// Stores a tuple of (minimum, maximum). 10 | /// 11 | /// 12 | public struct MinMax 13 | { 14 | public T Minimum { get; set; } 15 | 16 | public T Maximum { get; set; } 17 | } 18 | 19 | public static class MinMax 20 | { 21 | public static MinMax Create(T min, T max) 22 | { 23 | return new MinMax { Minimum = min, Maximum = max }; 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Volumes/ModelConstants.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Volumes 7 | { 8 | public class ModelConstants 9 | { 10 | /// 11 | /// The voxel value in a binary mask that represents foreground. 12 | /// 13 | public const byte MaskForegroundIntensity = 1; 14 | 15 | /// 16 | /// The voxel value in a binary mask that represents background. 17 | /// 18 | public const byte MaskBackgroundIntensity = 0; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Volumes/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | using System.Reflection; 7 | using System.Runtime.InteropServices; 8 | 9 | // General Information about an assembly is controlled through the following 10 | // set of attributes. Change these attribute values to modify the information 11 | // associated with an assembly. 12 | [assembly: AssemblyTitle("InnerEye.CreateDataset.Volumes")] 13 | [assembly: AssemblyDescription("")] 14 | [assembly: AssemblyConfiguration("")] 15 | [assembly: AssemblyCompany("")] 16 | [assembly: AssemblyProduct("InnerEye.CreateDataset.Volumes")] 17 | [assembly: AssemblyCopyright("Copyright © 2016")] 18 | [assembly: AssemblyTrademark("")] 19 | [assembly: AssemblyCulture("")] 20 | 21 | // Setting ComVisible to false makes the types in this assembly not visible 22 | // to COM components. If you need to access a type in this assembly from 23 | // COM, set the ComVisible attribute to true on that type. 24 | [assembly: ComVisible(false)] 25 | 26 | // The following GUID is for the ID of the typelib if this project is exposed to COM 27 | [assembly: Guid("12416238-4311-4d15-a2d9-4f3ed7771244")] 28 | 29 | // Version information for an assembly consists of the following four values: 30 | // 31 | // Major Version 32 | // Minor Version 33 | // Build Number 34 | // Revision 35 | // 36 | // You can specify all the values or you can default the Build and Revision Numbers 37 | // by using the '*' as shown below: 38 | // [assembly: AssemblyVersion("1.0.*")] 39 | [assembly: AssemblyVersion("1.0.0.0")] 40 | [assembly: AssemblyFileVersion("1.0.0.0")] 41 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Volumes/ReadOnlyVolume2D.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Volumes 7 | { 8 | using System; 9 | 10 | /// 11 | /// This class wraps the Volume2D so it cannot be written to the array. No data is copied or duplicated 12 | /// 13 | /// 14 | public class ReadOnlyVolume2D : Volume2D 15 | { 16 | public ReadOnlyVolume2D(Volume2D volume2d) 17 | : base(volume2d.Array, volume2d.DimX, volume2d.DimY, volume2d.SpacingX, volume2d.SpacingY, volume2d.Origin, volume2d.Direction) 18 | { 19 | } 20 | 21 | public new T this[int index] 22 | { 23 | get { return base[index]; } 24 | 25 | set { throw new InvalidOperationException($"{index} {value}"); } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Volumes/ReadOnlyVolume3D.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Volumes 7 | { 8 | using System; 9 | /// 10 | /// This class wraps the Volume3D so it cannot be written to the array. No data is copied or duplicated 11 | /// 12 | /// 13 | public class ReadOnlyVolume3D : Volume3D 14 | { 15 | public ReadOnlyVolume3D(Volume3D volume3D) 16 | : base(volume3D.Array, volume3D.DimX, volume3D.DimY, volume3D.DimZ, volume3D.SpacingX, volume3D.SpacingY, volume3D.SpacingZ, volume3D.Origin, volume3D.Direction) 17 | { 18 | } 19 | 20 | public new T this[int index] 21 | { 22 | get { return base[index]; } 23 | 24 | set { throw new InvalidOperationException($"{index} {value}"); } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Volumes/Region2D.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Volumes 7 | { 8 | public class Region2D 9 | { 10 | public Region2D(T minimumX, T minimumY, T maximumX, T maximumY) 11 | { 12 | MinimumX = minimumX; 13 | MinimumY = minimumY; 14 | MaximumX = maximumX; 15 | MaximumY = maximumY; 16 | } 17 | 18 | public T MinimumX { get; } 19 | 20 | public T MinimumY { get; } 21 | 22 | public T MaximumX { get; } 23 | 24 | public T MaximumY { get; } 25 | } 26 | } -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Volumes/SliceType.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Volumes 7 | { 8 | /// 9 | /// The slice type. 10 | /// More info: https://en.wikipedia.org/wiki/Anatomical_plane 11 | /// 12 | public enum SliceType 13 | { 14 | /// 15 | /// The axial XY plane. 16 | /// 17 | Axial, 18 | 19 | /// 20 | /// The coronal XZ plane. 21 | /// 22 | Coronal, 23 | 24 | /// 25 | /// The sagittal YZ plane. 26 | /// 27 | Sagittal, 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Volumes/SmoothingType.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Volumes 7 | { 8 | using System; 9 | 10 | [Obsolete("All contour-related code should move to using the new classes in the InnerEye.CreateDataset.Contours namespace.")] 11 | public enum SmoothingType 12 | { 13 | None, 14 | 15 | Small, 16 | 17 | Medium, 18 | 19 | Large 20 | } 21 | } -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Volumes/Transform3.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Volumes 7 | { 8 | using System; 9 | 10 | /// 11 | /// Models a 3D affine transformation. Modelled as Basis.x + Origin. Where Basis is a 3x3 matrix and Origin a Point3D 12 | /// 13 | public class Transform3 14 | { 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// The basis. 19 | /// The origin. 20 | /// basis 21 | public Transform3(Matrix3 basis, Point3D origin) 22 | { 23 | Basis = basis ?? throw new ArgumentNullException(nameof(basis)); 24 | Origin = origin; 25 | } 26 | 27 | /// 28 | /// Returns the identity transform 29 | /// 30 | /// The Transform3 identity. 31 | public static Transform3 Identity() 32 | { 33 | return new Transform3(Matrix3.CreateIdentity(), Point3D.Zero()); 34 | } 35 | 36 | /// 37 | /// Gets the basis. 38 | /// 39 | /// 40 | /// The basis. 41 | /// 42 | public Matrix3 Basis { get; } 43 | 44 | /// 45 | /// Gets or sets the origin. 46 | /// 47 | /// 48 | /// The origin. 49 | /// 50 | public Point3D Origin { get; set; } 51 | 52 | /// 53 | /// Transforms the given Point3D 54 | /// 55 | /// The transform. 56 | /// The point. 57 | public static Point3D operator *(Transform3 transform, Point3D point) 58 | { 59 | return transform.Basis * point + transform.Origin; 60 | } 61 | 62 | /// 63 | /// Compute the composite transform a*b which is the operation of first performing b then a. 64 | /// (a*b)x = a(b(x)), a*b*x = a*(b*x) 65 | /// 66 | /// a. 67 | /// The b. 68 | /// 69 | /// The result of the operator. 70 | /// 71 | public static Transform3 operator *(Transform3 a, Transform3 b) 72 | { 73 | return new Transform3(a.Basis * b.Basis, a * b.Origin); 74 | } 75 | 76 | /// 77 | /// Transforms the specified Point3D. 78 | /// 79 | /// The Point3D. 80 | /// The transformed Point3D. 81 | public Point3D Transform(Point3D point) 82 | { 83 | return this * point; 84 | } 85 | 86 | /// 87 | /// Computes the inverse of this transform. 88 | /// 89 | /// if Basis.Determinant == 0 90 | /// The inverse of this instance. 91 | public Transform3 Inverse() 92 | { 93 | var basisInverse = Basis.Inverse(); 94 | return new Transform3(basisInverse, -(basisInverse * Origin)); 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Volumes/Volume.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace InnerEye.CreateDataset.Volumes 7 | { 8 | using System; 9 | 10 | [Serializable] 11 | public abstract class Volume 12 | { 13 | private readonly T[] _array; 14 | 15 | protected Volume(T[] array, int dimensions) 16 | { 17 | _array = array; 18 | Dimensions = dimensions; 19 | } 20 | 21 | /// 22 | /// Gets the underlying array for this Volume. 23 | /// 24 | public T[] Array => _array; 25 | 26 | /// 27 | /// Gets the number of dimensions for this volume. 28 | /// Example: Volume2D will have 2 dimensions. 29 | /// 30 | public int Dimensions { get; } 31 | 32 | /// 33 | /// Gets the length of the array that holds all voxels. 34 | /// 35 | public int Length => _array.Length; 36 | 37 | public T this[int index] 38 | { 39 | get { return _array[index]; } 40 | 41 | set { _array[index] = value; } 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /Source/projects/InnerEye.CreateDataset.Volumes/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /Source/projects/MedLib.IO.Tests/AssemblyInitialize.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | using System.Diagnostics; 7 | using NUnit.Framework; 8 | 9 | /// 10 | /// Contains code that is called by the test runner at assembly loading time. 11 | /// This class must not be in a namespace for NUnit. 12 | /// https://stackoverflow.com/questions/3188380/one-time-initialization-for-nunit 13 | /// 14 | [SetUpFixture] 15 | public class AssemblyInitialize 16 | { 17 | [OneTimeSetUp] 18 | public static void SetCurrentDirectory() 19 | { 20 | // This is necessary because NUnit3 sets current directory to c:\windows\system32, 21 | // but we use many paths that are relative to the build output directory. 22 | System.Environment.CurrentDirectory = TestContext.CurrentContext.TestDirectory; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Source/projects/MedLib.IO.Tests/DicomDatsetExtensionsTests.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace MedLib.IO.Tests 7 | { 8 | using System; 9 | using System.IO; 10 | using System.Linq; 11 | using System.Threading.Tasks; 12 | using Dicom; 13 | using Dicom.Imaging; 14 | using Dicom.IO.Buffer; 15 | 16 | using InnerEye.CreateDataset.Volumes; 17 | 18 | using NUnit.Framework; 19 | 20 | [TestFixture] 21 | public class DicomDatsetExtensionsTests 22 | { 23 | [Description("Tests all the Dicom dataset extensions.")] 24 | [Test] 25 | public async Task TestAllExtensions() 26 | { 27 | var prostateFolder = TestData.GetFullImagesPath("sample_dicom"); 28 | var files = Directory.EnumerateFiles(prostateFolder).ToList(); 29 | 30 | var dicomFiles = new DicomFile[files.Count]; 31 | 32 | for (var i = 0; i < files.Count; i++) 33 | { 34 | dicomFiles[i] = await DicomFile.OpenAsync(files[i]); 35 | } 36 | 37 | var (width, height) = dicomFiles[0].Dataset.GetSliceSize(); 38 | var origin = dicomFiles[0].Dataset.GetOrigin(); 39 | var (spacingX, spacingY) = dicomFiles[0].Dataset.GetPixelSpacings(); 40 | var direction = dicomFiles[0].Dataset.GetDirectionalMatrix(); 41 | var rescaleIntercept = dicomFiles[0].Dataset.GetRescaleIntercept(); 42 | var rescaleSlope = dicomFiles[0].Dataset.GetRescaleSlope(); 43 | var isSignedPixelRepresentation = dicomFiles[0].Dataset.IsSignedPixelRepresentation(); 44 | var highBit = dicomFiles[0].Dataset.GetHighBit(); 45 | var sopClass = dicomFiles[0].Dataset.GetSopClass(); 46 | 47 | Assert.AreEqual(512, width); 48 | Assert.AreEqual(512, height); 49 | 50 | Assert.AreEqual(-250, origin.X); 51 | Assert.AreEqual(-250, origin.Y); 52 | Assert.AreEqual(125.5, origin.Z); 53 | 54 | Assert.AreEqual(0.9765625, spacingX); 55 | Assert.AreEqual(0.9765625, spacingY); 56 | 57 | Assert.AreEqual(1, direction.Data[0]); 58 | Assert.AreEqual(0, direction.Data[1]); 59 | Assert.AreEqual(0, direction.Data[2]); 60 | Assert.AreEqual(0, direction.Data[3]); 61 | Assert.AreEqual(1, direction.Data[4]); 62 | Assert.AreEqual(0, direction.Data[5]); 63 | Assert.AreEqual(0, direction.Data[6]); 64 | Assert.AreEqual(0, direction.Data[7]); 65 | Assert.AreEqual(1, direction.Data[8]); 66 | 67 | Assert.AreEqual(0, rescaleIntercept); 68 | Assert.AreEqual(1, rescaleSlope); 69 | Assert.AreEqual(true, isSignedPixelRepresentation); 70 | Assert.AreEqual(15, highBit); 71 | Assert.AreEqual(DicomUID.CTImageStorage, sopClass); 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /Source/projects/MedLib.IO.Tests/DicomSeriesReaderTests.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace MedLib.IO.Tests 7 | { 8 | using System.IO; 9 | using System.Linq; 10 | using System.Threading.Tasks; 11 | 12 | using Dicom; 13 | 14 | using MedLib.IO.Readers; 15 | 16 | using NUnit.Framework; 17 | 18 | [Category("ReaderTests")] 19 | [TestFixture] 20 | public class DicomSeriesReaderTests 21 | { 22 | [Description("Tests opening an image from a collection of DICOM datasets including validating the input and extracting voxels.")] 23 | [Test] 24 | public async Task TestImageOpening() 25 | { 26 | var prostateFolder = TestData.GetFullImagesPath("sample_dicom"); 27 | var files = Directory.EnumerateFiles(prostateFolder) 28 | .Where(x => !x.EndsWith("rtstruct_mod.dcm")).ToList(); 29 | 30 | var dicomFiles = new DicomFile[files.Count]; 31 | 32 | for (var i = 0; i < files.Count; i++) 33 | { 34 | dicomFiles[i] = await DicomFile.OpenAsync(files[i]); 35 | } 36 | 37 | var volume = DicomSeriesReader.BuildVolume( 38 | dicomFiles.Select(x => x.Dataset), 39 | new NonStrictGeometricAcceptanceTest(string.Empty, string.Empty), true); 40 | 41 | Assert.AreEqual(512, volume.DimX); 42 | Assert.AreEqual(262144, volume.DimXY); 43 | Assert.AreEqual(512, volume.DimY); 44 | Assert.AreEqual(2, volume.DimZ); 45 | Assert.AreEqual(3, volume.Dimensions); 46 | Assert.AreEqual(524288, volume.Length); 47 | Assert.AreEqual(-250d, volume.Origin.X); 48 | Assert.AreEqual(-250d, volume.Origin.Y); 49 | Assert.AreEqual(125.5d, volume.Origin.Z); 50 | Assert.AreEqual(0.9765625, volume.SpacingX); 51 | Assert.AreEqual(0.9765625, volume.SpacingY); 52 | Assert.AreEqual(2.86102294921875, volume.VoxelVolume); 53 | Assert.AreEqual(-1000, volume.Array[3453]); 54 | Assert.AreEqual(-1000, volume.Array[8453]); 55 | Assert.AreEqual(-1000, volume.Array[10453]); 56 | Assert.AreEqual(-1000, volume.Array[100453]); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /Source/projects/MedLib.IO.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | using System.Reflection; 7 | using System.Runtime.CompilerServices; 8 | using System.Runtime.InteropServices; 9 | 10 | // General Information about an assembly is controlled through the following 11 | // set of attributes. Change these attribute values to modify the information 12 | // associated with an assembly. 13 | [assembly: AssemblyTitle("MedLib.IO.Tests")] 14 | [assembly: AssemblyDescription("")] 15 | [assembly: AssemblyConfiguration("")] 16 | [assembly: AssemblyCompany("")] 17 | [assembly: AssemblyProduct("MedLib.IO.Tests")] 18 | [assembly: AssemblyCopyright("Copyright © 2016")] 19 | [assembly: AssemblyTrademark("")] 20 | [assembly: AssemblyCulture("")] 21 | 22 | // Setting ComVisible to false makes the types in this assembly not visible 23 | // to COM components. If you need to access a type in this assembly from 24 | // COM, set the ComVisible attribute to true on that type. 25 | [assembly: ComVisible(false)] 26 | 27 | // The following GUID is for the ID of the typelib if this project is exposed to COM 28 | [assembly: Guid("6bdefc0b-782b-41ec-aaee-e730c0d25faa")] 29 | 30 | // Version information for an assembly consists of the following four values: 31 | // 32 | // Major Version 33 | // Minor Version 34 | // Build Number 35 | // Revision 36 | // 37 | // You can specify all the values or you can default the Build and Revision Numbers 38 | // by using the '*' as shown below: 39 | // [assembly: AssemblyVersion("1.0.*")] 40 | [assembly: AssemblyVersion("1.0.0.0")] 41 | [assembly: AssemblyFileVersion("1.0.0.0")] 42 | -------------------------------------------------------------------------------- /Source/projects/MedLib.IO.Tests/TestData.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace MedLib.IO.Tests 7 | { 8 | using System.IO; 9 | using NUnit.Framework; 10 | 11 | /// 12 | /// Contains helper functions to get access to the test data. 13 | /// 14 | public static class TestData 15 | { 16 | /// 17 | /// Given a relative path inside of the Images submodule, create the full path to that file. 18 | /// This assumes that the test assembly is run in the location where the build places it, 19 | /// and that the full source tree is available. 20 | /// 21 | /// 22 | /// 23 | public static string GetFullImagesPath(string relativePath) 24 | { 25 | return Path.GetFullPath(Path.Combine(TestContext.CurrentContext.TestDirectory, @".\TestData", relativePath)); 26 | } 27 | 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Source/projects/MedLib.IO.Tests/TestData/sample_dicom/1_mod.dcm: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:a62287587daba0f9e59c12123c185569be1208e82e9a0421ee299d6d6ca07d28 3 | size 524934 4 | -------------------------------------------------------------------------------- /Source/projects/MedLib.IO.Tests/TestData/sample_dicom/2_mod.dcm: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:5fab6a080eb9b3634969bebf6e8cae83e64ded7b158e0e3953b23c5abfb94f8a 3 | size 524934 4 | -------------------------------------------------------------------------------- /Source/projects/MedLib.IO.Tests/TestData/sample_dicom/rtstruct_mod.dcm: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:9537e5afbec8b6c3da6ad23b2920136b60a6e92c906ea826b8401bbb3124fe66 3 | size 15130 4 | -------------------------------------------------------------------------------- /Source/projects/MedLib.IO.Tests/TestData/vol_int16.nii.gz: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:8114a7cd0caf9c2c4ca2e3442fd0192f2b29ed035f4b5fd4901ead6e69588caa 3 | size 510 4 | -------------------------------------------------------------------------------- /Source/projects/MedLib.IO.Tests/TestData/vol_uint16.nii.gz: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:7bd8612c4b29309b95278a7955b2d639d9e837c153d78c55d1adbc51b8550dc0 3 | size 3257 4 | -------------------------------------------------------------------------------- /Source/projects/MedLib.IO.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/ContourRenderingInformation.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace MedLib.IO 7 | { 8 | using System; 9 | using InnerEye.CreateDataset.Contours; 10 | 11 | /// 12 | /// Contains a segmentation as a contour, and information about how it should be rendered within a Dicom file. 13 | /// 14 | public class ContourRenderingInformation 15 | { 16 | /// 17 | /// Creates a new instance of the class, setting all properties that the class holds. 18 | /// 19 | /// The name of the anatomical structure that is represented by the contour. 20 | /// The color that should be used to render the contour. 21 | /// The contours broken down by slice of the scan. 22 | /// The contour name or mask was null. 23 | public ContourRenderingInformation(string name, RGBValue color, ContoursPerSlice contour) 24 | { 25 | Name = name ?? throw new ArgumentNullException(nameof(name)); 26 | Color = color; 27 | Contour = contour ?? throw new ArgumentNullException(nameof(contour)); 28 | } 29 | 30 | /// 31 | /// Creates a new instance of the class, from a binary mask. The contour is extracted from the mask 32 | /// using the default settings: Background 0, foreground 1, axial slices. 33 | /// 34 | /// The name of the anatomical structure that is represented by the contour. 35 | /// The color that should be used to render the contour. 36 | /// The binary mask that represents the anatomical structure. 37 | /// The contour name or mask was null. 38 | public ContourRenderingInformation(string name, RGBValue color, InnerEye.CreateDataset.Volumes.Volume3D mask) 39 | { 40 | Name = name ?? throw new ArgumentNullException(nameof(name)); 41 | Color = color; 42 | mask = mask ?? throw new ArgumentNullException(nameof(mask)); 43 | Contour = ExtractContours.ContoursWithHolesPerSlice(mask); 44 | } 45 | 46 | /// 47 | /// The name of the anatomical structure that is represented by the mask. 48 | /// 49 | public string Name { get; } 50 | 51 | /// 52 | /// The color that should be used to render the anatomical structure. 53 | /// 54 | public RGBValue Color { get; } 55 | 56 | /// 57 | /// The segmentation as a contour by slice. 58 | /// 59 | public ContoursPerSlice Contour { get; } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/DicomRtHelpers.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace MedLib.IO 7 | { 8 | using System; 9 | 10 | using Dicom; 11 | 12 | using MedLib.IO.Models.DicomRt; 13 | using MedLib.IO.Extensions; 14 | 15 | using InnerEye.CreateDataset.Volumes; 16 | 17 | /// 18 | /// Helpers for Dicom Rt files 19 | /// 20 | public static class DicomRtHelpers 21 | { 22 | /// 23 | /// Converts a Dicom file to a radiotherapy structure set. 24 | /// 25 | /// The structure set dicom file. 26 | /// The dicom to data transform. 27 | /// The radiotherapy structure set. 28 | /// If the Dicom file or Dicom dataset is null. 29 | /// If the file is not a structure set file. 30 | public static RadiotherapyStruct DicomFileToRadiotherapyStruct(DicomFile dicomFile, Transform3 dicomToDataTransform) 31 | { 32 | if (dicomFile?.Dataset == null) 33 | { 34 | throw new ArgumentNullException(nameof(dicomFile)); 35 | } 36 | 37 | if (!dicomFile.Dataset.IsRTStructure()) 38 | { 39 | throw new ArgumentException($"This file is not a structure set file. File: {dicomFile?.File?.Name}"); 40 | } 41 | 42 | return RtStructReader.LoadContours(dicomFile.Dataset, dicomToDataTransform, warningsAsErrors: false).Item1; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/Extensions/DicomConstants.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace MedLib.IO.Extensions 7 | { 8 | public static class DicomConstants 9 | { 10 | public const string CTModality = "CT"; 11 | public const string MRModality = "MR"; 12 | } 13 | } -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/Models/DICOMRT/RadiotherapyContour.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace MedLib.IO.Models.DicomRt 7 | { 8 | using MedLib.IO.RT; 9 | using InnerEye.CreateDataset.Contours; 10 | 11 | /// 12 | /// A RadiotherapyContour is a set of contours forming a single structure within 13 | /// an RT Structure set. This class brings together: 14 | /// * Contour information defining the geometry of the structure 15 | /// * An observation of that structure 16 | /// * Names and labels associated with the structure. 17 | /// * A Derived copy of the contours in image space. 18 | /// 19 | public class RadiotherapyContour 20 | { 21 | /// 22 | /// The set of contours forming this structure 23 | /// 24 | public DicomRTContour DicomRtContour { get; } 25 | 26 | /// 27 | /// Information about this structure 28 | /// 29 | public DicomRTStructureSetROI StructureSetRoi { get; } 30 | 31 | /// 32 | /// An Observation about this structure. Note that in the DICOM RT-Struct model 33 | /// a structure can have more than 1 observation - this is not supported. 34 | /// 35 | public DicomRTObservation DicomRtObservation { get; } 36 | 37 | /// 38 | /// A derived version of the DicomRTContours transformed into the coordinate space of a volume3D. 39 | /// 40 | public ContoursPerSlice Contours { get; set; } 41 | 42 | public RadiotherapyContour(DicomRTContour dicomRtContour, DicomRTStructureSetROI structure, DicomRTObservation dicomRtObservation) 43 | { 44 | DicomRtContour = dicomRtContour; 45 | StructureSetRoi = structure; 46 | DicomRtObservation = dicomRtObservation; 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/Models/Hdf5Object.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace MedLib.IO.Models 7 | { 8 | using InnerEye.CreateDataset.Volumes; 9 | 10 | public class Hdf5Object 11 | { 12 | public Hdf5Object(MedicalVolume volume, Volume3D segmentation) 13 | { 14 | 15 | Volume = volume; 16 | Segmentation = segmentation; 17 | } 18 | public MedicalVolume Volume {get; set;} 19 | public Volume3D Segmentation { get; set; } 20 | 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/Models/MedicalVolume.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace MedLib.IO.Models 7 | { 8 | using DicomRt; 9 | using Readers; 10 | using InnerEye.CreateDataset.Volumes; 11 | using System.Diagnostics; 12 | using System.Collections.Generic; 13 | using Dicom; 14 | 15 | public class MedicalVolume 16 | { 17 | /// 18 | /// True if this MedicalVolume was generated from DICOM images. 19 | /// 20 | public bool IsDicom => Identifiers != null & Identifiers.Count > 0; 21 | 22 | /// 25 | public bool IsCT => !IsDicom || (IsDicom && Identifiers[0].Image.SopCommon.SopClassUid == DicomUID.CTImageStorage.UID); 26 | 27 | /// 28 | /// The 3D volume 29 | /// 30 | public Volume3D Volume { get; } 31 | 32 | /// 33 | /// Paths of all the files that formed the Volume 34 | /// 35 | public IReadOnlyList FilePaths { get; } 36 | 37 | /// 38 | /// Dicom information for all the files that formed the volume (or empty in the case of nifti) 39 | /// 40 | public IReadOnlyList Identifiers { get; } 41 | 42 | /// 43 | /// Any radiotherapy struct associated with the Volume. This is never null. 44 | /// 45 | public RadiotherapyStruct Struct { get; set; } 46 | 47 | /// 48 | /// Construct MedicalVolume from Dicom images 49 | /// 50 | /// 51 | /// 52 | /// 53 | /// 54 | public MedicalVolume( 55 | Volume3D volume, 56 | IReadOnlyList identifiers, 57 | IReadOnlyList filePaths, 58 | RadiotherapyStruct rtStruct) 59 | { 60 | Debug.Assert(volume != null); 61 | Debug.Assert(identifiers != null); 62 | Debug.Assert(filePaths != null); 63 | Debug.Assert(rtStruct != null); 64 | 65 | Identifiers = identifiers; 66 | Volume = volume; 67 | FilePaths = filePaths; 68 | Struct = rtStruct; 69 | } 70 | 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | using System.Reflection; 7 | using System.Runtime.CompilerServices; 8 | using System.Runtime.InteropServices; 9 | 10 | // General Information about an assembly is controlled through the following 11 | // set of attributes. Change these attribute values to modify the information 12 | // associated with an assembly. 13 | [assembly: AssemblyTitle("MedLib.IO")] 14 | [assembly: AssemblyDescription("")] 15 | [assembly: AssemblyConfiguration("")] 16 | [assembly: AssemblyCompany("")] 17 | [assembly: AssemblyProduct("MedLib.IO")] 18 | [assembly: AssemblyCopyright("Copyright © 2016")] 19 | [assembly: AssemblyTrademark("")] 20 | [assembly: AssemblyCulture("")] 21 | 22 | // Setting ComVisible to false makes the types in this assembly not visible 23 | // to COM components. If you need to access a type in this assembly from 24 | // COM, set the ComVisible attribute to true on that type. 25 | [assembly: ComVisible(false)] 26 | 27 | // The following GUID is for the ID of the typelib if this project is exposed to COM 28 | [assembly: Guid("97046b3e-6de6-4a84-946d-17ba956411dd")] 29 | 30 | // Version information for an assembly consists of the following four values: 31 | // 32 | // Major Version 33 | // Minor Version 34 | // Build Number 35 | // Revision 36 | // 37 | // You can specify all the values or you can default the Build and Revision Numbers 38 | // by using the '*' as shown below: 39 | // [assembly: AssemblyVersion("1.0.*")] 40 | [assembly: AssemblyVersion("1.0.0.0")] 41 | [assembly: AssemblyFileVersion("1.0.0.0")] 42 | -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/RGBValue.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace MedLib.IO 7 | { 8 | using System; 9 | 10 | /// 11 | /// Stores a color as a (Red, Green, Blue) tuple 12 | /// 13 | [Serializable] 14 | public struct RGBValue 15 | { 16 | /// 17 | /// The Red component of the color. 18 | /// 19 | public byte R { get; set; } 20 | 21 | /// 22 | /// The Green component of the color. 23 | /// 24 | public byte G { get; set; } 25 | 26 | /// 27 | /// The Blue component of the color. 28 | /// 29 | public byte B { get; set; } 30 | 31 | /// 32 | /// Creates a new instance of the class from the (R, G, B) values. 33 | /// 34 | /// 35 | /// 36 | /// 37 | public RGBValue(byte red, byte green, byte blue) 38 | { 39 | R = red; 40 | G = green; 41 | B = blue; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/RT/DicomEquipment.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace MedLib.IO.RT 7 | { 8 | using Dicom; 9 | using Extensions; 10 | 11 | /// 12 | /// Encodes part of the DICOM Equipment module 13 | /// http://dicom.nema.org/medical/Dicom/current/output/chtml/part03/sect_C.7.5.html 14 | /// 15 | public class DicomEquipment 16 | { 17 | /// 18 | /// Type 2, Long String (64 chars) 19 | /// 20 | public string Manufacturer { get; set; } 21 | 22 | /// 23 | /// Type 3 Long string 24 | /// 25 | public string SoftwareVersions { get; set; } 26 | 27 | /// 28 | /// Device name 29 | /// 30 | public string Device { get; set; } 31 | 32 | private DicomEquipment(string manufacturer, string softwareVersions) 33 | { 34 | Manufacturer = manufacturer; 35 | SoftwareVersions = softwareVersions; 36 | 37 | } 38 | 39 | public DicomEquipment(string manufacturer, string device, string softwareVersions) 40 | { 41 | Manufacturer = manufacturer; 42 | Device = device; 43 | SoftwareVersions = softwareVersions; 44 | } 45 | 46 | public static DicomEquipment Read(DicomDataset ds) 47 | { 48 | var manufacturer = ds.GetTrimmedStringOrEmpty(DicomTag.Manufacturer); 49 | var softwareVersions = ds.GetTrimmedStringOrEmpty(DicomTag.SoftwareVersions); 50 | return new DicomEquipment(manufacturer, softwareVersions); 51 | } 52 | 53 | public static void Write(DicomDataset ds, DicomEquipment equipment) 54 | { 55 | ds.Add(DicomTag.Manufacturer, equipment.Manufacturer); 56 | ds.Add(DicomTag.SoftwareVersions, equipment.SoftwareVersions); 57 | } 58 | 59 | /// 60 | /// Creates an empty DicomEquipment instance 61 | /// 62 | /// 63 | public static DicomEquipment CreateEmpty() 64 | { 65 | return new DicomEquipment(string.Empty, string.Empty); 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/RT/DicomFrameOfReference.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | using Dicom; 7 | using MedLib.IO.Extensions; 8 | 9 | namespace MedLib.IO.RT 10 | { 11 | /// 12 | /// Encodes the DICOM Frame of reference module. 13 | /// 14 | /// 15 | public class DicomFrameOfReference 16 | { 17 | 18 | private DicomFrameOfReference(string uid, string referenceIndicator) 19 | { 20 | FrameOfReferenceUid = uid; 21 | PositionReferenceIndicator = referenceIndicator; 22 | } 23 | 24 | /// 25 | /// UID of the reference coordinate frame. Type 1. 26 | /// 27 | public string FrameOfReferenceUid { get; } 28 | 29 | /// 30 | /// Reference indicator for the coordinate system. Type 2 31 | /// 32 | public string PositionReferenceIndicator { get; } 33 | 34 | /// 35 | /// Read a DicomFrameOfReference from the given dataset throwing if Type 1 parameters are not present. 36 | /// 37 | /// 38 | /// 39 | public static DicomFrameOfReference Read(DicomDataset ds) 40 | { 41 | // throw 42 | var uid = ds.GetSingleValue(DicomTag.FrameOfReferenceUID); 43 | // no throw 44 | var posRef = ds.GetTrimmedStringOrEmpty(DicomTag.PositionReferenceIndicator); 45 | 46 | return new DicomFrameOfReference(uid.UID, posRef); 47 | } 48 | 49 | /// 50 | /// Creates an empty DicomFrameOfReference instance 51 | /// 52 | public static DicomFrameOfReference CreateEmpty() 53 | { 54 | return new DicomFrameOfReference( 55 | string.Empty, string.Empty 56 | ); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/RT/DicomPatient.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace MedLib.IO.RT 7 | { 8 | using Dicom; 9 | 10 | using Extensions; 11 | 12 | /// 13 | /// Encodes part of the DICOM Patient Module 14 | /// see http://dicom.nema.org/medical/Dicom/current/output/chtml/part03/sect_C.7.html 15 | /// 16 | public class DicomPatient 17 | { 18 | public DicomPatient(DicomPersonNameConverter name, string id, string birthDate, string sex) 19 | { 20 | Name = name; 21 | Id = id; 22 | BirthDate = birthDate; 23 | Sex = sex; 24 | } 25 | 26 | /// 27 | /// Patient Name in PN format Type 2. 28 | /// 29 | public DicomPersonNameConverter Name { get; } 30 | 31 | /// 32 | /// Institution's PatientID Type 2 33 | /// 34 | public string Id { get; } 35 | 36 | /// 37 | /// Patient's birthdate DA format Type 2 38 | /// 39 | public string BirthDate { get; } 40 | 41 | /// 42 | /// Patient's gender code string {M,F,O} Type 2 43 | /// 44 | public string Sex { get; } 45 | 46 | public static void Write(DicomDataset ds, DicomPatient patient) 47 | { 48 | ds.Add(DicomTag.PatientName, patient.Name.AsPersonName(DicomTag.PatientName).Get()); 49 | ds.Add(DicomTag.PatientID, patient.Id); 50 | ds.Add(DicomTag.PatientBirthDate, patient.BirthDate); 51 | ds.Add(DicomTag.PatientSex, patient.Sex); 52 | } 53 | 54 | public static DicomPatient Read(DicomDataset ds) 55 | { 56 | var patientName = ds.GetStringOrEmpty(DicomTag.PatientName); 57 | var patientId = ds.GetTrimmedStringOrEmpty(DicomTag.PatientID); 58 | var patientBirthDate = ds.GetStringOrEmpty(DicomTag.PatientBirthDate); 59 | var patientSex = ds.GetTrimmedStringOrEmpty(DicomTag.PatientSex); 60 | return new DicomPatient(new DicomPersonNameConverter(patientName), patientId, patientBirthDate, patientSex); 61 | } 62 | 63 | /// 64 | /// Return an empty DicomPatient instance 65 | /// 66 | /// 67 | public static DicomPatient CreateEmpty() 68 | { 69 | return new DicomPatient( 70 | new DicomPersonNameConverter(string.Empty), 71 | string.Empty, 72 | string.Empty, 73 | string.Empty 74 | ); 75 | } 76 | 77 | } 78 | } -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/RT/DicomPersonNameConverter.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace MedLib.IO.RT 7 | { 8 | using System.Globalization; 9 | using Dicom; 10 | 11 | public class DicomPersonNameConverter 12 | { 13 | public DicomPersonNameConverter(string firstName, string lastName, string middleName, string prefix, string suffix) 14 | { 15 | First = firstName; 16 | Last = lastName; 17 | Middle = middleName; 18 | Prefix = prefix; 19 | Suffix = suffix; 20 | } 21 | 22 | public DicomPersonNameConverter(string dicomFormattedPatientName) 23 | { 24 | if (string.IsNullOrWhiteSpace(dicomFormattedPatientName)) 25 | { 26 | return; 27 | } 28 | 29 | var elements = dicomFormattedPatientName.Split('^'); 30 | 31 | if (elements.Length > 0) 32 | { 33 | Last = elements[0]; 34 | } 35 | 36 | if (elements.Length > 1) 37 | { 38 | First = elements[1]; 39 | } 40 | 41 | if (elements.Length > 2) 42 | { 43 | Middle = elements[2]; 44 | } 45 | 46 | if (elements.Length > 3) 47 | { 48 | Prefix = elements[3]; 49 | } 50 | 51 | if (elements.Length > 4) 52 | { 53 | Suffix = elements[4]; 54 | } 55 | } 56 | 57 | public string First { get; set; } 58 | 59 | public string Last { get; set; } 60 | 61 | public string Middle { get; set; } 62 | 63 | public string Prefix { get; set; } 64 | 65 | public string Suffix { get; set; } 66 | 67 | public static string GetFormattedName(string dicomFormattedPatientName) 68 | { 69 | if (string.IsNullOrWhiteSpace(dicomFormattedPatientName)) 70 | { 71 | return dicomFormattedPatientName; 72 | } 73 | 74 | return new DicomPersonNameConverter(dicomFormattedPatientName).FormattedName; 75 | } 76 | 77 | public string FormattedName 78 | => 79 | $"{ToTitleCase(Prefix)}{(string.IsNullOrWhiteSpace(Prefix) ? "" : " ")}{ToTitleCase(First)}{(string.IsNullOrWhiteSpace(First) ? "" : " ")}{ToTitleCase(Middle)}{(string.IsNullOrWhiteSpace(Middle) ? "" : " ")}{ToTitleCase(Last)}{(string.IsNullOrWhiteSpace(Last) ? "" : " ")}{Suffix}".Trim() 80 | ; 81 | 82 | public string ToTitleCase(string str) 83 | { 84 | return string.IsNullOrEmpty(str) ? str : CultureInfo.CurrentCulture.TextInfo.ToTitleCase(str.ToLower(CultureInfo.CurrentCulture)); 85 | } 86 | 87 | public DicomPersonName AsPersonName(DicomTag dicomTag) 88 | { 89 | return new DicomPersonName(dicomTag, Last, First, Middle, Prefix, Suffix); 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/RT/DicomRTContourImageItem.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace MedLib.IO.RT 7 | { 8 | using Dicom; 9 | 10 | using MedLib.IO.Extensions; 11 | 12 | public class DicomRTContourImageItem 13 | { 14 | /// 15 | /// Create a reference to the given SOP common instance. 16 | /// 17 | /// 18 | /// 19 | public static DicomRTContourImageItem Reference(DicomSOPCommon instance) 20 | { 21 | return new DicomRTContourImageItem(instance.SopClassUid, instance.SopInstanceUid); 22 | } 23 | 24 | public DicomRTContourImageItem(string referencedSopClassUid, string referencedSopInstanceUid) 25 | { 26 | ReferencedSOPClassUID = referencedSopClassUid; 27 | ReferencedSOPInstanceUID = referencedSopInstanceUid; 28 | } 29 | 30 | public string ReferencedSOPClassUID { get; } 31 | 32 | public string ReferencedSOPInstanceUID { get; } 33 | 34 | public static DicomRTContourImageItem Read(DicomDataset imageds) 35 | { 36 | var referencedSOPClassUID = imageds.GetStringOrEmpty(DicomTag.ReferencedSOPClassUID); 37 | var referencedSOPInstanceUID = imageds.GetStringOrEmpty(DicomTag.ReferencedSOPInstanceUID); 38 | return new DicomRTContourImageItem(referencedSOPClassUID, referencedSOPInstanceUID); 39 | } 40 | 41 | public static DicomDataset Write(DicomRTContourImageItem contour) 42 | { 43 | var ds = new DicomDataset(); 44 | ds.Add(DicomTag.ReferencedSOPClassUID, contour.ReferencedSOPClassUID); 45 | ds.Add(DicomTag.ReferencedSOPInstanceUID, contour.ReferencedSOPInstanceUID); 46 | return ds; 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/RT/DicomRTFrameOFReference.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace MedLib.IO.RT 7 | { 8 | using System.Collections.Generic; 9 | 10 | using Dicom; 11 | 12 | /// 13 | /// The Referenced Frame of Reference Sequence (3006,0010) describes a set of frames of reference in 14 | /// which some or all of the ROIs are expressed.Since the Referenced Frame of Reference UID 15 | /// (3006,0024) is required for each ROI, each frame of reference used to express the coordinates of an ROI 16 | /// shall be listed in the Referenced Frame of Reference Sequence(3006,0010) once and only once. 17 | /// 18 | public class DicomRTFrameOFReference 19 | { 20 | public string FrameOfRefUID { get; } 21 | 22 | public IReadOnlyList ReferencedStudies { get; } 23 | 24 | public DicomRTFrameOFReference( 25 | string frameOfRefUid, 26 | IReadOnlyList referencedStudies) 27 | { 28 | FrameOfRefUID = frameOfRefUid; 29 | ReferencedStudies = referencedStudies; 30 | } 31 | 32 | public static DicomRTFrameOFReference Read(DicomDataset ds) 33 | { 34 | var frameReferencedUID = ds.GetSingleValueOrDefault(DicomTag.FrameOfReferenceUID, string.Empty); 35 | 36 | var referencedStudies = new List(); 37 | if (ds.Contains(DicomTag.RTReferencedStudySequence)) 38 | { 39 | var seq = ds.GetSequence(DicomTag.RTReferencedStudySequence); 40 | foreach (var item in seq) 41 | { 42 | referencedStudies.Add(DicomRTReferencedStudy.Read(item)); 43 | } 44 | } 45 | return new DicomRTFrameOFReference( 46 | frameReferencedUID, 47 | referencedStudies); 48 | } 49 | 50 | public static DicomDataset Write(DicomRTFrameOFReference dicomRtFrameOfReference) 51 | { 52 | var ds = new DicomDataset(); 53 | ds.Add(DicomTag.FrameOfReferenceUID, dicomRtFrameOfReference.FrameOfRefUID); 54 | var lisOfStudies = new List(); 55 | foreach (var refStudy in dicomRtFrameOfReference.ReferencedStudies) 56 | { 57 | var newDS = DicomRTReferencedStudy.Write(refStudy); 58 | lisOfStudies.Add(newDS); 59 | } 60 | if (lisOfStudies.Count > 0) 61 | { 62 | ds.Add(new DicomSequence(DicomTag.RTReferencedStudySequence, lisOfStudies.ToArray())); 63 | } 64 | return ds; 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/RT/DicomRTReferencedSeries.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace MedLib.IO.RT 7 | { 8 | using System.Collections.Generic; 9 | 10 | using Dicom; 11 | 12 | using MedLib.IO.Extensions; 13 | 14 | public class DicomRTReferencedSeries 15 | { 16 | public string SeriesInstanceUID { get; } 17 | 18 | public IReadOnlyList ContourImages { get; } 19 | 20 | public DicomRTReferencedSeries(string seriesInstanceUid, IReadOnlyList contourImages) 21 | { 22 | SeriesInstanceUID = seriesInstanceUid; 23 | ContourImages = contourImages; 24 | } 25 | 26 | public static DicomRTReferencedSeries Read(DicomDataset ds) 27 | { 28 | var seriesInstanceUID = ds.GetStringOrEmpty(DicomTag.SeriesInstanceUID); 29 | 30 | var contourImages = new List(); 31 | if (ds.Contains(DicomTag.ContourImageSequence)) 32 | { 33 | var seq = ds.GetSequence(DicomTag.ContourImageSequence); 34 | foreach (var item in seq) 35 | { 36 | var contourImageItem = DicomRTContourImageItem.Read(item); 37 | contourImages.Add(contourImageItem); 38 | } 39 | } 40 | 41 | return new DicomRTReferencedSeries(seriesInstanceUID, contourImages); 42 | } 43 | 44 | public static DicomDataset Write(DicomRTReferencedSeries series) 45 | { 46 | var ds = new DicomDataset(); 47 | ds.Add(DicomTag.SeriesInstanceUID, series.SeriesInstanceUID); 48 | 49 | var listOfContour = new List(); 50 | foreach (var contour in series.ContourImages) 51 | { 52 | var newDS = DicomRTContourImageItem.Write(contour); 53 | listOfContour.Add(newDS); 54 | } 55 | 56 | ds.Add(new DicomSequence(DicomTag.ContourImageSequence, listOfContour.ToArray())); 57 | return ds; 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/RT/DicomRTReferencedStudy.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace MedLib.IO.RT 7 | { 8 | using System; 9 | using System.Collections.Generic; 10 | 11 | using Dicom; 12 | 13 | using MedLib.IO.Extensions; 14 | 15 | public class DicomRTReferencedStudy 16 | { 17 | 18 | public static readonly string StudyComponentManagementSopClass = DicomUID.StudyComponentManagementSOPClassRETIRED.UID; 19 | 20 | public string ReferencedSOPClassUID { get; } 21 | 22 | public string ReferencedSOPInstanceUID { get; } 23 | 24 | public IReadOnlyList ReferencedSeries { get; } 25 | 26 | public DicomRTReferencedStudy( 27 | string referencedSopClassUid, 28 | string referencedSopInstanceUid, 29 | IReadOnlyList referencedSeries) 30 | { 31 | ReferencedSOPClassUID = referencedSopClassUid; 32 | ReferencedSOPInstanceUID = referencedSopInstanceUid; 33 | ReferencedSeries = referencedSeries; 34 | } 35 | 36 | public static DicomRTReferencedStudy Read(DicomDataset ds) 37 | { 38 | ds = ds ?? throw new ArgumentException(nameof(ds)); 39 | 40 | var refSOPClass = ds.GetStringOrEmpty(DicomTag.ReferencedSOPClassUID); 41 | var refSOPInstance = ds.GetStringOrEmpty(DicomTag.ReferencedSOPInstanceUID); 42 | var listSeries = new List(); 43 | 44 | if (ds.Contains(DicomTag.RTReferencedSeriesSequence)) 45 | { 46 | var seq = ds.GetSequence(DicomTag.RTReferencedSeriesSequence); 47 | foreach (var item in seq) 48 | { 49 | listSeries.Add(DicomRTReferencedSeries.Read(item)); 50 | } 51 | } 52 | return new DicomRTReferencedStudy(refSOPClass, refSOPInstance, listSeries); 53 | } 54 | 55 | public static DicomDataset Write(DicomRTReferencedStudy refStudy) 56 | { 57 | refStudy = refStudy ?? throw new ArgumentException(nameof(refStudy)); 58 | 59 | var ds = new DicomDataset(); 60 | ds.Add(DicomTag.ReferencedSOPClassUID, refStudy.ReferencedSOPClassUID); 61 | ds.Add(DicomTag.ReferencedSOPInstanceUID, refStudy.ReferencedSOPInstanceUID); 62 | var listOfContour = new List(); 63 | foreach (var series in refStudy.ReferencedSeries) 64 | { 65 | var newDS = DicomRTReferencedSeries.Write(series); 66 | listOfContour.Add(newDS); 67 | } 68 | if (listOfContour.Count > 0) 69 | { 70 | ds.Add(new DicomSequence(DicomTag.RTReferencedSeriesSequence, listOfContour.ToArray())); 71 | } 72 | return ds; 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/RT/DicomRTSeries.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace MedLib.IO.RT 7 | { 8 | using Dicom; 9 | 10 | using Extensions; 11 | using System; 12 | using System.Globalization; 13 | 14 | /// 15 | /// Encodes parts of the RTSeries DICOM module we use. 16 | /// see http://dicom.nema.org/medical/Dicom/current/output/chtml/part03/sect_C.8.8.html 17 | /// 18 | public class DicomRTSeries 19 | { 20 | public const string RtModality = "RTSTRUCT"; 21 | 22 | public string Modality { get; } 23 | 24 | public string SeriesInstanceUID 25 | { 26 | get; 27 | set; 28 | } 29 | 30 | /// 31 | /// Get/Set the Series Description of this RT Series 32 | /// 33 | public string SeriesDescription { get; set; } 34 | 35 | public DicomRTSeries(string modality, string seriesInstanceUID, string description) 36 | { 37 | Modality = modality; 38 | SeriesInstanceUID = seriesInstanceUID; 39 | SeriesDescription = description; 40 | } 41 | 42 | public static DicomRTSeries Read(DicomDataset ds) 43 | { 44 | var modality = ds.GetStringOrEmpty(DicomTag.Modality); 45 | var seriesInstanceUID = ds.GetStringOrEmpty(DicomTag.SeriesInstanceUID); 46 | var description = ds.GetStringOrEmpty(DicomTag.SeriesDescription); 47 | return new DicomRTSeries(modality, seriesInstanceUID, description); 48 | } 49 | 50 | public static void Write(DicomDataset ds, DicomRTSeries series) 51 | { 52 | ds.Add(DicomTag.Modality, series.Modality); 53 | ds.Add(DicomTag.SeriesInstanceUID, series.SeriesInstanceUID); 54 | ds.Add(DicomTag.SeriesDescription, series.SeriesDescription); 55 | // Type 2 attributes - must be present but empty is fine. 56 | ds.Add(DicomTag.OperatorsName, string.Empty); 57 | ds.Add(DicomTag.SeriesNumber, string.Empty); 58 | 59 | // Type 3 tags - optional but useful 60 | var now = DateTime.UtcNow; 61 | var date = now.ToString("yyyyMMdd", CultureInfo.InvariantCulture); 62 | var time = now.ToString("HHmmss", CultureInfo.InvariantCulture); 63 | ds.Add(DicomTag.SeriesDate, date); 64 | ds.Add(DicomTag.SeriesTime, time); 65 | } 66 | } 67 | 68 | } -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/RT/DicomSOPCommon.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace MedLib.IO.RT 7 | { 8 | using Dicom; 9 | using MedLib.IO.Extensions; 10 | 11 | /// 12 | /// Encodes important Type 1 tags from the SOP Common module 13 | /// 14 | /// 15 | public class DicomSOPCommon 16 | { 17 | /// 18 | /// The SOP Class UID of the parent instance. This uniquely and authoratively defines 19 | /// the modules expected within a Dicom dataset. Type 1, VR: UI 20 | /// 21 | public string SopClassUid { get; } 22 | 23 | /// 24 | /// A unique identifier for the parent instance. In theory this is a GUID in DICOM format. 25 | /// Type 1: VR: UI 26 | /// 27 | public string SopInstanceUid { get; } 28 | 29 | private DicomSOPCommon(string sopClassUid, string sopInstanceUid) 30 | { 31 | SopClassUid = sopClassUid; 32 | SopInstanceUid = sopInstanceUid; 33 | } 34 | 35 | /// 36 | /// Read a DicomSOPInstance from the given DicomDataset, throwing if required 37 | /// type 1 properties are not present. 38 | /// 39 | /// 40 | /// 41 | public static DicomSOPCommon Read(DicomDataset ds) 42 | { 43 | // throw 44 | var sopClassUid = ds.GetSingleValue(DicomTag.SOPClassUID).UID; 45 | var sopInstanceUid = ds.GetSingleValue(DicomTag.SOPInstanceUID).UID; 46 | 47 | return new DicomSOPCommon(sopClassUid, sopInstanceUid); 48 | } 49 | 50 | /// 51 | /// Creates an empty DicomSOPCommon instance. 52 | /// 53 | /// 54 | public static DicomSOPCommon CreateEmpty() 55 | { 56 | return new DicomSOPCommon(DicomExtensions.EmptyUid.UID, DicomExtensions.EmptyUid.UID); 57 | } 58 | 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/Readers/DicomFileAndPath.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 |  7 | namespace MedLib.IO.Readers 8 | { 9 | using System; 10 | using System.Diagnostics; 11 | using System.IO; 12 | using Dicom; 13 | 14 | /// 15 | /// Read only tuple of DicomFile and its original path 16 | /// 17 | public sealed class DicomFileAndPath 18 | { 19 | /// 20 | /// Creates a new instance of the class. 21 | /// 22 | /// The value to use for the File property of the object. 23 | /// The value to use for the Path property of the object. 24 | public DicomFileAndPath(DicomFile dicomFile, string path) 25 | { 26 | File = dicomFile; 27 | Path = path; 28 | } 29 | 30 | /// 31 | /// Create a DicomFileAndPath from a path to a folder 32 | /// 33 | /// 34 | /// 35 | public static DicomFileAndPath SafeCreate(string path) 36 | { 37 | try 38 | { 39 | return new DicomFileAndPath(DicomFile.Open(path), path); 40 | } 41 | catch (Exception e) 42 | { 43 | Trace.TraceInformation($"DicomFileAndPath.Create: File {path} error {e}"); 44 | } 45 | return null; 46 | } 47 | 48 | /// 49 | /// Create a DicomFileAndPath from a stream and path 50 | /// 51 | /// 52 | /// 53 | /// 54 | public static DicomFileAndPath SafeCreate(Stream stream, string path) 55 | { 56 | try 57 | { 58 | return new DicomFileAndPath(DicomFile.Open(stream), path); 59 | } 60 | catch (Exception e) 61 | { 62 | Trace.TraceInformation($"DicomFileAndPath.Create: Cannot open from stream. Error {e}"); 63 | } 64 | return null; 65 | } 66 | 67 | /// 68 | /// The DicomFile associated with the given Path, 69 | /// 70 | public DicomFile File { get; private set; } 71 | 72 | /// 73 | /// The file system path to the DicomFile 74 | /// 75 | public string Path { get; private set; } 76 | 77 | /// 78 | /// Saves the Dicom file to the given folder. The filename is read from the 79 | /// property, which must be non-empty. Returns the full filename (folder plus filename) to which 80 | /// the file was saved. 81 | /// 82 | /// The directory into which the Dicom file should be saved. The directory must exist already. 83 | public string SaveToFolder(string folder) 84 | { 85 | if (string.IsNullOrWhiteSpace(Path)) 86 | { 87 | throw new InvalidOperationException("Saving requires a non-empty string in the Path property."); 88 | } 89 | var fullFilename = System.IO.Path.Combine(folder, Path); 90 | File.Save(fullFilename); 91 | return fullFilename; 92 | } 93 | } 94 | } -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/Readers/DicomSeriesContent.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace MedLib.IO.Readers 7 | { 8 | using System.Collections.Generic; 9 | using Dicom; 10 | 11 | /// 12 | /// Readonly collection of CT/MR images associated with a given series. 13 | /// 14 | public sealed class DicomSeriesContent 15 | { 16 | public DicomSeriesContent(DicomUID seriesUID, IReadOnlyList content) 17 | { 18 | SeriesUID = seriesUID; 19 | Content = content; 20 | } 21 | 22 | /// 23 | /// The unique DICOM Series UID 24 | /// 25 | public DicomUID SeriesUID { get; private set; } 26 | 27 | /// 28 | /// The list of recognised Sop Class instances in this series. 29 | /// 30 | public IReadOnlyList Content { get; private set; } 31 | } 32 | } -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/Readers/DicomSeriesReader.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace MedLib.IO.Readers 7 | { 8 | using System; 9 | using System.Collections.Generic; 10 | using Dicom; 11 | using MedLib.IO.Models; 12 | using InnerEye.CreateDataset.Volumes; 13 | 14 | /// 15 | /// Reads medical image volumes represented as DICOM series. 16 | /// Supports only CT and MR images at present with 2 bytes per pixel. 17 | /// 18 | public static class DicomSeriesReader 19 | { 20 | /// 21 | /// The collection of supported transfer syntaxes for CT & MR images. 22 | /// 23 | public static readonly DicomTransferSyntax[] SupportedTransferSyntaxes = { 24 | DicomTransferSyntax.ExplicitVRLittleEndian, // Does not crash app if corrupted - loads corrupted data 25 | DicomTransferSyntax.ImplicitVRLittleEndian, // Does not crash app if corrupted - loads corrupted data 26 | DicomTransferSyntax.ExplicitVRBigEndian, // Does not crash app if corrupted - loads corrupted data 27 | DicomTransferSyntax.JPEGProcess14SV1, // Does not crash app if corrupted - loads corrupted data 28 | DicomTransferSyntax.JPEGProcess14, // Does not crash app if corrupted. - loads corrupted data 29 | DicomTransferSyntax.JPEGLSLossless, // Codec exception managed code if corrupted - does not load 30 | DicomTransferSyntax.RLELossless // Does not crash app or load data if corrupted 31 | }; 32 | 33 | /// 34 | /// Attempt to construct a 3-dimensional volume instance from the provided set of DICOM series files. 35 | /// 36 | /// The collection of DICOM datasets. 37 | /// An implmentation of IVolumeGeometricAcceptanceTest expressing the geometric tollerances required by your application 38 | /// true if it is appropriate for your application to support lossy pixel encodings 39 | /// The created 3-dimensional volume. 40 | /// The DICOM datasets or acceptance test is null. 41 | /// A volume could not be formed from the provided DICOM series datasets. 42 | public static Volume3D BuildVolume( 43 | IEnumerable dicomDatasets, 44 | IVolumeGeometricAcceptanceTest acceptanceTest, 45 | bool supportLossyCodecs) 46 | { 47 | dicomDatasets = dicomDatasets ?? throw new ArgumentNullException(nameof(dicomDatasets)); 48 | acceptanceTest = acceptanceTest ?? throw new ArgumentNullException(nameof(acceptanceTest)); 49 | 50 | // 1. Construct the volume information: this requires a minimum set of DICOM tags in each dataset. 51 | var volumeInformation = VolumeInformation.Create(dicomDatasets); 52 | 53 | // 2. Now validate the volume based on the acceptance tests (will throw argument exception on failure). 54 | DicomSeriesInformationValidator.ValidateVolumeInformation(volumeInformation, acceptanceTest, supportLossyCodecs ? null : SupportedTransferSyntaxes); 55 | 56 | // 3. Now validated, lets extract the pixels as a short array. 57 | return DicomSeriesImageReader.BuildVolume(volumeInformation); 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/Readers/IVolumeGeometricAcceptanceTest.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace MedLib.IO.Readers 7 | { 8 | using Dicom; 9 | using InnerEye.CreateDataset.Volumes; 10 | 11 | /// 12 | /// Allow for customized acceptance of a volume depending on criteria outside the scope of this library 13 | /// 14 | public interface IVolumeGeometricAcceptanceTest 15 | { 16 | /// 17 | /// Called by the framework when it proposes to form a volume encoded by {volumeOrigin, iop, voxelDims} from the 18 | /// given set of ordered Dicom datasets. 19 | /// 20 | /// The type of images forming the volume 21 | /// The origin of the volume in the DICOM reference coordinate system 22 | /// The orientation matrix of the volume in the DICOM reference coordinate system 23 | /// The dimensions of the voxels in mm 24 | /// Set this to a human readable string defining the reason for rejection 25 | /// Return true if and only if you agree to this 26 | bool Propose(DicomUID sopClassUid, Point3D volumeOrigin, Matrix3 iop, Point3D voxelDims, out string reason); 27 | 28 | /// 29 | /// Constructing volumes from a candidate set of DICOM images necessarily involves error. This method will be called 30 | /// by the implementation for every corner of every slice. You must explicitely accept the error for each call otherwise 31 | /// the entire volume will be rejected and the images will not load. 32 | /// 33 | /// The actual position of the slice corner in the reference coordinate system 34 | /// inferred from the DICOM dataset 35 | /// The position of the slice corner in the reference coordinate system 36 | /// within the volumetric construction 37 | /// 38 | bool AcceptPositionError(DicomUID sopClassUid, Point3D actualCoordinate, Point3D volumeCoordinate); 39 | 40 | /// 41 | /// Constructing volumes from a candidate set of DICOM images necessarily involves error.This method is called for every sequential pair of slices in the volume. 42 | /// You must explicitely accept the error for each call otherwise the entire volume will be rejected and the images will not load 43 | /// 44 | /// The gap in mm between sequential slices 45 | /// The median slice gap in mm 46 | /// 47 | bool AcceptSliceSpacingError(DicomUID sopClassUid, double sliceGap, double medianSliceGap); 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/Writers/RTStructCreator.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace MedLib.IO.Writers 7 | { 8 | using System; 9 | using System.Collections.Generic; 10 | using MedLib.IO.Extensions; 11 | using MedLib.IO.Models.DicomRt; 12 | using MedLib.IO.Readers; 13 | using MedLib.IO.RT; 14 | using InnerEye.CreateDataset.Contours; 15 | using InnerEye.CreateDataset.Volumes; 16 | 17 | public class RTStructCreator 18 | { 19 | /// 20 | /// Creates a new RadiotherapyContour for inclusion in a RadiotherapyStruct ready for serialization 21 | /// 22 | /// 23 | /// The contours relative to the given volume you wish to map into the DICOM reference coordinate system 24 | /// The DICOM identifiers describing the origin of the volume 25 | /// The volume transform. 26 | /// The DICOM structure name 27 | /// The color of this structure 28 | /// The roiNumber of this structure 29 | /// 30 | public static RadiotherapyContour CreateRadiotherapyContour( 31 | ContoursPerSlice axialContours, 32 | IReadOnlyList identifiers, 33 | VolumeTransform volumeTransform, 34 | string name, 35 | (byte R, byte G, byte B) color, 36 | string roiNumber, 37 | DicomPersonNameConverter interpreterName, 38 | ROIInterpretedType roiInterpretedType) 39 | { 40 | if (identifiers == null || identifiers.Count == 0) 41 | { 42 | throw new ArgumentException("The DICOM identifiers cannot be null or empty"); 43 | } 44 | 45 | var contours = axialContours.ToDicomRtContours(identifiers, volumeTransform); 46 | var rtcontour = new DicomRTContour(roiNumber, Tuple.Create(color.R, color.G, color.B), contours); 47 | var rtRoIstructure = new DicomRTStructureSetROI(roiNumber, name, identifiers[0].FrameOfReference.FrameOfReferenceUid, ERoiGenerationAlgorithm.Semiautomatic); 48 | var observation = new DicomRTObservation(roiNumber, interpreterName, roiInterpretedType); 49 | var output = new RadiotherapyContour(rtcontour, rtRoIstructure, observation); 50 | output.Contours = axialContours; 51 | return output; 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/Writers/RTStructWriter.cs: -------------------------------------------------------------------------------- 1 | /// ------------------------------------------------------------------------------------------ 2 | /// Copyright (c) Microsoft Corporation. All rights reserved. 3 | /// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. 4 | /// ------------------------------------------------------------------------------------------ 5 | 6 | namespace MedLib.IO.Writers 7 | { 8 | using Dicom; 9 | using Models.DicomRt; 10 | 11 | public class RtStructWriter 12 | { 13 | public static void SaveRtStruct(string filePath, RadiotherapyStruct rtStruct) 14 | { 15 | var file = GetRtStructFile(rtStruct); 16 | file.Save(filePath); 17 | } 18 | 19 | public static DicomFile GetRtStructFile(RadiotherapyStruct rtStruct) 20 | { 21 | var file = new DicomFile(); 22 | var ds = file.Dataset; 23 | 24 | // We must use the same UID for SOPInstanceUID & MediaStorageSOPInstanceUID 25 | DicomUID sopInstanceUID = DicomUID.Generate(); 26 | 27 | file.FileMetaInfo.MediaStorageSOPClassUID = DicomUID.RTStructureSetStorage; 28 | file.FileMetaInfo.MediaStorageSOPInstanceUID = sopInstanceUID; 29 | // Fo-Dicom has some policy for this - using the machine name - we remove this 30 | file.FileMetaInfo.Remove(DicomTag.SourceApplicationEntityTitle); 31 | 32 | // It is very important that we only use ImplicitVRLittleEndian here, otherwise large contours 33 | // can exceed the maximum length of a an explicit VR. 34 | file.FileMetaInfo.TransferSyntax = DicomTransferSyntax.ImplicitVRLittleEndian; 35 | 36 | //WRITE INSTANCE UID AND SOP CLASS UID 37 | ds.Add(DicomTag.SOPClassUID, DicomUID.RTStructureSetStorage); 38 | ds.Add(DicomTag.SOPInstanceUID, sopInstanceUID); 39 | 40 | RadiotherapyStruct.Write(ds, rtStruct); 41 | 42 | return file; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Source/projects/MedLib.IO/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Source/projects/build.yml: -------------------------------------------------------------------------------- 1 | trigger: 2 | - master 3 | 4 | pool: 5 | vmImage: 'windows-2019' 6 | 7 | variables: 8 | buildConfiguration: 'Release' 9 | buildPlatform: "x64" 10 | 11 | steps: 12 | - task: CredScan@3 13 | 14 | - task: NuGetToolInstaller@0 15 | displayName: 'Use NuGet 4.8.1' 16 | inputs: 17 | versionSpec: 4.8.1 18 | 19 | - task: NuGetCommand@2 20 | displayName: 'NuGet Restore' 21 | inputs: 22 | feedsToUse: config 23 | nugetConfigPath: Source/NuGet.config 24 | restoreDirectory: '$(Build.SourcesDirectory)/Source/thirdparty/packages' 25 | 26 | - task: ComponentGovernanceComponentDetection@0 27 | inputs: 28 | scanType: 'Register' 29 | verbosity: 'Verbose' 30 | alertWarningLevel: 'Critical' 31 | failOnAlert: true 32 | 33 | - task: VSBuild@1 34 | displayName: 'Build all solutions' 35 | inputs: 36 | platform: '$(buildPlatform)' 37 | configuration: '$(buildConfiguration)' 38 | clean: true 39 | msbuildArchitecture: x64 40 | createLogFile: true 41 | 42 | - task: VSTest@2 43 | inputs: 44 | testSelector: 'testAssemblies' 45 | testAssemblyVer2: | 46 | **\*test*.dll 47 | !**\*TestAdapter.dll 48 | !**\obj\** 49 | searchFolder: '$(System.DefaultWorkingDirectory)' 50 | 51 | - task: CopyFiles@2 52 | inputs: 53 | SourceFolder: '$(Build.SourcesDirectory)/Source/projects/InnerEye.CreateDataset.Runner/bin' 54 | Contents: '**' 55 | TargetFolder: '$(Build.ArtifactStagingDirectory)' 56 | CleanTargetFolder: true 57 | 58 | - task: PublishBuildArtifacts@1 59 | inputs: 60 | PathtoPublish: '$(Build.ArtifactStagingDirectory)' 61 | ArtifactName: 'CreateDatasetRunner' 62 | publishLocation: 'Container' -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "2.1.402" 4 | } 5 | } --------------------------------------------------------------------------------