Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix some bugs #4

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 46 additions & 14 deletions RT.Core/DICOM/PixelDataInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class PixelDataInfo
public double[] PixelSpacing { get; set; }
public string ImageType { get; set; }
public double SliceThickness { get; set; }
public double SpacingBetweenSlices { get; set; }
public int Rows { get; set; }
public int Columns { get; set; }
public int BitsAllocated { get; set; }
Expand All @@ -32,37 +33,68 @@ public class PixelDataInfo

public PixelDataInfo(DicomFile file)
{
var imgOrientationPatient = file.Dataset.Get<double[]>(DicomTag.ImageOrientationPatient, new double[] { 0, 0, 0, 0, 0, 0 });
var imgOrientationPatient = new double[] { 0, 0, 0, 0, 0, 0 };
if (file.Dataset.TryGetValues<double>(DicomTag.ImageOrientationPatient, out double[] tmp))
{
imgOrientationPatient = tmp;
}

RowDir = new Point3d(imgOrientationPatient[0], imgOrientationPatient[1], imgOrientationPatient[2]);
ColDir = new Point3d(imgOrientationPatient[3], imgOrientationPatient[4], imgOrientationPatient[5]);

var imgPositionPatient = file.Dataset.Get<double[]>(DicomTag.ImagePositionPatient, new double[] { 0, 0, 0 });
var imgPositionPatient = new double[] { 0, 0, 0 };
if (file.Dataset.TryGetValues<double>(DicomTag.ImagePositionPatient, out tmp))
{
imgPositionPatient = tmp;
}

ImagePositionPatient = new Point3d(imgPositionPatient[0], imgPositionPatient[1], imgPositionPatient[2]);

SliceThickness = file.Dataset.Get<double>(DicomTag.SliceThickness, 0.0);
Rows = file.Dataset.Get<int>(DicomTag.Rows);
Columns = file.Dataset.Get<int>(DicomTag.Columns);
BitsAllocated = file.Dataset.Get<int>(DicomTag.BitsAllocated, 0);
PixelRepresentation = file.Dataset.Get<int>(DicomTag.PixelRepresentation, 0);
RescaleSlope = file.Dataset.Get<float>(DicomTag.RescaleSlope, 1.0f);
RescaleIntercept = file.Dataset.Get<float>(DicomTag.RescaleIntercept, 0.0f);
PixelSpacing = file.Dataset.Get<double[]>(DicomTag.PixelSpacing, new double[] {1,1,1 });
SliceThickness = file.Dataset.GetSingleValueOrDefault<double>(DicomTag.SliceThickness, 0.0);

//winson add 2020.9.2 - Inconsistent 'Slice Thickness' and 'Spacing Between Slices'
SpacingBetweenSlices = file.Dataset.GetSingleValueOrDefault<double>(DicomTag.SpacingBetweenSlices, 0.0);
if (SpacingBetweenSlices > 0.0)
{
SliceThickness = SpacingBetweenSlices;
}

Rows = file.Dataset.GetSingleValue<int>(DicomTag.Rows);
Columns = file.Dataset.GetSingleValue<int>(DicomTag.Columns);
BitsAllocated = file.Dataset.GetSingleValueOrDefault<int>(DicomTag.BitsAllocated, 0);
PixelRepresentation = file.Dataset.GetSingleValueOrDefault<int>(DicomTag.PixelRepresentation, 0);
RescaleSlope = file.Dataset.GetSingleValueOrDefault<float>(DicomTag.RescaleSlope, 1.0f);
RescaleIntercept = file.Dataset.GetSingleValueOrDefault<float>(DicomTag.RescaleIntercept, 0.0f);

if (file.Dataset.TryGetValues<double>(DicomTag.PixelSpacing, out tmp))
{
PixelSpacing = tmp;
}
else
{
PixelSpacing = new double[] { 1, 1, 1 };
}

try
{
SliceLocation = file.Dataset.Get<double>(DicomTag.SliceLocation, 0.0);
SliceLocation = file.Dataset.GetSingleValueOrDefault<double>(DicomTag.SliceLocation, 0.0);
HasSliceLocation = true;
}
#pragma warning disable CS0168 // The variable 'e' is declared but never used
catch (Exception e)
#pragma warning restore CS0168 // The variable 'e' is declared but never used
{
HasSliceLocation = false;
}

try
if (file.Dataset.TryGetValues<double>(DicomTag.GridFrameOffsetVector, out tmp))//All Z-offsets
{
GridFrameOffsetVector = tmp;
}
else
{
GridFrameOffsetVector = file.Dataset.Get<DicomDecimalString>(DicomTag.GridFrameOffsetVector).Get<double[]>(); //All Z-offsets
GridFrameOffsetVector = new double[1];
}
catch (Exception e) { GridFrameOffsetVector = new double[1]; };
}
}
}
8 changes: 8 additions & 0 deletions RT.Core/Dose/DicomDoseObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ namespace RT.Core.Dose
{
public class DicomDoseObject:DicomObject, IDoseObject
{
public string SerriesNumber { get; set; }
public string SerriesDescription { get; set; }

public string ClassUID { get; set; }
public string InstanceUID { get; set; }
public string ReferencedClassUID { get; set; }
public string ReferencedInstanceUID { get; set; }

public IVoxelDataStructure Grid { get; set; }
public DicomDoseObject() { }
}
Expand Down
1 change: 1 addition & 0 deletions RT.Core/Dose/RelativeNormalisationOption.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace RT.Core.Dose
{
public enum RelativeNormalisationOption
{
Rx,
Max,
POI,
}
Expand Down
128 changes: 71 additions & 57 deletions RT.Core/Geometry/GridBasedVoxelDataStructure.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,73 +81,87 @@ public override void Interpolate(Point3d position, Voxel voxel)
}
else
{
//float x0 = 0, x1 = 0, y0 = 0, y1 = 0, z0 = 0, z1 = 0;
//int ix0 = 0, ix1 = 0, iy0 = 0, iy1 = 0, iz0 = 0, iz1 = 0;

if (ConstantGridSpacing)
try
{
ix0 = (int)((position.X - XCoords[0]) / GridSpacing.X);
if (ix0 == XCoords.Length - 1)
ix1 = ix0;
else
ix1 = ix0 + 1;
x0 = XCoords[ix0];
x1 = XCoords[ix1];
iy0 = (int)((position.Y - YCoords[0]) / GridSpacing.Y);
if (iy0 == YCoords.Length - 1)
iy1 = iy0;
else
iy1 = iy0 + 1;
y0 = YCoords[iy0];
y1 = YCoords[iy1];
if (GridSpacing.Z != 0)
//float x0 = 0, x1 = 0, y0 = 0, y1 = 0, z0 = 0, z1 = 0;
//int ix0 = 0, ix1 = 0, iy0 = 0, iy1 = 0, iz0 = 0, iz1 = 0;

if (ConstantGridSpacing)
{
iz0 = (int)((position.Z - ZCoords[0]) / GridSpacing.Z);
if (iz0 == ZCoords.Length - 1)
iz1 = iz0;
ix0 = (int)((position.X - XCoords[0]) / GridSpacing.X);
if (ix0 >= XCoords.Length - 1)
ix1 = ix0 = XCoords.Length - 1;
else
ix1 = ix0 + 1;
x0 = XCoords[ix0];
x1 = XCoords[ix1];

iy0 = (int)((position.Y - YCoords[0]) / GridSpacing.Y);
if (iy0 >= YCoords.Length - 1)
iy1 = iy0 = YCoords.Length - 1;
else
iy1 = iy0 + 1;

y0 = YCoords[iy0];
y1 = YCoords[iy1];
if (GridSpacing.Z != 0)
{
iz0 = (int)((position.Z - ZCoords[0]) / GridSpacing.Z);
iz1 = iz0 + 1;
z0 = ZCoords[iz0];
z1 = ZCoords[iz1];

if (iz0 >= ZCoords.Length - 1)
iz1 = iz0 = ZCoords.Length - 1;
else
iz1 = iz0 + 1;

z0 = ZCoords[iz0];
z1 = ZCoords[iz1];
}
else
{
iz0 = 0; iz1 = 0;
z0 = ZCoords[iz0];
z1 = ZCoords[iz1];
}
}
else
{
iz0 = 0; iz1 = 0;
z0 = ZCoords[iz0];
z1 = ZCoords[iz1];
var xt = binarySearchForSurroundingCoords(position.X, XCoords);
x0 = (float)xt.Item1;
x1 = (float)xt.Item2;
ix0 = xt.Item3;
ix1 = xt.Item4;
var yt = binarySearchForSurroundingCoords(position.Y, YCoords);
y0 = (float)yt.Item1;
y1 = (float)yt.Item2;
iy0 = yt.Item3;
iy1 = yt.Item4;
var zt = binarySearchForSurroundingCoords(position.Z, ZCoords);
z0 = (float)zt.Item1;
z1 = (float)zt.Item2;
iz0 = zt.Item3;
iz1 = zt.Item4;
}

voxel.Value = Interpolation.TrilinearInterpolate(
(float)position.X, (float)position.Y, (float)position.Z,
x0, y0, z0,
x1, y1, z1,
Data[getIndex(ix0, iy0, iz0)],
Data[getIndex(ix1, iy0, iz0)],
Data[getIndex(ix0, iy0, iz1)],
Data[getIndex(ix1, iy0, iz1)],
Data[getIndex(ix0, iy1, iz0)],
Data[getIndex(ix1, iy1, iz0)],
Data[getIndex(ix0, iy1, iz1)],
Data[getIndex(ix1, iy1, iz1)]);
}
else
#pragma warning disable CS0168 // The variable 'e' is declared but never used
catch(Exception e)
#pragma warning restore CS0168 // The variable 'e' is declared but never used
{
var xt = binarySearchForSurroundingCoords(position.X, XCoords);
x0 = (float)xt.Item1;
x1 = (float)xt.Item2;
ix0 = xt.Item3;
ix1 = xt.Item4;
var yt = binarySearchForSurroundingCoords(position.Y, YCoords);
y0 = (float)yt.Item1;
y1 = (float)yt.Item2;
iy0 = yt.Item3;
iy1 = yt.Item4;
var zt = binarySearchForSurroundingCoords(position.Z, ZCoords);
z0 = (float)zt.Item1;
z1 = (float)zt.Item2;
iz0 = zt.Item3;
iz1 = zt.Item4;
}

voxel.Value = Interpolation.TrilinearInterpolate(
(float)position.X, (float)position.Y, (float)position.Z,
x0, y0, z0,
x1, y1, z1,
Data[getIndex(ix0, iy0, iz0)],
Data[getIndex(ix1, iy0, iz0)],
Data[getIndex(ix0, iy0, iz1)],
Data[getIndex(ix1, iy0, iz1)],
Data[getIndex(ix0, iy1, iz0)],
Data[getIndex(ix1, iy1, iz0)],
Data[getIndex(ix0, iy1, iz1)],
Data[getIndex(ix1, iy1, iz1)]);
voxel.Value = DefaultPhysicalValue;
}
}
}

Expand Down
19 changes: 16 additions & 3 deletions RT.Core/Geometry/VoxelDataStructureBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public abstract class VoxelDataStructureBase
private Point3d positionCache;
private Voxel voxelCache;

public double RxDose { get; set; }
public double NormalisationPercent { get; set; } = 100;
public NormalisationType NormalisationType { get; set; } = NormalisationType.Relative;
public RelativeNormalisationOption RelativeNormalisationOption { get; set; }
Expand Down Expand Up @@ -92,12 +93,24 @@ public float GetNormalisationAmount()
{
if (NormalisationType == NormalisationType.Absolute)
return 1;

if (NormalisationType == NormalisationType.Relative)
{
if (RelativeNormalisationOption == RelativeNormalisationOption.Max)
return MaxVoxel.Value * Scaling * ((float)NormalisationPercent / (100*100));
float value = 1.0f;

if (RelativeNormalisationOption == RelativeNormalisationOption.Rx)
{
value = 1.0f;
}
else if (RelativeNormalisationOption == RelativeNormalisationOption.Max)
{
value = MaxVoxel.Value;
}
else if (RelativeNormalisationOption == RelativeNormalisationOption.POI && NormalisationPOI != null)
return this.Interpolate(NormalisationPOI.Position).Value * Scaling * ((float)NormalisationPercent / (100* 100));
{
value = this.Interpolate(NormalisationPOI.Position).Value;
}
return value * Scaling * ((float)NormalisationPercent / (100* 100));
}
return 1;
}
Expand Down
51 changes: 49 additions & 2 deletions RT.Core/IO/DicomLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,40 @@ public static async Task<DicomDoseObject> LoadDicomDoseAsync(string fileName, IP
return await LoadDicomDoseAsync(new string[] { fileName }, progress);
}

public static DicomDoseObject LoadDicomDoseSync(DicomFile dicomFile)
{
var loader = new DicomDoseLoader();
var dose = new DicomDoseObject();
loader.Load(dicomFile, dose, null);
return dose;
}

public static async Task<DicomPlanObject> LoadDicomPlanAsync(string[] fileNames)
{
var files = await getFilesAsync(fileNames);
var loader = new PlanLoader();
var plan = new DicomPlanObject();
loader.Load(files, plan);
return plan;
}

public static DicomPlanObject LoadDicomPlanAsync(DicomFile dicomFile)
{
var loader = new PlanLoader();
var plan = new DicomPlanObject();
loader.Load(dicomFile, plan);
return plan;
}


public static async Task<DicomPlanObject> LoadDicomPlanAsync(string fileName)
{
return await LoadDicomPlanAsync(new string[] { fileName });
}

#pragma warning disable CS1998 // This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
public static async Task<EgsDoseObject> LoadEgsObjectAsync(string file, IProgress<double> progress)
#pragma warning restore CS1998 // This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
var loader = new EgsDoseLoader();
var dose = new EgsDoseObject();
Expand Down Expand Up @@ -61,9 +94,17 @@ public static async Task<StructureSet> LoadStructureSetAsync(string[] fileNames,
return structureSet;
}

public static async Task<DicomDoseObject> LoadStructureSetAsync(string fileName, IProgress<double> progress)
public static StructureSet LoadStructureSetSync(DicomFile dicomFile, IProgress<double> progress)
{
return await LoadDicomDoseAsync(new string[] { fileName }, progress);
var loader = new ROILoader();
var structureSet = new StructureSet();
loader.Load(dicomFile, structureSet, progress);
return structureSet;
}

public static async Task<StructureSet> LoadStructureSetAsync(string fileName, IProgress<double> progress)
{
return await LoadStructureSetAsync(new string[] { fileName }, progress);
}

private static async Task<DicomFile[]> getFilesAsync(string[] fileNames)
Expand All @@ -73,7 +114,13 @@ private static async Task<DicomFile[]> getFilesAsync(string[] fileNames)
foreach(string fileName in fileNames)
{
if (DicomFile.HasValidHeader(fileName))
{
files.Add(await DicomFile.OpenAsync(fileName));
}
else if(DicomFile.IsDICOMFile(fileName))
{
files.Add(await DicomFile.OpenAsync(fileName));
}
}
return files.ToArray();
}
Expand Down
Loading