public void LoadImageAndContours()
        {
            var acceptanceTests = new ModerateGeometricAcceptanceTest(string.Empty, string.Empty);
            var medicalVolume   = MedIO.LoadAllDicomSeriesInFolderAsync(TestData.GetFullImagesPath(@"sample_dicom"), acceptanceTests).Result.First().Volume;

            var volumes = new Dictionary <string, ContourStatistics>()
            {
                { "Bladder", new ContourStatistics(95.87, -1000.0, 0) },
                { "Femur_L", new ContourStatistics(205.04, -1000.0, 0) },
            };

            var readOnlyVolume = new ReadOnlyVolume3D <short>(medicalVolume.Volume);

            for (int i = 0; i < medicalVolume.Struct.Contours.Count; i++)
            {
                var contour       = medicalVolume.Struct.Contours[i];
                var name          = contour.StructureSetRoi.RoiName;
                var contourVolume = contour.Contours.ToVolume3D(medicalVolume.Volume);
                Console.WriteLine($"Starting checks for contour {name}");
                var contourStatistics = ContourStatistics.FromVolumeAndMask(readOnlyVolume, contourVolume);
                Assert.AreEqual(volumes[contour.StructureSetRoi.RoiName].SizeInCubicCentimeters, contourStatistics.SizeInCubicCentimeters, 1e-1, $"Size for contour {name}");
                Assert.AreEqual(volumes[contour.StructureSetRoi.RoiName].VoxelValueMean, contourStatistics.VoxelValueMean, 1e-1, $"Mean for contour {name}");
                Assert.AreEqual(volumes[contour.StructureSetRoi.RoiName].VoxelValueStandardDeviation, contourStatistics.VoxelValueStandardDeviation, 1e-1, $"Std for contour {name}");
            }
        }
예제 #2
0
        /// <summary>
        /// Computes an instance of contour statistics, <see cref="ContourStatistics"/>, from those voxels
        /// of the <paramref name="originalVolume"/> where the mask volume attains the foreground value.
        /// </summary>
        /// <param name="image"></param>
        /// <param name="mask"></param>
        /// <param name="foreground"></param>
        /// <returns></returns>
        public static ContourStatistics FromVolumeAndMask(ReadOnlyVolume3D <short> image, Volume3D <byte> mask, byte foreground = 1)
        {
            image = image ?? throw new ArgumentNullException(nameof(image));
            mask  = mask ?? throw new ArgumentNullException(nameof(mask));
            if (mask.Length != image.Length)
            {
                throw new ArgumentException("Image and mask must have the same length", nameof(image));
            }

            double mean     = 0;
            double variance = 0;
            double sum      = 0;
            ulong  count    = 0;

            // StreamingStatistics.MeanVariance
            for (int i = 0; i < image.Length; i++)
            {
                if (mask[i] == foreground)
                {
                    count++;
                    double xi = image[i];
                    sum += xi;
                    var diff = (count * xi) - sum;
                    if (count > 1)
                    {
                        variance += (diff * diff) / (count * (count - 1));
                    }

                    mean += (xi - mean) / count;
                }
            }

            var volumeSizeInCC    = count * image.VoxelVolume / 1000d;
            var standardDeviation = count == 0 ? 0 : Math.Sqrt(variance / count);

            return(new ContourStatistics(volumeSizeInCC, mean, standardDeviation));
        }