Пример #1
0
        public CalPAQ1(UISettings ui, FileData f, CalPAC categ = null) : base(ui, f)
        {
            try {
                // low-alv-des-high cut
                if (categ != null)                 // use alv des cutoffs from categorize class
                {
                    Alv_Log_Size = categ.p1Mean;
                    //Sac_Log_Size=categ.p2Mean;
                    //Des_Log_Size=categ.p3Mean;
                    Alv_Size = Math.Pow(10.0d, categ.p1Mean) - 1;
                    //Sac_size=Math.Pow(10.0d, categ.p2Mean)-1;
                    //Des_size=Math.Pow(10.0d, categ.p3Mean)-1;
                    //Alv_Cut=Math.Pow(10.0d, categ.Alv_Log_Cut)-1;
                    DucDes_Threshold = Math.Pow(10.0d, categ.c1_DucDes_CI95_1tail) - 1;
                    //Alv_cut=Alv_Cut/px2um2;
                }
                else                     // alv des cutoffs from ui
                {
                    DucDes_Threshold = Math.Pow(10.0d, ui.BlobDes) - 1;
                }
                DucDes_Log_Threshold = Math.Log10(DucDes_Threshold + 1);

                AreaComponentsLabeling aclabel = new AreaComponentsLabeling()
                {
                    Low  = (int)Math.Round(Low_Threshold / ui.um2px2),
                    High = (int)Math.Round(Math.Min(int.MaxValue, High_Threshold / ui.um2px2)),
                    Alv  = (int)Math.Round(DucDes_Threshold / ui.um2px2),                // use Des_cut to elliminate Sac color
                    Des  = (int)Math.Round(DucDes_Threshold / ui.um2px2)
                };
                Invert AFinvert = new Invert();
                UnmanagedResult = aclabel.Apply(AFinvert.Apply(UnmanagedBlackWhite));
                //Low_count = Low_sumArea = High_count = High_sumArea = 0;
                foreach (Blobx blob in aclabel.BlobCounter.blobs)
                {
                    if (blob.Area <= aclabel.Des)                     // alv/sac
                    {
                        AlvSac_count++; AlvSac_SumArea += ui.um2px2 * blob.Area; AlvSac_SumBoundary += ui.umpx * blob.Perimeter;
                    }
                    else                          // duct/des
                    {
                        DucDes_count++; DucDes_SumArea += ui.um2px2 * blob.Area; DucDes_SumBoundary += ui.umpx * blob.Perimeter;
                    }
                }

                Total_SumArea = ui.um2px2 * (UnmanagedMarkup.Width * UnmanagedMarkup.Height); // total area
                Lung_SumArea  = Total_SumArea - Low_SumArea - High_SumArea;                   // lung area
                Paren_SumArea = Lung_SumArea - NonParen_SumArea;                              // parenchymal area
                Tis_SumArea   = Paren_SumArea - AlvSac_SumArea - DucDes_SumArea;              // septum tissue

                AlvSac_Count    = 1000.0d * 1000.0d * AlvSac_count / Paren_SumArea;
                DucDes_Count    = 1000.0d * 1000.0d * DucDes_count / Paren_SumArea;
                AlvSac_Boundary = 1.0d * AlvSac_SumBoundary / Paren_SumArea;
                DucDes_Boundary = 1.0d * DucDes_SumBoundary / Paren_SumArea;
                AlvSac_Fraction = 1.0d * AlvSac_SumArea / Paren_SumArea;
                DucDes_Fraction = 1.0d * DucDes_SumArea / Paren_SumArea;           // is still better to divide by paren area

                Tis_Fraction     = 1.0d - AlvSac_Fraction - DucDes_Fraction;
                DucDes_Alv_Ratio = DucDes_Fraction / AlvSac_Fraction;

                StringBuilder header = new StringBuilder();
                header.Append($"{FileName}  ps: {ui.PixelScale:G2}/{ui.ResizeValue:G2} px/um" + $"\nduc/des thres:{DucDes_Log_Threshold:0.00} log\x2081\x2080µm\xB2");
                header.Append($"\nlung: {Lung_SumArea:G2}µm\xB2, {(1.0d*Lung_SumArea/Total_SumArea):0%} image (blw: {Low_SumArea/Total_SumArea:0%} ovr: {1.0d*High_SumArea/Total_SumArea:0%})");
                header.Append($"\nparenchyma: {Paren_SumArea:G2}µm\xB2, {(Paren_SumArea/Lung_SumArea):0%} lung (exc: {1.0d*NonParen_SumArea/Total_SumArea:0%})");
                header.Append($"\nseptum: {Tis_SumArea:G2}µm\xB2, {Tis_SumArea/Paren_SumArea:0%} paren (airspace: {(AlvSac_SumArea+DucDes_SumArea)/Total_SumArea:0%})");

                StringBuilder footer = new StringBuilder();
                if (Math.Abs(Alv_Size) > 0.01d)
                {
                    footer.Append($" AS:{Alv_Size:G2} (Size, µm\xB2)");
                }
                footer.Append($"\nASC:{AlvSac_Count:G2} DC:{DucDes_Count:G2} (Count\x2090: 1/mm\xB2)"
                              + $"\nASB:{AlvSac_Boundary:G2} DB:{DucDes_Boundary:G2} (Boundary\x2090, 1/µm)"
                              + $"\nASF:{AlvSac_Fraction:0%} DF:{DucDes_Fraction:0%} (Area\x2090 Fraction, %)"
                              + $"\nTF:{Tis_Fraction:0.0%} D2A:{DucDes_Alv_Ratio:F2} (Fraction, Ratio)");

                UnmanagedMarkup = UnmanagedImage.FromManagedImage(AddBlobText(UnmanagedMarkup.ToManagedImage(false), Color.Black, $"{header}", $"{footer}", null, null,     // ,blobs, blobDes.ToArray()
                                                                              (int)Math.Round(0.02d * UnmanagedMarkup.Width * Math.Sqrt(ui.ExportDetailRatio))));
                UnmanagedResult = UnmanagedImage.FromManagedImage(AddBlobText(UnmanagedResult.ToManagedImage(false), Color.PaleGreen, $"{header}", $"{footer}", null, null, // ,blobs, blobDes.ToArray()
                                                                              (int)Math.Round(0.02d * UnmanagedMarkup.Width * Math.Sqrt(ui.ExportDetailRatio))));
            } catch { throw new Exception("Error Occured During Airspace Quantification"); }
        }
Пример #2
0
        /// <summary>
        /// Plot calculated distribution with OxyPlot (type 0-null 1-size 2-area 3-combined)
        /// </summary>
        /// <param name="categ">categorized information CalBlobAC</param>
        /// <param name="type">0-null 1-size 2-area 3-combined</param>
        /// <returns></returns>
        public static PlotModel ToOxyPlot(this CalPAC categ, int type)
        {
            try {
                var plot = new PlotModel();
                switch (type)
                {
                case 1: plot.Subtitle = $"Size Distribution\n{categ.Grouping} (N={categ.N})"; break;

                case 2: plot.Subtitle = $"Area Distribution\n{categ.Grouping} (N={categ.N})"; break;

                case 3: plot.Subtitle = $"Size & Area-Weighted Size Distribution\n{categ.Grouping} (N={categ.N})"; break;

                default: plot.Subtitle = ""; break;
                }
                plot.Axes.Add(new LinearAxis {
                    Title = "Airspace log10 µm\xB2", Position = AxisPosition.Bottom, Minimum = 0, Maximum = 7, MajorStep = 1, MinorStep = 0.25, TickStyle = TickStyle.Inside
                });
                plot.Axes.Add(new LinearAxis {
                    Title = "Density", Position = AxisPosition.Left, Minimum = 0, Maximum = 1, MajorStep = 0.2, MinorStep = 0.05, TickStyle = TickStyle.Inside
                });
                var    fillsize = OxyColor.FromArgb(130, 0, 0, 230);
                var    fillarea = OxyColor.FromArgb(130, 225, 19, 2);
                var    outline = OxyColor.FromArgb(160, 0, 0, 0);
                var    draw1 = OxyColor.FromArgb(255, 79, 154, 6);
                var    draw2 = OxyColor.FromArgb(255, 220, 158, 30);
                var    draw3 = OxyColor.FromArgb(255, 204, 0, 0);
                double width = 0.05; double offset = 0.05;
                if (type == 1 || type == 3)             // size
                {
                    var histogram = new RectangleBarSeries()
                    {
                        Title = $"Size Dist (LogLikelihood={categ.gmm1Fit:G2})", FillColor = fillsize, StrokeColor = outline
                    };
                    for (int i = 0; i < categ.DistCount.Count; i++)
                    {
                        histogram.Items.Add(new RectangleBarItem(categ.DistCount[i][0] - width - offset, 0, categ.DistCount[i][0] + width - offset, categ.DistCount[i][1]));
                    }
                    plot.Series.Add(histogram);
                    plot.Series.Add(FormGaussian($"Population 1 (µ={categ.p1Mean:0.00}, σ={categ.p1Covariance:0.00}, λ={categ.p1Proportion:0.00})", draw1, 0, 10, categ.p1Mean, categ.p1Covariance, categ.p1Proportion));
                    plot.Annotations.Add(new LineAnnotation()
                    {
                        Type = LineAnnotationType.Vertical, X = categ.c1_DucDes_CI95_1tail, Text = $"x={categ.c1_DucDes_CI95_1tail:0.0}", Color = fillsize, StrokeThickness = 2
                    });
                }
                if (type == 2 || type == 3)             // area
                {
                    var histogram = new RectangleBarSeries()
                    {
                        Title = $"Area-Weighted Size Dist (LogLikelihood={categ.gmm2Fit:G2})", FillColor = fillarea, StrokeColor = outline
                    };
                    for (int i = 0; i < categ.DistArea.Count; i++)
                    {
                        histogram.Items.Add(new RectangleBarItem(categ.DistArea[i][0] - width + offset, 0, categ.DistArea[i][0] + width + offset, categ.DistArea[i][1]));
                    }
                    plot.Series.Add(histogram);
                    plot.Series.Add(FormGaussian($"Population 2 (µ={categ.p2Mean:0.00}, σ={categ.p2Covariance:0.00}, λ={categ.p2Proportion:0.00})", draw2, 0, 10, categ.p2Mean, categ.p2Covariance, categ.p2Proportion));
                    plot.Series.Add(FormGaussian($"Population 3 (µ={categ.p3Mean:0.00}, σ={categ.p3Covariance:0.00}, λ={categ.p3Proportion:0.00})", draw3, 0, 10, categ.p3Mean, categ.p3Covariance, categ.p3Proportion));
                    if (type == 3)
                    {
                        plot.Annotations.Add(new LineAnnotation()
                        {
                            Type = LineAnnotationType.Vertical, X = categ.c2_Sac_Log_Threshold, Text = $"x={categ.c2_Sac_Log_Threshold:0.0}", Color = OxyColor.FromArgb(130, 220, 158, 30), StrokeThickness = 2
                        });
                    }
                    plot.Annotations.Add(new LineAnnotation()
                    {
                        Type = LineAnnotationType.Vertical, X = categ.c2_DucDes_Log_Threshold, Text = $"x={categ.c2_DucDes_Log_Threshold:0.0}", Color = fillarea, StrokeThickness = 2
                    });
                }
                return(plot);
            } catch { throw new Exception("Error encountered generating histogram and distribution graph."); }
        }