├── .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 | }
--------------------------------------------------------------------------------