/// <summary> /// Creates a radiotherapy structure from a set of contours, including the given rendering /// information (name of the contour, color to render in). /// </summary> /// <param name="contours">The contours and their rendering information.</param> /// <param name="dicomIdentifiers">The Dicom identifiers for the scan to which the contours belong.</param> /// <param name="volumeTransform">The Dicom-to-data transformation of the scan to which the contours belong.</param> /// <returns></returns> public static RadiotherapyStruct ContoursToRadiotherapyStruct(IEnumerable <ContourRenderingInformation> contours, IReadOnlyList <DicomIdentifiers> dicomIdentifiers, VolumeTransform volumeTransform) { var radiotherapyStruct = RadiotherapyStruct.CreateDefault(dicomIdentifiers); int roiNumber = 0; var nameConverter = new DicomPersonNameConverter("InnerEye", "CreateDataset", string.Empty, string.Empty, string.Empty); foreach (var contour in contours) { // ROIs need to start at 1 by DICOM spec roiNumber++; // Create contours - mapping each contour into the volume. var radiotherapyContour = RTStructCreator.CreateRadiotherapyContour( contour.Contour, dicomIdentifiers, volumeTransform, contour.Name, (contour.Color.R, contour.Color.G, contour.Color.B), roiNumber.ToString(), nameConverter, ROIInterpretedType.None ); radiotherapyStruct.Contours.Add(radiotherapyContour); } return(radiotherapyStruct); }
/// <summary> /// Creates a single Dicom file that contains a radiotherapy structure, /// derived from a set of contours and rendering information. /// </summary> /// <param name="contours">The contours and their rendering information.</param> /// <param name="dicomIdentifiers">The Dicom identifiers for the scan to which the contours belong.</param> /// <param name="volumeTransform">The Dicom-to-data transformation of the scan to which the contours belong.</param> /// <returns></returns> public static DicomFileAndPath ContoursToDicomRtFile(IEnumerable <ContourRenderingInformation> contours, IReadOnlyList <DicomIdentifiers> dicomIdentifiers, VolumeTransform volumeTransform) { var radiotherapyStruct = ContoursToRadiotherapyStruct(contours, dicomIdentifiers, volumeTransform); return(new DicomFileAndPath(RtStructWriter.GetRtStructFile(radiotherapyStruct), "RTStruct.dcm")); }
/// <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> /// Converts a set of application contours into DICOM RT objects ready for serialization /// </summary> /// <typeparam name="T"></typeparam> /// <param name="axialContours">The axial contours you wish to convert</param> /// <param name="identifiers">The set of identifiers, 1 for each slice in parentVolume</param> /// <param name="volumeTransform">The volume transform.</param> /// <returns></returns> public static List <DicomRTContourItem> ToDicomRtContours( this Microsoft.RTConvert.Contours.ContoursPerSlice axialContours, IReadOnlyList <DicomIdentifiers> identifiers, VolumeTransform volumeTransform) { if (identifiers == null || identifiers.Count == 0) { throw new ArgumentException(nameof(identifiers), "The identifiers cannot be null or empty"); } if (volumeTransform == null) { throw new ArgumentException(nameof(volumeTransform), "The volume cannot be null or empty"); } var resultList = new List <DicomRTContourItem>(); var tolerance = volumeTransform.SpacingZ / 2; // Iterate through the sets of contours per slice foreach (var tuple in axialContours) { // For this slice, compute the z-axis coordinate in the DICOM reference coordinate system var z = tuple.Key; var zAxisPhysicalCoordinate = (volumeTransform.DataToDicom * new Point3D(0, 0, z)).Z; // Locate the DICOM identifier containing this slice. Note that for non-axial volumes this is not the right test // but is sufficient for Axial volumes. var identifier = identifiers.FirstOrDefault(x => Math.Abs(x.Image.ImagePositionPatient.Z - zAxisPhysicalCoordinate) < tolerance); if (identifier == null) { throw new Exception("Invalid contour or image identifiers"); } // Reference the slice containing these contours by SopInstance UID var sopCommonInstance = identifier.Image.SopCommon; var contourImageSeq = new List <DicomRTContourImageItem>() { new DicomRTContourImageItem(sopCommonInstance.SopClassUid, sopCommonInstance.SopInstanceUid) }; // Iterate through the contour objects on this slice. foreach (var contour in tuple.Value) { // Convert the pixel based contour into the DICOM reference coordinate system and flatten to an arry of doubles. var allpoints = contour.ContourPoints.SelectMany( p => (volumeTransform.DataToDicom * new Point3D(p.X, p.Y, z)).Data).ToArray(); resultList.Add(new DicomRTContourItem( allpoints, contour.Length, ClosedPlanarString, contourImageSeq)); } } return(resultList); }