private static Volume3D <byte> ToVolume3D( this ContoursPerSlice contours, double spacingX, double spacingY, double spacingZ, Point3D origin, Matrix3 direction, Region3D <int> roi) { ContoursPerSlice subContours = new ContoursPerSlice( contours.Where(x => x.Value != null).Select( contour => new KeyValuePair <int, IReadOnlyList <ContourPolygon> >( contour.Key - roi.MinimumZ, contour.Value.Select(x => new ContourPolygon( x.ContourPoints.Select( point => new PointF(point.X - roi.MinimumX, point.Y - roi.MinimumY)).ToArray(), 0)) .ToList())).ToDictionary(x => x.Key, y => y.Value)); var result = new Volume3D <byte>(roi.MaximumX - roi.MinimumX + 1, roi.MaximumY - roi.MinimumY + 1, roi.MaximumZ - roi.MinimumZ + 1, spacingX, spacingY, spacingZ, origin, direction); result.Fill(subContours, ModelConstants.MaskForegroundIntensity); return(result); }
/// <summary> /// Creates a volume that has the same spacing and coordinate system as the reference volume, /// and fills all points that fall inside of the contours in the present object with the /// default foreground value. The returned volume has its size determined by the given region of interest. /// Contour points are transformed using the region of interest. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="contours">The contours to use for filling.</param> /// <param name="refVolume3D">The reference volume to copy spacing and coordinate system from.</param> /// <param name="regionOfInterest"></param> /// <returns></returns> public static Volume3D <byte> ToVolume3D <T>(this ContoursPerSlice contours, Volume3D <T> refVolume3D, Region3D <int> regionOfInterest) { return(contours.ToVolume3D( refVolume3D.SpacingX, refVolume3D.SpacingY, refVolume3D.SpacingZ, refVolume3D.Origin, refVolume3D.Direction, regionOfInterest)); }
/// <summary> /// Creates a volume that has the same size, spacing, and coordinate system as the reference volume, /// and fills all points that fall inside of the contours in the present object with the default foreground value. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="contours">The contours to use for filling.</param> /// <param name="refVolume3D">The reference volume to copy spacing and coordinate system from.</param> /// <returns></returns> public static Volume3D <byte> ToVolume3D <T>(this ContoursPerSlice contours, Volume3D <T> refVolume3D) { return(contours.ToVolume3D( refVolume3D.SpacingX, refVolume3D.SpacingY, refVolume3D.SpacingZ, refVolume3D.Origin, refVolume3D.Direction, refVolume3D.GetFullRegion())); }
/// <summary> /// Creates a new RadiotherapyContour for inclusion in a RadiotherapyStruct ready for serialization /// </summary> /// <typeparam name="T"></typeparam> /// <param name="axialContours">The contours relative to the given volume you wish to map into the DICOM reference coordinate system</param> /// <param name="identifiers"> The DICOM identifiers describing the origin of the volume</param> /// <param name="volumeTransform">The volume transform.</param> /// <param name="name">The DICOM structure name</param> /// <param name="color">The color of this structure</param> /// <param name="roiNumber">The roiNumber of this structure</param> /// <returns></returns> public static RadiotherapyContour CreateRadiotherapyContour( ContoursPerSlice axialContours, IReadOnlyList <DicomIdentifiers> identifiers, VolumeTransform volumeTransform, string name, (byte R, byte G, byte B) color,
/// <summary> /// Creates a new instance of the class, setting all properties that the class holds. /// </summary> /// <param name="name">The name of the anatomical structure that is represented by the contour.</param> /// <param name="color">The color that should be used to render the contour.</param> /// <param name="contour">The contours broken down by slice of the scan.</param> /// <exception cref="ArgumentNullException">The contour name or mask was null.</exception> public ContourRenderingInformation(string name, RGBColor color, ContoursPerSlice contour) { Name = name ?? throw new ArgumentNullException(nameof(name)); Color = color; Contour = contour ?? throw new ArgumentNullException(nameof(contour)); }
/// <summary> /// Modifies the present volume by filling all points that fall inside of the given contours, /// using the provided fill value. Contours are filled on axial slices. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="volume">The volume that should be modified.</param> /// <param name="contours">The contours per axial slice.</param> /// <param name="value">The value that should be used to fill all points that fall inside of /// the given contours.</param> public static void Fill <T>(this Volume3D <T> volume, ContoursPerSlice contours, T value) => FillPolygon.FillContours(volume, contours, value);
/// <summary> /// Gets the smallest cuboid region that full encloses all the per-slice contours in the present object. /// </summary> /// <param name="axialContours"></param> /// <returns></returns> public static Region3D <int> GetRegion(this ContoursPerSlice axialContours) { var minX = double.MaxValue; var maxX = double.MinValue; var minY = double.MaxValue; var maxY = double.MinValue; var minZ = int.MaxValue; var maxZ = int.MinValue; foreach (var contours in axialContours) { if (contours.Value.Count == 0) { continue; } if (contours.Key < minZ) { minZ = contours.Key; } if (contours.Key > maxZ) { maxZ = contours.Key; } foreach (var contour in contours.Value) { foreach (var point in contour.ContourPoints) { if (point.X < minX) { minX = point.X; } if (point.X > maxX) { maxX = point.X; } if (point.Y < minY) { minY = point.Y; } if (point.Y > maxY) { maxY = point.Y; } } } } minX = minX == double.MaxValue ? 0 : minX; minY = minY == double.MaxValue ? 0 : minY; minZ = minZ == int.MaxValue ? 0 : minZ; maxX = maxX == double.MinValue ? 0 : maxX; maxY = maxY == double.MinValue ? 0 : maxY; maxZ = maxZ == int.MinValue ? 0 : maxZ; return(new Region3D <int>((int)Math.Floor(minX), (int)Math.Floor(minY), minZ, (int)Math.Ceiling(maxX), (int)Math.Ceiling(maxY), maxZ)); }