예제 #1
0
        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,
            });
        }
예제 #2
0
        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);
        }
예제 #3
0
        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());
        }
예제 #4
0
파일: Matrix.cs 프로젝트: zzti/Evil-DICOM
        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);
        }
예제 #5
0
        /// <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);
        }
예제 #6
0
        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();
            }
        }
예제 #7
0
        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);
        }
예제 #8
0
        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());
        }
예제 #9
0
        public static double GetContourSliceThickness(this StructureMeta meta)
        {
            var zs = meta.SliceContours.Select(sc => sc.Z).Distinct().OrderBy(z => z).ToList();

            return(zs.Min());
        }
예제 #10
0
        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);
        }
예제 #11
0
 private ImageContours(StructureMeta sm, Matrix im)
 {
     _contours = sm.SliceContours;
     _im       = im;
 }