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 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); }
/// <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)); } }
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; }
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); }
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); }
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); }
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); }; }
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; }