private static void Main(string[] args) { foreach (var slideName in Util.GetSlideFilenames(args)) { using (var slideCache = new SlideCache(slideName)){ var hValues = File.Exists(slideCache.DataPath + "hValues.xml")?SlidePartitioner <double> .Load(slideCache.DataPath + "hValues.xml"):new SlidePartitioner <double>(slideCache.Slide, 1f, new Size(2000, 2000)); var eValues = File.Exists(slideCache.DataPath + "eValues.xml")?SlidePartitioner <double> .Load(slideCache.DataPath + "eValues.xml"):hValues.Duplicate <double>(); var hRange = new Range <double>(); var eRange = new Range <double>(); foreach (var tile in hValues.Values) { using (Bitmap tileImage = slideCache.Slide.GetImagePart(tile), hImage = tileImage.Clone() as Bitmap, eImage = tileImage.Clone() as Bitmap){ var gpH = new ColorDeconvolution().Get1stStain(hImage, ColorDeconvolution.KnownStain.HaematoxylinEosin); var gpE = new ColorDeconvolution().Get2ndStain(eImage, ColorDeconvolution.KnownStain.HaematoxylinEosin); var hSum = 0u; var eSum = 0u; var cnt = 0; foreach (var grayscalePixel in gpH.Pixels()) { hSum += grayscalePixel.V; eSum += gpE.GetPixel(grayscalePixel.X, grayscalePixel.Y); cnt++; } var meanH = (double)hSum / (double)cnt; tile.Data = meanH; hRange.Add(meanH); var meanE = (double)eSum / (double)cnt; eValues[tile.Index].Data = meanE; eRange.Add(meanE); gpH.Dispose(); gpE.Dispose(); if (slideCache.Slide.GetAnnotationsInArea(tile.SourceArea).Any()) { var tileCache = slideCache.GetTileCache(tile.Index); tileCache.SetImage("rgb", tileImage); tileCache.SetImage("h", gpH.Bitmap); tileCache.SetImage("e", gpE.Bitmap); } } Console.WriteLine(slideCache.SlideName + "-" + tile.Index + " done"); } var range = new Range <double> { hRange.Minimum, hRange.Maximum, eRange.Minimum, eRange.Maximum }; Func <double, Color> toColor = v => { var c = (int)Math.Round(range.Normalize(v) * 255d); return(Color.FromArgb(c, c, c)); }; slideCache.SetImage("hValues", hValues.GenerateHeatMap(toColor)); slideCache.SetImage("eValues", eValues.GenerateHeatMap(toColor)); slideCache.SetImage("overview", slideCache.Slide.GetImagePart(0, 0, slideCache.Slide.Size.Width, slideCache.Slide.Size.Height, hValues.Columns, hValues.Rows)); hValues.Save(slideCache.DataPath + "hValues.xml"); eValues.Save(slideCache.DataPath + "eValues.xml"); } } }
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)); } }
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 }); }
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 })); }
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); }; }
private static void Main(string[] args) { #region init if (0 == args.Length) { Console.WriteLine("no slide name"); return; } var slideName = args[0]; var processinHelper = new Processing(slideName); var slide = processinHelper.Slide; #endregion init TiledProcessInformation<uint[]> haematoxylinHistogram; TiledProcessInformation<uint[]> eosinHistogram; if (!File.Exists(processinHelper.DataPath + "haematoxylinHistogram.tpi") || !File.Exists(processinHelper.DataPath + "eosinHistogram.tpi")) { if (!Directory.Exists(processinHelper.DataPath + "deconvolution")) Directory.CreateDirectory(processinHelper.DataPath + "deconvolution"); var tissueData = TiledProcessInformation<bool>.FromFile(processinHelper.DataPath + "tissueData.tpi"); haematoxylinHistogram = new TiledProcessInformation<uint[]>(tissueData.Partitioner, tissueData.WsiUri); eosinHistogram = new TiledProcessInformation<uint[]>(tissueData.Partitioner, tissueData.WsiUri); var partitioner = tissueData.Partitioner; var dict = new Dictionary<Point, WsiRect>(); foreach (var tile in tissueData.Partitioner) dict.Add(tissueData.Partitioner.CurrentIndices, tile); var stopwatch = new Stopwatch(); foreach (var tile in partitioner) { var tissueTile = dict[partitioner.CurrentIndices]; if (!tissueData[tissueTile]) continue; stopwatch.Start(); using (var tileImage = slide.GetImagePart(tile)) { var hHistogramValue = new uint[256]; var hValues = new List<double>(); using (var gpH = new ColorDeconvolution().Get1stStain(tileImage, ColorDeconvolution.KnownStain.HaematoxylinEosin)) { foreach (var intensity in gpH.GetPixels()) { hHistogramValue[intensity]++; hValues.Add(intensity); } haematoxylinHistogram.AddDataToCurrentTile(hHistogramValue); gpH.Dispose(); gpH.Bitmap.Save(processinHelper.DataPath + "deconvolution\\" + partitioner.CurrentIndices + ".h.png"); } var eHistogramValue = new uint[256]; var eValues = new List<double>(); using (var gpE = new ColorDeconvolution().Get2ndStain(tileImage, ColorDeconvolution.KnownStain.HaematoxylinEosin)) { foreach (var intensity in gpE.GetPixels()) { eHistogramValue[intensity]++; eValues.Add(intensity); } eosinHistogram.AddDataToCurrentTile(eHistogramValue); gpE.Dispose(); gpE.Bitmap.Save(processinHelper.DataPath + "deconvolution\\" + partitioner.CurrentIndices + ".e.png"); } NumericVector hHistogram = RConnector.Engine.CreateNumericVector(hValues); RConnector.Engine.SetSymbol("hHistogram", hHistogram); NumericVector eHistogram = RConnector.Engine.CreateNumericVector(eValues); RConnector.Engine.SetSymbol("eHistogram", eHistogram); var handle = RConnector.StartOutput(); RConnector.Engine.Evaluate("hist(eHistogram, col=rgb(1,0,0,0.5),xlim=c(0,255), main=\"" + partitioner.CurrentIndices + "\", xlab=\"HE\")"); RConnector.Engine.Evaluate("hist(hHistogram, col=rgb(0,0,1,0.5), add=T)"); var output = RConnector.EndOutput(handle); output.Save(processinHelper.DataPath + "deconvolution\\histogram" + partitioner.CurrentIndices + ".png"); } stopwatch.Stop(); Console.WriteLine(partitioner.CurrentIndices + ":" + (stopwatch.ElapsedMilliseconds / 1000d) + "s"); stopwatch.Reset(); } haematoxylinHistogram.ToFile(processinHelper.DataPath + "haematoxylinHistogram.tpi"); eosinHistogram.ToFile(processinHelper.DataPath + "eosinHistogram.tpi"); } else { haematoxylinHistogram = TiledProcessInformation<uint[]>.FromFile(processinHelper.DataPath + "haematoxylinHistogram.tpi"); eosinHistogram = TiledProcessInformation<uint[]>.FromFile(processinHelper.DataPath + "eosinHistogram.tpi"); } var hRange = new Range<uint>(); foreach (var tile in haematoxylinHistogram.Partitioner) { if (null == haematoxylinHistogram[tile]) continue; uint sum = 0; for (uint i = 0; i < 256; i++) { sum += haematoxylinHistogram[tile][i] * (255 - i); } hRange.Add(sum); } Func<uint[], Color> h2pixel = h => { if (null == h) return Color.Gray; uint sum = 0; for (uint i = 0; i < 256; i++) { sum += h[i] * (255 - i); } var ratio = (double)sum / hRange.Maximum; return Color.FromArgb(0, 0, (int)Math.Round(255.0 * ratio)); }; var eRange = new Range<uint>(); foreach (var tile in eosinHistogram.Partitioner) { if (null == eosinHistogram[tile]) continue; uint sum = 0; for (uint i = 0; i < 256; i++) { sum += eosinHistogram[tile][i] * (255 - i); } eRange.Add(sum); } Func<uint[], Color> e2pixel = e => { if (null == e) return Color.Gray; uint sum = 0; for (uint i = 0; i < 256; i++) { sum += e[i] * (255 - i); } var ratio = (double)sum / eRange.Maximum; return Color.FromArgb((int)Math.Round(255.0 * ratio), 0, 0); }; using (Bitmap b = haematoxylinHistogram.GenerateHeatMap(h2pixel)) b.Save(processinHelper.DataPath + "haematoxylinHistogram.png"); using (Bitmap b = eosinHistogram.GenerateHeatMap(e2pixel)) b.Save(processinHelper.DataPath + "eosinHistogram.png"); Console.WriteLine("done"); Console.ReadKey(); }
private static void processInput() { int Radius = 2; int NoiseLevel = 10; Console.WriteLine("Processing Input..."); foreach (var import in importItems) { Console.WriteLine(); Console.WriteLine(import.FileName); Console.WriteLine("Slide extrahieren..."); var processingHelper = new Processing(import.FileName); var slide = processingHelper.Slide; Console.WriteLine("Ausschnitt aus Slide extrahieren mit originaler Auflösung..."); int partImageWidth = import.LowerRight.X - import.UpperLeft.X; int partImageHeight = import.LowerRight.Y - import.UpperLeft.Y; Bitmap partImage = slide.GetImagePart( import.UpperLeft.X, import.UpperLeft.Y, partImageWidth, partImageHeight, partImageWidth, partImageHeight ); #region global tissue detection Console.WriteLine("Gewebe suchen und in separatem Layer speichern..."); var bitmapProcessor = new BitmapProcessor(partImage); ObjectLayer overviewLayer = new TissueDetector().Execute(bitmapProcessor, Radius, NoiseLevel); bitmapProcessor.Dispose(); Console.WriteLine("Gewebe-Layer in Ausschnitt zeichnen + speichern..."); DrawObjectsToImage(partImage, overviewLayer, Color.Black); partImage.Save(processingHelper.DataPath + "ImagePartTissue.png"); #endregion global tissue detection #region Deconvolution Console.WriteLine("Execute deconvolution 3..."); var gpX = new ColorDeconvolution().Get3rdStain(partImage, ColorDeconvolution.KnownStain.HaematoxylinEosin); gpX.Dispose(); Bitmap gpX_bmp = gpX.Bitmap; gpX_bmp.Save(processingHelper.DataPath + "ImagePartColor3.png"); Console.WriteLine("Execute deconvolution 2..."); var gpE = new ColorDeconvolution().Get2ndStain(partImage, ColorDeconvolution.KnownStain.HaematoxylinEosin); gpE.Dispose(); Bitmap gpE_bmp = gpE.Bitmap; gpE_bmp.Save(processingHelper.DataPath + "ImagePartColor2.png"); Console.WriteLine("Execute deconvolution 1..."); var gpH = new ColorDeconvolution().Get1stStain(partImage, ColorDeconvolution.KnownStain.HaematoxylinEosin); gpH.Dispose(); Bitmap gpH_bmp = gpH.Bitmap; gpH_bmp.Save(processingHelper.DataPath + "ImagePartColor1.png"); #endregion Deconvolution #region execute edge detection Console.WriteLine("Execute edge detection..."); SobelResponse responseH = Filtering.ExecuteSobel(gpH_bmp); SobelResponse responseE = Filtering.ExecuteSobel(gpE_bmp); var substracted = new double[responseH.Size.Width, responseH.Size.Height]; var substractedRange = new Range<double>(); for (var x = 0; x < responseH.Size.Width; x++) { for (var y = 0; y < responseH.Size.Height; y++) { var value = Math.Max(0, responseE.Gradient[x, y] - responseH.Gradient[x, y]); substracted[x, y] = value; substractedRange.Add(value); } } double[,] nonMaximumSupression = Filtering.ExecuteNonMaximumSupression(substracted, responseE.Orientation); Bitmap edges = Visualization.Visualize(nonMaximumSupression, Visualization.CreateColorizing(substractedRange.Maximum)); edges.Save(processingHelper.DataPath + "ImagePartEdges.png"); #endregion execute edge detection exportItems.Add( new Ausgabe { Identify = import.Identify, Result = false, Message = "kein Fehler" } ); } }