public static TargetIndices CalculateIndices(StructureMeta gtv, DoseMatrix dd, double prescriptionDose) { var cropped = dd.Clone(); cropped.CropMatrixToStructure(gtv, 20); var presVol = cropped.ConvertIsodoseLevelToMesh(prescriptionDose).CalculateVolumeCC(); var halfVol = cropped.ConvertIsodoseLevelToMesh(prescriptionDose / 2).CalculateVolumeCC(); var dvh = cropped.CalcDVH(); var points = dvh.GetDVHData().Points; var test = points.GetVolumeAtDose(prescriptionDose); var dosevol = dvh.GetDVHData().Points.GetVolumeAtDose(prescriptionDose) / 100 * cropped.VolumeCC(); var gradVol = dvh.GetDVHData().Points.GetVolumeAtDose(prescriptionDose / 2) / 100 * cropped.VolumeCC(); var isodoseDef = new IsodoseLevel() { Value = prescriptionDose, Color = new Scalar(0, 0, 255) }; var isoStructure = cropped.Find2DIsodoseLines(isodoseDef).First(); isoStructure.Look = StructureLooks.Purple; //var vol = isoStructure.CalculateVolumeCC(); //var gtvVol = gtv.CalculateVolumeCC(); var ci = presVol / 5;// gtvVol; //var ci2 = tvol / gtvVol; var gi = halfVol / dosevol; return(new TargetIndices() { Gradient = gi, RTOGCI = ci, }); }
public static DVH CalculateSDF_DVH(StructureMeta sm, DoseMatrix dm) { var cropDM = dm.Clone(); cropDM.CropMatrixToStructure(sm, 2); // cropDM.ShowAllSlices(); var sdf = sm.CalculateSDFMatrix(cropDM); cropDM.Resample(cropDM.XRes / 3, cropDM.YRes / 3, cropDM.ZRes / 3); sdf.Resample(sdf.XRes / 3, sdf.YRes / 3, sdf.ZRes / 3); var maxDose = cropDM.MaxDose; var voxelCC = cropDM.XRes / 10 * cropDM.YRes / 10 * cropDM.ZRes / 10; var doseUnit = dm.DoseUnit == DoseUnit.ABSOLUTE ? "Gy" : "%"; var dvh = new DVH(maxDose, voxelCC, doseUnit); var vol = 0.0; for (int z = 0; z < cropDM.DimensionZ; z++) { var zPos = cropDM.ImageToPatientTx(new Core.Helpers.Vector3(0, 0, z)).Z; var contours = new SliceContourMeta[] { sdf.FindStructureContour(zPos) }; vol += contours.Sum(c => c.CalculateArea()) * cropDM.ZRes; CalculateContoursDVH(contours, cropDM, dvh); } dvh.Volume = vol; return(dvh); }
public static DVHPoint[] CalculateMarchingDVH(StructureMeta sm, DoseMatrix dm) { var maxDose = dm.MaxDose; var resample = dm.ResampleMatrixToStructure(sm); var onlyStructure = resample.ExcludeOutsideStructure(sm); onlyStructure.CropMatrixToStructure(sm, 10); //for (int z = 0; z < onlyStructure.DimensionZ; z++) //{ // var slice = onlyStructure.GetZPlaneBySlice(z); // FloatMat.Show(slice); //} var points = new List <DVHPoint>(); for (double i = 0; i < maxDose; i += 0.5) { var mesh = MachingCubes.Calculate(onlyStructure, i); if (i == 3) { mesh.Export(@"F:\OneDrive\__RED_ION\Git\EvilDICOM.CV\DICOMCV.Tests\gtv3dd.obj"); } points.Add(new DVHPoint(new Dose(i, "Gy"), new Volume(mesh.CalculateVolumeCC(), "cc"))); } return(points.ToArray()); }
public Matrix MaskToStructure(StructureMeta str) { Matrix mat = EmptyClone(); for (int z = 0; z < DimensionZ; z++) { var zPos = ImageToPatientTx(new Vector3(0, 0, z)).Z; var contour = str.SliceContours.FirstOrDefault(sc => sc.Z == zPos); using (var slice = new Mat(mat.DimensionY, mat.DimensionX, MatType.CV_32FC1, new Scalar(1))) { using (var masked = new Mat(mat.DimensionY, mat.DimensionX, MatType.CV_32FC1, new Scalar(-1))) { using (var mask = new Mat(slice.Rows, slice.Cols, MatType.CV_8UC1, new Scalar(0))) { if (contour != null) { contour.MaskImageFast(mask, PatientTransformMatrix, 255); slice.CopyTo(masked, mask); } mat.SetZPlaneBySlice(masked, z); } } } } return(mat); }
/// <summary> /// Creates a rough approximation of the structure inside a given 3d matrix. Useful for calculating bounds /// </summary> /// <typeparam name="T"></typeparam> /// <param name="sm"></param> /// <param name="im"></param> /// <returns></returns> public static ImageContours BuildFromImage(StructureMeta sm, Matrix im) { var ic = new ImageContours(sm, im); ic.ConstructStructureSlicesOnImage(im); return(ic); }
public static void CropMatrixToStructure(Matrix m, StructureMeta contour, double marginMM) { var allPoints = contour.SliceContours.SelectMany(sc => sc.ContourPoints).ToList(); var minPointX = allPoints.Min(pt => pt.X) - marginMM; var maxPointX = allPoints.Max(pt => pt.X) + marginMM; var minPointY = allPoints.Min(pt => pt.Y) - marginMM; var maxPointY = allPoints.Max(pt => pt.Y) + marginMM; var minPointZ = contour.SliceContours.Min(sc => sc.Z) - marginMM; var maxPointZ = contour.SliceContours.Max(sc => sc.Z) + marginMM; var minCorner = new Point3d(minPointX, minPointY, minPointZ); var maxCorner = new Point3d(maxPointX, maxPointY, maxPointZ); var imageCoordMinCorner = m.PatientTransformMatrix.Inv().ToMat().TransformPoint3d(minCorner); var imageCoordMaxCorner = m.PatientTransformMatrix.Inv().ToMat().TransformPoint3d(maxCorner); var minX = (int)Math.Floor(Math.Min(imageCoordMinCorner.X, imageCoordMaxCorner.X)); minX = minX < 0 ? 0 : minX; var minY = (int)Math.Floor(Math.Min(imageCoordMinCorner.Y, imageCoordMaxCorner.Y)); minY = minY < 0 ? 0 : minY; var minZ = (int)Math.Floor(Math.Min(imageCoordMinCorner.Z, imageCoordMaxCorner.Z)); minZ = minZ < 0 ? 0 : minZ; var maxX = (int)Math.Ceiling(Math.Max(imageCoordMinCorner.X, imageCoordMaxCorner.X)); maxX = maxX > (m.DimensionX - 1) ? m.DimensionX : maxX; var maxY = (int)Math.Ceiling(Math.Max(imageCoordMinCorner.Y, imageCoordMaxCorner.Y)); maxY = maxY > (m.DimensionY - 1) ? m.DimensionY : maxY; var maxZ = (int)Math.Ceiling(Math.Max(imageCoordMinCorner.Z, imageCoordMaxCorner.Z)); maxZ = maxZ > (m.DimensionZ - 1) ? m.DimensionZ : maxZ; var rangeX = new OpenCvSharp.Range(minX, maxX); var rangeY = new OpenCvSharp.Range(minY, maxY); var rangeZ = new OpenCvSharp.Range(minZ, maxZ); using (var cropped = new Mat(m._mat, rangeZ, rangeY, rangeX)) { m.DimensionX = maxX - minX; m.DimensionY = maxY - minY; m.DimensionZ = maxZ - minZ; var xOffset = minX * m.XRes; var yOffset = minY * m.YRes; var zOffset = minZ * m.ZRes; var txOffset = Transform.TransformOffset(new Vector3(xOffset, yOffset, zOffset), m.ImageOrientation); m.Origin = m.Origin + txOffset; var mat = cropped.Clone(); m._mat.Dispose(); m._mat = mat; m.CalculatePatientTransformMatrix(); m.CalculateBounds(); } }
public static DVH CalculateDVH(StructureMeta sm, DoseMatrix dm) { var maxDose = dm.MaxDose; var voxelCC = dm.XRes / 10 * dm.YRes / 10 * dm.ZRes / 10; var doseUnit = dm.DoseUnit == DoseUnit.ABSOLUTE ? "Gy" : "%"; var dvh = new DVH(maxDose, voxelCC, doseUnit); var zSlices = sm.SliceContours.GroupBy(sc => sc.Z).OrderBy(grp => grp.Key); foreach (var slice in zSlices) { var z = slice.Key; CalculateContoursDVH(slice, dm, dvh); } return(dvh); }
public static StructureMeta[] Find2DIsodoseLines(this Matrix matrix, params IsodoseLevel[] levels) { List <StructureMeta> metas = new List <StructureMeta>(); foreach (var level in levels) { var meta = new StructureMeta() { StructureId = level.Value.ToString(), StructureName = level.Value.ToString() }; meta.Color = level.Color; for (int z = 0; z < matrix.DimensionZ; z++) { using (var mat = matrix.GetZPlaneBySlice(z)) { var ctrs = mat.Find2DIsodoseLine(level); if (ctrs.Any()) { foreach (var contour in ctrs) { var allPoints = new Vec4f[contour.Length]; var points = contour.Select(c => new Vec4f(c.X, c.Y, z, 1)); using (var pointMat = new Mat <float>(new[] { contour.Length }, points.ToArray())) { var txPointMat = pointMat.Transform(matrix.PatientTransformMatrix); txPointMat.GetArray(out allPoints); } var sliceContour = new SliceContourMeta(); var points3D = allPoints.Select(a => new Point3f(a.Item0, a.Item1, a.Item2)).ToList(); points3D.ForEach(sliceContour.AddPoint); meta.SliceContours.Add(sliceContour); } } } } metas.Add(meta); } return(metas.ToArray()); }
public static double GetContourSliceThickness(this StructureMeta meta) { var zs = meta.SliceContours.Select(sc => sc.Z).Distinct().OrderBy(z => z).ToList(); return(zs.Min()); }
public static StructureSetMeta ParseDICOM(string file) { var sm = new StructureSetMeta(); var dcm = DICOMObject.Read(file); var sel = dcm.GetSelector(); var metas = sel.StructureSetROISequence.Items.Select(i => { var meta = new StructureMeta(); meta.StructureId = i.GetSelector().ROIName?.Data; meta.ROINumber = i.GetSelector().ROINumber.Data; return(meta); }); foreach (var meta in metas) { try { var comatch = sel.ROIContourSequence.Items.FirstOrDefault(i => i.GetSelector().ReferencedROINumber.Data == meta.ROINumber); var romatch = sel.RTROIObservationsSequence.Items.FirstOrDefault(i => i.GetSelector().ReferencedROINumber.Data == meta.ROINumber); var colorValues = comatch.GetSelector().ROIDisplayColor.Data_; var color = new Vec3b((byte)colorValues[0], (byte)colorValues[1], (byte)colorValues[2]); var dicomType = romatch.GetSelector().RTROIInterpretedType.Data; var name = romatch.GetSelector().ROIObservationLabel.Data; meta.StructureName = name; meta.Color = new Scalar(colorValues[0], colorValues[1], colorValues[2]); var hasContours = comatch.GetSelector().ContourSequence != null; if (!hasContours) { continue; } //HAS CONTOURS - SET COLOR BYTES IN MATRIX foreach (var slice in comatch.GetSelector().ContourSequence.Items) { var contours = slice.GetSelector().ContourData.Data_; if (contours.Count % 3 != 0) { _logger.LogWarning($"Slice for structure {meta.StructureId} has {contours.Count} contour points. Not divisible by 3! Can't process."); continue; } try { var contour = new SliceContourMeta(); for (int i = 0; i < contours.Count; i += 3) { var contourPt = new OpenCvSharp.Point3f((float)contours[i + 0], (float)contours[i + 1], (float)contours[i + 2]); contour.AddPoint(contourPt); } meta.SliceContours.Add(contour); meta.DICOMType = dicomType; } catch (Exception e) { _logger.LogError(e.ToString()); } } //OrganizeContours - contours containing other contours (holes and fills) will be organized //into children. All other contours are outermost contours and not children of any other var slices = meta.SliceContours.GroupBy(s => s.Z).ToList(); foreach (var slice in slices) { var sliceContours = slice.OrderByDescending(s => s.CalculateArea()).ToList(); ContourHelper.OrganizeIntoChildren(sliceContours[0], sliceContours.Skip(1)); } sm.Structures.Add(meta.StructureId, meta); } catch (Exception e) { _logger.LogError(e, $"Could not add structure {meta.StructureId}"); } } return(sm); }
private ImageContours(StructureMeta sm, Matrix im) { _contours = sm.SliceContours; _im = im; }