private ObjectLayer Execute1stLevelSegmentation(GrayscaleProcessor gp, GrayscaleProcessor gpSobel, GrayscaleProcessor gpH)
        {
            ContourBasedSegmentation cbs = new ContourBasedSegmentation();

            cbs.CreatePrimarySegmentation(gp, MAX_CONTOURLENGTH);

            cbs.EvaluateContours(c =>
            {
                if (ContourProperties.FromContour(c).Convexity < 0.95)
                {
                    return(-1);
                }

                return(ContourValue.GetValue(c, gpSobel));
            });

            ObjectLayer layer = cbs.CreateLayer(MIN_CONTOURLENGTH, int.MaxValue);

            layer = new ContourOptimizer().RemoveNonCompactPixels(layer, 3);

            layer = layer.CreateAbove(obj =>
            {
                return(this.GetContourGradient(obj, gp) < 0);
            });

            //layer=new ConcaveObjectSeparation().Execute(layer, 0.33, true);

            return(layer);
        }
Exemple #2
0
    private int[] GetHistogram(ImageObject obj, GrayscaleProcessor p)
    {
        Rectangle boundingBox = obj.Contour.FindBoundingBox();

        int y2 = boundingBox.Bottom;
        int x2 = boundingBox.Right;
        int y1 = boundingBox.Y;
        int x1 = boundingBox.X;

        int[] histogram = new int[256];

        for (int dy = y1; dy < y2; dy++)
        {
            for (int dx = x1; dx < x2; dx++)
            {
                if (obj.Layer.Map[dx, dy] != obj.Id)
                {
                    continue;
                }

                histogram[p[dx, dy]]++;
            }
        }

        return(histogram);
    }
Exemple #3
0
        /// <summary>
        /// Convert image to color space of known stain.
        /// </summary>
        /// <param name="source">Source image.</param>
        /// <param name="stain">Known stain.</param>
        /// <param name="channel">Channel of stain. Takes int 0-2.</param>
        /// <returns>Color deconvoluted image.</returns>
        public static Bitmap ColorDeconvolution(Bitmap source, ColorDeconvolution.KnownStain stain, int channel)
        {
            using (var image = source.Clone() as Bitmap)
            {
                BitmapProcessor    bitmapProcessor    = new BitmapProcessor(source);
                ColorDeconvolution colorDeconvolution = new ColorDeconvolution();
                GrayscaleProcessor gpDeconvoluted     = null;
                if (channel == 0)
                {
                    gpDeconvoluted = colorDeconvolution.Get1stStain(bitmapProcessor, stain);
                }
                else if (channel == 1)
                {
                    gpDeconvoluted = colorDeconvolution.Get2ndStain(bitmapProcessor, stain);
                }
                else if (channel == 2)
                {
                    gpDeconvoluted = colorDeconvolution.Get3rdStain(bitmapProcessor, stain);
                }
                else
                {
                    return(null);
                }

                Bitmap result = gpDeconvoluted.Bitmap.Clone() as Bitmap;
                gpDeconvoluted.Dispose();
                return(result);
            }
        }
 private static void calculateFeatures(ObjectLayer objectLayer, Bitmap source)
 {
     using (var grayscaleProcessor = new GrayscaleProcessor(source, RgbToGrayscaleConversion.Mean)
     {
         WriteBack = false
     }) MeanIntensity.ProcessLayer(objectLayer, grayscaleProcessor);
     foreach (var imageObject in objectLayer.Objects)
     {
         imageObject.Features.Add(new AreaOfContour(ContourProperties.FromContour(imageObject.Contour)));
     }
 }
        private IEnumerable <Tuple <Bitmap, string, int> > process()
        {
            using (var source = this.DisplayedImage.Clone() as Bitmap){
                var gspR = new GrayscaleProcessor(source.Clone() as Bitmap, RgbToGrayscaleConversion.JustReds);
                gspR.Dispose();
                yield return(Tuple.Create(gspR.Bitmap, "Red", 128));

                var gpDAB = new ColorDeconvolution().Get2ndStain(source, ColorDeconvolution.KnownStain.HaematoxylinDAB);
                gpDAB.Dispose();
                yield return(Tuple.Create(gpDAB.Bitmap, "DAB", 128));
            }
        }
Exemple #6
0
 protected override void OnLoad(EventArgs e)
 {
     base.OnLoad(e);
     this.CreateTabContainer("Deconvolution");
     this.TabContainer.Enabled = true;
     this.deconvolutedImageBox = new ImageListBox(() => this.DisplayedImage, this.SetDisplayedImage)
     {
         Parent = this.TabContainer, Height = 100
     };
     (new Button {
         Parent = this.TabContainer, Text = "deconvolute", Dock = DockStyle.Top
     }).Click += delegate {
         this.deconvolutedImageBox.Init();
         foreach (var tuple in this.process())
         {
             var map = new Map(tuple.Item1.Width, tuple.Item1.Height);
             if (tuple.Item2 != "Blue")
             {
                 using (var gsp = new GrayscaleProcessor(tuple.Item1, RgbToGrayscaleConversion.JustReds))
                 {
                     gsp.WriteBack = false;
                     foreach (var grayscalePixel in gsp.Pixels())
                     {
                         map[grayscalePixel.X, grayscalePixel.Y] = grayscalePixel.V > tuple.Item3 ? 1u : 0u;
                     }
                 }
             }
             else
             {
                 using (var gsp = new  GrayscaleProcessor(tuple.Item1, RgbToGrayscaleConversion.JustReds))
                 {
                     gsp.WriteBack = false;
                     foreach (var grayscalePixel in gsp.Pixels())
                     {
                         map[grayscalePixel.X, grayscalePixel.Y] = 1u;
                     }
                 }
             }
             var layer = new ConnectedComponentCollector().Execute(map);
             layer.Name = tuple.Item2;
             this.addLayer(layer, true);
             this.deconvolutedImageBox.Add(tuple.Item1, tuple.Item2);
         }
     };
     new Button {
         Text = "goto zoom", Parent = this.TabContainer, Dock = DockStyle.Top
     }.Click += delegate { WsiInterop.Navigation.Goto((float)this.zoomNumericUpDown.Value); };
     this.zoomNumericUpDown = new NumericUpDown()
     {
         Parent = this.TabContainer, Dock = DockStyle.Top, Minimum = 0, Maximum = 1, Value = 0.5M, DecimalPlaces = 1, Increment = 0.1M
     };
 }
        private void PerformImageAnalysis()
        {
            if (WsiComposite.Tile.WsiBox.Image == null) return;

              GrayscaleProcessor p = new GrayscaleProcessor(WsiComposite.Tile.WsiBox.Image, RgbToGrayscaleConversion.Mean);
              p.WriteBack = false;

              ObjectLayer layer = new ThresholdSegmentation().Execute(p);

              p.Dispose();

              WsiComposite.Tile.WsiBox.ObjectLayer = layer;
        }
Exemple #8
0
    private double GetContourGradient(ImageObject obj, GrayscaleProcessor p)
    {
        int[] nX = { +1, 0, -1, 0 };
        int[] nY = { 0, +1, 0, -1 };

        int height = p.Height;
        int width  = p.Width;

        double sumInner = 0.0, sumOuter = 0.0;
        double numInner = 0.0, numOuter = 0.0;

        for (int i = 0; i < obj.Contour.Length; i++)
        {
            Point pI = obj.Contour[i];

            for (int j = 0; j < 4; j++)
            {
                int x = pI.X + nX[j];
                int y = pI.Y + nY[j];

                if (x < 0 || y < 0 || x >= width || y >= height)
                {
                    continue;
                }

                if (obj.Contour.Contains(x, y))
                {
                    continue;
                }

                UInt32 intensity = p.GetPixel(x, y);

                if (obj.Layer.Map[x, y] == obj.Id)
                {
                    sumInner += intensity;
                    numInner++;
                }
                else
                {
                    sumOuter += intensity;
                    numOuter++;
                }
            }
        }

        double meanInner = sumInner / numInner;
        double meanOuter = sumOuter / numOuter;

        return(meanInner - meanOuter);
    }
        private static ObjectLayer createLayer(Bitmap bitmap, int threshold, string name)
        {
            var map = new Map(bitmap.Width, bitmap.Height);

            using (var gsp = new GrayscaleProcessor(bitmap, RgbToGrayscaleConversion.JustReds)){
                gsp.WriteBack = false;
                foreach (var grayscalePixel in gsp.Pixels())
                {
                    map[grayscalePixel.X, grayscalePixel.Y] = grayscalePixel.V > threshold?1u:0u;
                }
            }
            var layer = new ConnectedComponentCollector().Execute(map);

            layer.Name = name;
            return(layer);
        }
        public ObjectLayer Execute(Bitmap image)
        {
            var m = new Map(image.Width, image.Height);

            using (var gp = new GrayscaleProcessor(image.Clone() as Bitmap, RgbToGrayscaleConversion.Mean))
                for (var x = 0; x < image.Width; x++)
                {
                    for (var y = 0; y < image.Height; y++)
                    {
                        m[x, y] = gp.GetPixel(x, y) < 200?0u:1u;
                    }
                }
            var layer = new ConnectedComponentCollector().Execute(m);

            layer.Name = "lumina";
            return(layer);
        }
Exemple #11
0
    private ObjectLayer Execute1stLevelSegmentation(GrayscaleProcessor p, GrayscaleProcessor pSobel)
    {
        ContourBasedSegmentation cbs = new ContourBasedSegmentation();

        cbs.CreatePrimarySegmentation(p, MAX_CONTOURLENGTH);

        cbs.EvaluateContours(pSobel);

        ObjectLayer layer = cbs.CreateLayer();

        layer = layer.CreateAbove(obj =>
        {
            return(GetContourGradient(obj, p) > 0);
        });

        return(layer);
    }
Exemple #12
0
    private ObjectLayer Execute2ndLevelSegmentation(ObjectLayer l1stLevel, GrayscaleProcessor p)
    {
        ObjectLayer layer = l1stLevel.CreateAbove(obj =>
        {
            return(true);
        });

        double[] background = GetBackgroundHistogram(layer, p);
        double[] foreground = GetForegroundHistogram(layer, p);

        while (true)
        {
            bool removed = false;

            layer = layer.CreateAbove(obj =>
            {
                int[] histogram = GetHistogram(obj, p);

                double ratioForeground = GetRatioForeground(histogram, foreground, background);

                if (ratioForeground > 0.5)
                {
                    return(true);
                }

                for (int i = 0; i < 256; i++)
                {
                    int val = histogram[i];

                    background[i] += val;
                    foreground[i] -= val;
                }

                removed = true;

                return(false);
            });

            if (!removed)
            {
                break;
            }
        }

        return(layer);
    }
        private Contour[] Sort(Contour[] contours, GrayscaleProcessor gpSobel, GrayscaleProcessor gpH, float targetArea)
        {
            List <ContourDataComposite <double> > valuedContours = new List <ContourDataComposite <double> >();

            Parallel.For(0, contours.Length, i =>
            {
                Contour c = contours[i];

                double value = this.GetContourValue(c, gpSobel, gpH, targetArea);

                if (value <= 0)
                {
                    return;
                }

                lock (valuedContours)
                {
                    valuedContours.Add(new ContourDataComposite <double>(c, value));
                }
            });

            valuedContours.Sort(delegate(ContourDataComposite <double> c1, ContourDataComposite <double> c2)
            {
                if (c1.Data > c2.Data)
                {
                    return(-1);
                }
                if (c1.Data < c2.Data)
                {
                    return(1);
                }

                return(0);
            });

            contours = new Contour[valuedContours.Count];

            for (int i = 0; i < valuedContours.Count; i++)
            {
                contours[i] = valuedContours[i].Contour;
            }

            return(contours);
        }
Exemple #14
0
    private double[] GetBackgroundHistogram(ObjectLayer layer, GrayscaleProcessor p)
    {
        double[] histogram = new double[256];

        for (int dy = 0; dy < p.Height; dy++)
        {
            for (int dx = 0; dx < p.Width; dx++)
            {
                if (layer.Map[dx, dy] != 0)
                {
                    continue;
                }

                histogram[p[dx, dy]]++;
            }
        }

        return(histogram);
    }
        private double GetContourValue(Contour c, GrayscaleProcessor gpSobel, GrayscaleProcessor gpH, float targetArea)
        {
            double h = MeanIntensityOnContour.GetValue(c, gpH);

            ContourProperties cp = ContourProperties.FromContour(c);

            float area = Math.Min(cp.Area, targetArea) / targetArea;

            if (cp.Convexity < 0.9 && cp.Area < targetArea)
            {
                area = 1F / targetArea;
            }

            float convexity = cp.Convexity * cp.Convexity;

            double color = h / 255.0;

            return(color * area * convexity * ContourValue.GetValue(c, gpSobel));
        }
        private static ObjectLayer createLayer(Bitmap source)
        {
            var minContourLength         = 20;
            var maxContourLength         = 200;
            var contourBasedSegmentation = new ContourBasedSegmentation();

            using (var grayscaleProcessor = new GrayscaleProcessor(source, RgbToGrayscaleConversion.Mean)
            {
                WriteBack = false
            }){
                contourBasedSegmentation.CreatePrimarySegmentation(grayscaleProcessor, maxContourLength, true);
                new SobelEdgeDetector().Execute(grayscaleProcessor);
                contourBasedSegmentation.EvaluateContours(grayscaleProcessor);
            }
            var layer = contourBasedSegmentation.CreateLayer(minContourLength, maxContourLength);

            layer.Name = "Contour Based Segmentation (minContourLength=" + minContourLength + ", maxContourLength=" + maxContourLength + ")";
            calculateFeatures(layer, source);
            return(layer);
        }
        public static IResult <bool> Execute(Bitmap image)
        {
            var r = new Result <bool>();

            using (var source = image.Clone() as Bitmap){
                var gspR = new GrayscaleProcessor(source.Clone() as Bitmap, RgbToGrayscaleConversion.JustReds);
                gspR.Dispose();
                r.DebugBitmaps.Add(Tuple.Create(gspR.Bitmap, "Red"));
                r.DebugLayers.Add(createLayer(gspR.Bitmap, RedThreshold, "Red"));
                r.DebugVariables.Add("RedThreshold", RedThreshold);
                var gpDAB = new SharpAccessory.Imaging.Filters.ColorDeconvolution().Get2ndStain(source, SharpAccessory.Imaging.Filters.ColorDeconvolution.KnownStain.HaematoxylinDAB);
                gpDAB.Dispose();
                r.DebugBitmaps.Add(Tuple.Create(gpDAB.Bitmap, "DAB"));
                var dabLayer = createLayer(gpDAB.Bitmap, DabThreshold, "DAB");
                r.DebugLayers.Add(dabLayer);
                r.DebugVariables.Add("DabThreshold", DabThreshold);
                r.Value = 0 < dabLayer.Objects.Count;
            }
            return(r);
        }
        private double[] GetForegroundHistogram(ObjectLayer layer, GrayscaleProcessor p)
        {
            double[] histogram = new double[256];

            Parallel.For(0, layer.Objects.Count, i =>
            {
                int[] objHistogram = this.GetHistogram(layer.Objects[i], p);

                lock (histogram)
                {
                    for (int j = 0; j < 256; j++)
                    {
                        int value = objHistogram[j];

                        histogram[j] += value;
                    }
                }
            });

            return(histogram);
        }
        public override ProcessResult Execute(ProcessExecutionParams p)
        {
            GrayscaleProcessor gpH = new ColorDeconvolution().Get1stStain(p.Bitmap, ColorDeconvolution.KnownStain.HaematoxylinEosin);

            GrayscaleProcessor gp = new GrayscaleProcessor(p.Bitmap, RgbToGrayscaleConversion.JustReds);

            GrayscaleProcessor gpSobel = (GrayscaleProcessor)gp.Clone();

            new MeanFilter().Execute(gp, new Size(3, 3));

            new SobelEdgeDetector().Execute(gpSobel);

            new MinimumFilter().Execute(gpH, new Size(3, 3));

            new PixelInverter().Execute(gpH);

            ObjectLayer l1stLevel = this.Execute1stLevelSegmentation(gp, gpSobel, gpH);

            float targetArea = this.GetTargetArea(l1stLevel);

            ObjectLayer l2ndLevel = this.Execute2ndLevelSegmentation(gp, gpSobel, gpH, targetArea);

            ObjectLayer l3rdLevel = this.Execute3rdLevelSegmentation(l2ndLevel, gpSobel, gpH, targetArea);

            gpSobel.WriteBack = false;
            gpH.WriteBack     = false;
            gp.WriteBack      = false;

            gpSobel.Dispose();
            gpH.Dispose();
            gp.Dispose();

            gpSobel.Bitmap.Dispose();
            gpH.Bitmap.Dispose();

            l3rdLevel.Name = "Image Analysis";

            return(new ProcessResult(new ObjectLayer[] { l3rdLevel }));
        }
        private double[] GetBackgroundHistogram(ObjectLayer layer, GrayscaleProcessor p)
        {
            Map map = new Map(p.Width, p.Height);

            for (int dy = 0; dy < p.Height; dy++)
            {
                for (int dx = 0; dx < p.Width; dx++)
                {
                    if (layer.Map[dx, dy] == 0)
                    {
                        map[dx, dy] = 1;
                    }
                }
            }

            double[,] distanceMap = new DistanceTransformation().Execute(map);

            double[] histogram = new double[256];

            for (int dy = 0; dy < p.Height; dy++)
            {
                for (int dx = 0; dx < p.Width; dx++)
                {
                    if (map[dx, dy] == 0)
                    {
                        continue;
                    }

                    if (distanceMap[dx, dy] < 3)
                    {
                        continue;
                    }

                    histogram[p[dx, dy]]++;
                }
            }

            return(histogram);
        }
        public override ProcessResult Execute(ProcessExecutionParams p)
        {
            GrayscaleProcessor gpH = new ColorDeconvolution().Get1stStain(p.Bitmap, ColorDeconvolution.KnownStain.HaematoxylinEosin);

              GrayscaleProcessor gp = new GrayscaleProcessor(p.Bitmap, RgbToGrayscaleConversion.JustReds);

              GrayscaleProcessor gpSobel = (GrayscaleProcessor)gp.Clone();

              new MeanFilter().Execute(gp, new Size(3, 3));

              new SobelEdgeDetector().Execute(gpSobel);

              new MinimumFilter().Execute(gpH, new Size(3, 3));

              new PixelInverter().Execute(gpH);

              ObjectLayer l1stLevel = this.Execute1stLevelSegmentation(gp, gpSobel, gpH);

              float targetArea = this.GetTargetArea(l1stLevel);

              ObjectLayer l2ndLevel = this.Execute2ndLevelSegmentation(gp, gpSobel, gpH, targetArea);

              ObjectLayer l3rdLevel = this.Execute3rdLevelSegmentation(l2ndLevel, gpSobel, gpH, targetArea);

              gpSobel.WriteBack = false;
              gpH.WriteBack = false;
              gp.WriteBack = false;

              gpSobel.Dispose();
              gpH.Dispose();
              gp.Dispose();

              gpSobel.Bitmap.Dispose();
              gpH.Bitmap.Dispose();

              l3rdLevel.Name = "Image Analysis";

              return new ProcessResult(new ObjectLayer[] { l3rdLevel });
        }
        private ObjectLayer Execute3rdLevelSegmentation(ObjectLayer l2ndLevel, GrayscaleProcessor gpSobel, GrayscaleProcessor gpH, float targetArea)
        {
            List <Contour> finalContours = new List <Contour>();

            for (int i = 0; i < l2ndLevel.Objects.Count; i++)
            {
                finalContours.Add(l2ndLevel.Objects[i].Contour);
            }

            double[] hBackground = this.GetBackgroundHistogram(l2ndLevel, gpH);
            double[] hForeground = this.GetForegroundHistogram(l2ndLevel, gpH);

            Parallel.For(0, l2ndLevel.Objects.Count, i =>
            {
                ImageObject obj = l2ndLevel.Objects[i];

                ContourProperties cp = ContourProperties.FromContour(obj.Contour);

                obj.Features.Add(new Feature("Area", cp.Area));
            });

            Map map = new Map(gpSobel.Width, gpSobel.Height);

            Parallel.For(0, gpH.Height, dy =>
            {
                for (int dx = 0; dx < gpH.Width; dx++)
                {
                    UInt32 h = gpH[dx, dy];

                    if (hForeground[h] <= hBackground[h])
                    {
                        continue;
                    }

                    UInt32 id = l2ndLevel.Map[dx, dy];

                    if (id != 0)
                    {
                        ImageObject obj = l2ndLevel.Objects.GetObjectById(id);

                        double area = obj.Features["Area"].Value;

                        if (area > 0.33 * targetArea)
                        {
                            continue;
                        }
                    }

                    map[dx, dy] = 0xffffffff;
                }
            });

            ObjectLayer layer = new ConnectedComponentCollector().Execute(map);

            layer = new ContourOptimizer().RemoveNonCompactPixels(layer, 3);

            for (int i = 0; i < layer.Objects.Count; i++)
            {
                finalContours.Add(layer.Objects[i].Contour);
            }

            Contour[] contours = this.Sort(finalContours.ToArray(), gpSobel, gpH, targetArea);

            layer = this.CreateLayer(gpSobel.Width, gpSobel.Height, contours);

            Map finalMap = new Map(layer.Map, false);

            for (int dy = 0; dy < gpH.Height; dy++)
            {
                for (int dx = 0; dx < gpH.Width; dx++)
                {
                    if (l2ndLevel.Map[dx, dy] != 0)
                    {
                        continue;
                    }

                    if (map[dx, dy] != 0)
                    {
                        continue;
                    }

                    finalMap[dx, dy] = 0;
                }
            }

            layer = new ConnectedComponentCollector().Execute(finalMap);

            layer = new ContourOptimizer().RemoveNonCompactPixels(layer, 3);

            //layer=new ConcaveObjectSeparation().Execute(layer, 0.33, true);

            double minArea = Math.Max(0.1 * targetArea, MIN_AREA);

            layer = layer.CreateAbove(obj =>
            {
                float area = ContourProperties.FromContour(obj.Contour).Area;

                return(area > minArea);
            });

            layer = this.RefillContours(layer);

            return(layer);
        }
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
              this.CreateTabContainer("StromaDetection");
              this.TabContainer.Enabled = true;

              (new Button
              {
            Text = "execute cell core segmentation",
            Parent = this.TabContainer,
            Dock = DockStyle.Top
              }).Click += delegate
              {
            if (null == this.DisplayedImage) return;
            ProcessResult result = null;
            var progressDialog = new ProgressDialog { Message = "executing cell core segmentation", ProgressBarStyle = ProgressBarStyle.Marquee, AllowCancel = false };
            progressDialog.BackgroundTask += () =>
            {
              var segmentation = new CellCoreSegmentation();
              var executionParams = new ProcessExecutionParams(this.DisplayedImage);
              result = segmentation.Execute(executionParams);
            };
            progressDialog.CenterToScreen();
            progressDialog.ShowDialog();
            this.SetLayers(result.Layers.ToArray());
              };

              (new Button
              {
            Text = "execute threshold segmentation",
            Parent = this.TabContainer,
            Dock = DockStyle.Top
              }).Click += delegate
              {
            if (null == this.DisplayedImage) return;
            var m = new Map(this.DisplayedImage.Width, this.DisplayedImage.Height);
            using (var gp = new GrayscaleProcessor(this.DisplayedImage.Clone() as Bitmap, RgbToGrayscaleConversion.Mean))
            {
              for (var x = 0; x < this.DisplayedImage.Width; x++)
              {
            for (var y = 0; y < this.DisplayedImage.Height; y++)
            {
              m[x, y] = gp.GetPixel(x, y) < this.threshold.Value ? 1u : 0u;
            }
              }
            }
            var layer = new ConnectedComponentCollector().Execute(m);
            layer.Name = "threshold " + this.threshold.Value + " segmentation";
            var layers = this.GetLayers().ToList();
            layers.Add(layer);
            this.SetLayers(layers.ToArray());
              };

              this.threshold = new NumericUpDown
              {
            Parent = new GroupBox
            {
              Parent = this.TabContainer,
              Dock = DockStyle.Top,
              Text = "threshold",
              Height = 40
            },
            Dock = DockStyle.Fill,
            Minimum = 0,
            Maximum = 255,
            Increment = 16,
            Value = 128,
            DecimalPlaces = 0
              };

              (new Button
              {
            Text = "display edges",
            Parent = this.TabContainer,
            Dock = DockStyle.Top
              }).Click += delegate
              {
            this.SetDisplayedImage(this.edges);
              };

              (new Button
              {
            Text = "execute edge detection",
            Parent = this.TabContainer,
            Dock = DockStyle.Top
              }).Click += delegate
              {
            if (null == this.stainH || null == this.stainE) return;
            this.responseH = Filtering.ExecuteSobel(this.stainH);
            this.responseE = Filtering.ExecuteSobel(this.stainE);
            var substracted = new double[this.responseH.Size.Width, this.responseH.Size.Height];
            var substractedRange = new Range<double>();
            for (var x = 0; x < this.responseH.Size.Width; x++)
            {
              for (var y = 0; y < this.responseH.Size.Height; y++)
              {
            var value = Math.Max(0, this.responseE.Gradient[x, y] - this.responseH.Gradient[x, y]);
            substracted[x, y] = value;
            substractedRange.Add(value);
              }
            }
            this.nonMaximumSupression = Filtering.ExecuteNonMaximumSupression(substracted, this.responseE.Orientation);
            this.edges = Visualization.Visualize(this.nonMaximumSupression, Visualization.CreateColorizing(substractedRange.Maximum));
            this.SetDisplayedImage(this.edges);
              };

              (new Button
              {
            Text = "display haematoxylin",
            Parent = this.TabContainer,
            Dock = DockStyle.Top
              }).Click += delegate
              {
            this.SetDisplayedImage(this.stainH);
              };

              (new Button {
            Text = "display eosin",
            Parent = this.TabContainer,
            Dock = DockStyle.Top
              }).Click += delegate
              {
            this.SetDisplayedImage(this.stainE);
              };

              (new Button {
            Text = "display source",
            Parent = this.TabContainer,
            Dock = DockStyle.Top
              }).Click += delegate
              {
            this.SetDisplayedImage(this.source);
              };

              (new Button {
            Text = "execute deconvolution",
            Parent = this.TabContainer,
            Dock = DockStyle.Top
              }).Click += delegate
              {
            if (null == this.DisplayedImage) return;
            this.source = this.DisplayedImage;
            var gpE = new ColorDeconvolution().Get2ndStain(this.DisplayedImage, ColorDeconvolution.KnownStain.HaematoxylinEosin);
            gpE.Dispose();
            this.stainE = gpE.Bitmap;
            var gpH = new ColorDeconvolution().Get1stStain(this.DisplayedImage, ColorDeconvolution.KnownStain.HaematoxylinEosin);
            gpH.Dispose();
            this.stainH = gpH.Bitmap;
            this.SetDisplayedImage(this.stainE);
              };
        }
Exemple #24
0
    public override ProcessResult Execute(ProcessExecutionParams p)
    {
        GrayscaleProcessor gp = new GrayscaleProcessor(new Bitmap(p.Bitmap), RgbToGrayscaleConversion.None);

        BitmapProcessor bp = new BitmapProcessor(p.Bitmap.Clone() as Bitmap);

        for (int dy = 0; dy < gp.Height; dy++)
        {
            for (int dx = 0; dx < gp.Width; dx++)
            {
                int pixel = (int)bp.GetPixel(dx, dy);

                int r = (pixel & 0x00ff0000) >> 16;
                int g = (pixel & 0x0000ff00) >> 08;
                int b = (pixel & 0x000000ff) >> 00;

                int max = Math.Max(Math.Max(r, g), b);
                int min = Math.Min(Math.Min(r, g), b);

                int range = max - min;

                int level = (r + g + b) / 3;

                int val = level - range;

                if (val > 255)
                {
                    val = 255;
                }
                if (val < 0)
                {
                    val = 0;
                }

                gp.SetPixel(dx, dy, (UInt32)level);
            }
        }

        GrayscaleProcessor gpSobel = (GrayscaleProcessor)gp.Clone();

        new SobelEdgeDetector().Execute(gpSobel);

        ObjectLayer l1stLevel = Execute1stLevelSegmentation(gp, gpSobel);

        ObjectLayer l2ndLevel = Execute2ndLevelSegmentation(l1stLevel, gp);

        gpSobel.WriteBack = false;
        gp.WriteBack      = false;

        gpSobel.Dispose();
        gp.Dispose();
        bp.Dispose();

        gpSobel.Bitmap.Dispose();
        gp.Bitmap.Dispose();
        bp.Bitmap.Dispose();

        l1stLevel.Name = "1st Level";
        l2ndLevel.Name = "2nd Level";

        return(new ProcessResult(new ObjectLayer[] { l1stLevel, l2ndLevel }));
    }
        private double GetContourGradient(ImageObject obj, GrayscaleProcessor gp)
        {
            int[] nX = { +1, 0, -1, 0 };
              int[] nY = { 0, +1, 0, -1 };

              int height = gp.Height;
              int width = gp.Width;

              double sumInner = 0.0, sumOuter = 0.0;
              double numInner = 0.0, numOuter = 0.0;

              for (int i = 0; i < obj.Contour.Length; i++)
              {
            Point p = obj.Contour[i];

            for (int j = 0; j < 4; j++)
            {
              int x = p.X + nX[j];
              int y = p.Y + nY[j];

              if (x < 0 || y < 0 || x >= width || y >= height) continue;

              if (obj.Contour.Contains(x, y)) continue;

              UInt32 intensity = gp[x, y];

              if (obj.Layer.Map[x, y] == obj.Id)
              {
            sumInner += intensity;
            numInner++;
              }
              else
              {
            sumOuter += intensity;
            numOuter++;
              }
            }
              }

              double meanInner = sumInner / numInner;
              double meanOuter = sumOuter / numOuter;

              return meanInner - meanOuter;
        }
        private double GetContourValue(Contour c, GrayscaleProcessor gpSobel, GrayscaleProcessor gpH, float targetArea)
        {
            double h = MeanIntensityOnContour.GetValue(c, gpH);

              ContourProperties cp = ContourProperties.FromContour(c);

              float area = Math.Min(cp.Area, targetArea) / targetArea;

              if (cp.Convexity < 0.9 && cp.Area < targetArea)
              {
            area = 1F / targetArea;
              }

              float convexity = cp.Convexity * cp.Convexity;

              double color = h / 255.0;

              return color * area * convexity * ContourValue.GetValue(c, gpSobel);
        }
        private double[] GetBackgroundHistogram(ObjectLayer layer, GrayscaleProcessor p)
        {
            Map map = new Map(p.Width, p.Height);

              for (int dy = 0; dy < p.Height; dy++) for (int dx = 0; dx < p.Width; dx++)
            {
              if (layer.Map[dx, dy] == 0) map[dx, dy] = 1;
            }

              double[,] distanceMap = new DistanceTransformation().Execute(map);

              double[] histogram = new double[256];

              for (int dy = 0; dy < p.Height; dy++) for (int dx = 0; dx < p.Width; dx++)
            {
              if (map[dx, dy] == 0) continue;

              if (distanceMap[dx, dy] < 3) continue;

              histogram[p[dx, dy]]++;
            }

              return histogram;
        }
        private ObjectLayer Execute2ndLevelSegmentation(GrayscaleProcessor gp, GrayscaleProcessor gpSobel, GrayscaleProcessor gpH, float targetArea)
        {
            ContourBasedSegmentation cbs = new ContourBasedSegmentation();

            cbs.CreatePrimarySegmentation(gp, MAX_CONTOURLENGTH);

            cbs.EvaluateContours(c =>
            {
                return(this.GetContourValue(c, gpSobel, gpH, targetArea));
            });

            ObjectLayer layer = cbs.CreateLayer(MIN_CONTOURLENGTH, int.MaxValue);

            layer = layer.CreateAbove(obj =>
            {
                return(this.GetContourGradient(obj, gp) < 0);
            });

            layer = new ContourOptimizer().RemoveNonCompactPixels(layer, 3);

            //layer=new ConcaveObjectSeparation().Execute(layer, 0.33, true);

            double[] hBackground = this.GetBackgroundHistogram(layer, gpH);
            double[] hForeground = this.GetForegroundHistogram(layer, gpH);

            bool isFirst = true;

            ObjectLayer firstStep = null;

            while (true)
            {
                bool removed = false;

                layer = layer.CreateAbove(obj =>
                {
                    int[] hHistogram = this.GetHistogram(obj, gpH);

                    double hRatioForeground = this.GetRatioForeground(hHistogram, hForeground, hBackground);

                    if (hRatioForeground > 0.5)
                    {
                        return(true);
                    }

                    for (int i = 0; i < 256; i++)
                    {
                        int val = hHistogram[i];

                        hForeground[i] -= val;
                        hBackground[i] += val;
                    }

                    removed = true;

                    return(false);
                });

                if (isFirst)
                {
                    firstStep = layer;
                    isFirst   = false;
                }

                if (!removed)
                {
                    break;
                }
            }

            if (layer.Objects.Count == 0)
            {
                layer = firstStep;
            }

            double minArea = Math.Max(0.1 * targetArea, MIN_AREA);

            layer = layer.CreateAbove(obj =>
            {
                float area = ContourProperties.FromContour(obj.Contour).Area;

                return(area >= minArea);
            });

            layer = this.RefillContours(layer);

            return(layer);
        }
        private ObjectLayer Execute2ndLevelSegmentation(GrayscaleProcessor gp, GrayscaleProcessor gpSobel, GrayscaleProcessor gpH, float targetArea)
        {
            ContourBasedSegmentation cbs = new ContourBasedSegmentation();

              cbs.CreatePrimarySegmentation(gp, MAX_CONTOURLENGTH);

              cbs.EvaluateContours(c =>
              {
            return this.GetContourValue(c, gpSobel, gpH, targetArea);
              });

              ObjectLayer layer = cbs.CreateLayer(MIN_CONTOURLENGTH, int.MaxValue);

              layer = layer.CreateAbove(obj =>
              {
            return this.GetContourGradient(obj, gp) < 0;
              });

              layer = new ContourOptimizer().RemoveNonCompactPixels(layer, 3);

              layer = new ConcaveObjectSeparation().Execute(layer, 0.33, true);

              double[] hBackground = this.GetBackgroundHistogram(layer, gpH);
              double[] hForeground = this.GetForegroundHistogram(layer, gpH);

              bool isFirst = true;

              ObjectLayer firstStep = null;

              while (true)
              {
            bool removed = false;

            layer = layer.CreateAbove(obj =>
            {
              int[] hHistogram = this.GetHistogram(obj, gpH);

              double hRatioForeground = this.GetRatioForeground(hHistogram, hForeground, hBackground);

              if (hRatioForeground > 0.5) return true;

              for (int i = 0; i < 256; i++)
              {
            int val = hHistogram[i];

            hForeground[i] -= val;
            hBackground[i] += val;
              }

              removed = true;

              return false;
            });

            if (isFirst)
            {
              firstStep = layer;
              isFirst = false;
            }

            if (!removed) break;
              }

              if (layer.Objects.Count == 0) layer = firstStep;

              double minArea = Math.Max(0.1 * targetArea, MIN_AREA);

              layer = layer.CreateAbove(obj =>
              {
            float area = ContourProperties.FromContour(obj.Contour).Area;

            return area >= minArea;
              });

              layer = this.RefillContours(layer);

              return layer;
        }
        private ObjectLayer Execute1stLevelSegmentation(GrayscaleProcessor gp, GrayscaleProcessor gpSobel, GrayscaleProcessor gpH)
        {
            ContourBasedSegmentation cbs = new ContourBasedSegmentation();

              cbs.CreatePrimarySegmentation(gp, MAX_CONTOURLENGTH);

              cbs.EvaluateContours(c =>
              {
            if (ContourProperties.FromContour(c).Convexity < 0.95) return -1;

            return ContourValue.GetValue(c, gpSobel);
              });

              ObjectLayer layer = cbs.CreateLayer(MIN_CONTOURLENGTH, int.MaxValue);

              layer = new ContourOptimizer().RemoveNonCompactPixels(layer, 3);

              layer = layer.CreateAbove(obj =>
              {
            return this.GetContourGradient(obj, gp) < 0;
              });

              layer = new ConcaveObjectSeparation().Execute(layer, 0.33, true);

              return layer;
        }
        private double[] GetForegroundHistogram(ObjectLayer layer, GrayscaleProcessor p)
        {
            double[] histogram = new double[256];

              Parallel.For(0, layer.Objects.Count, i =>
              {
            int[] objHistogram = this.GetHistogram(layer.Objects[i], p);

            lock (histogram)
            {
              for (int j = 0; j < 256; j++)
              {
            int value = objHistogram[j];

            histogram[j] += value;
              }
            }
              });

              return histogram;
        }
        private int[] GetHistogram(ImageObject obj, GrayscaleProcessor p)
        {
            Rectangle boundingBox = obj.Contour.FindBoundingBox();

              int y2 = boundingBox.Bottom;
              int x2 = boundingBox.Right;
              int y1 = boundingBox.Y;
              int x1 = boundingBox.X;

              int[] histogram = new int[256];

              for (int dy = y1; dy < y2; dy++) for (int dx = x1; dx < x2; dx++)
            {
              if (obj.Layer.Map[dx, dy] != obj.Id) continue;

              histogram[p[dx, dy]]++;
            }

              return histogram;
        }
        private Contour[] Sort(Contour[] contours, GrayscaleProcessor gpSobel, GrayscaleProcessor gpH, float targetArea)
        {
            List<ContourDataComposite<double>> valuedContours = new List<ContourDataComposite<double>>();

              Parallel.For(0, contours.Length, i =>
              {
            Contour c = contours[i];

            double value = this.GetContourValue(c, gpSobel, gpH, targetArea);

            if (value <= 0) return;

            lock (valuedContours)
            {
              valuedContours.Add(new ContourDataComposite<double>(c, value));
            }
              });

              valuedContours.Sort(delegate(ContourDataComposite<double> c1, ContourDataComposite<double> c2)
              {
            if (c1.Data > c2.Data) return -1;
            if (c1.Data < c2.Data) return 1;

            return 0;
              });

              contours = new Contour[valuedContours.Count];

              for (int i = 0; i < valuedContours.Count; i++)
              {
            contours[i] = valuedContours[i].Contour;
              }

              return contours;
        }
        private ObjectLayer Execute3rdLevelSegmentation(ObjectLayer l2ndLevel, GrayscaleProcessor gpSobel, GrayscaleProcessor gpH, float targetArea)
        {
            List<Contour> finalContours = new List<Contour>();

              for (int i = 0; i < l2ndLevel.Objects.Count; i++)
              {
            finalContours.Add(l2ndLevel.Objects[i].Contour);
              }

              double[] hBackground = this.GetBackgroundHistogram(l2ndLevel, gpH);
              double[] hForeground = this.GetForegroundHistogram(l2ndLevel, gpH);

              Parallel.For(0, l2ndLevel.Objects.Count, i =>
              {
            ImageObject obj = l2ndLevel.Objects[i];

            ContourProperties cp = ContourProperties.FromContour(obj.Contour);

            obj.Features.Add(new Feature("Area", cp.Area));
              });

              Map map = new Map(gpSobel.Width, gpSobel.Height);

              Parallel.For(0, gpH.Height, dy =>
              {
            for (int dx = 0; dx < gpH.Width; dx++)
            {
              UInt32 h = gpH[dx, dy];

              if (hForeground[h] <= hBackground[h]) continue;

              UInt32 id = l2ndLevel.Map[dx, dy];

              if (id != 0)
              {
            ImageObject obj = l2ndLevel.Objects.GetObjectById(id);

            double area = obj.Features["Area"].Value;

            if (area > 0.33 * targetArea) continue;
              }

              map[dx, dy] = 0xffffffff;
            }
              });

              ObjectLayer layer = new ConnectedComponentCollector().Execute(map);

              layer = new ContourOptimizer().RemoveNonCompactPixels(layer, 3);

              for (int i = 0; i < layer.Objects.Count; i++)
              {
            finalContours.Add(layer.Objects[i].Contour);
              }

              Contour[] contours = this.Sort(finalContours.ToArray(), gpSobel, gpH, targetArea);

              layer = this.CreateLayer(gpSobel.Width, gpSobel.Height, contours);

              Map finalMap = new Map(layer.Map, false);

              for (int dy = 0; dy < gpH.Height; dy++) for (int dx = 0; dx < gpH.Width; dx++)
            {
              if (l2ndLevel.Map[dx, dy] != 0) continue;

              if (map[dx, dy] != 0) continue;

              finalMap[dx, dy] = 0;
            }

              layer = new ConnectedComponentCollector().Execute(finalMap);

              layer = new ContourOptimizer().RemoveNonCompactPixels(layer, 3);

              layer = new ConcaveObjectSeparation().Execute(layer, 0.33, true);

              double minArea = Math.Max(0.1 * targetArea, MIN_AREA);

              layer = layer.CreateAbove(obj =>
              {
            float area = ContourProperties.FromContour(obj.Contour).Area;

            return area > minArea;
              });

              layer = this.RefillContours(layer);

              return layer;
        }