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 static void DrawHeatMapAll(SlidePartitioner <Dictionary <String, TissuAnnotaionEnum> > tissueSlidePartitioner, SlideCache slideCache) { Func <Dictionary <String, TissuAnnotaionEnum>, Color> drawWekaClassificationBaggingFunc = classifyDic => TissuAnnotaionToColor(classifyDic["wekaClassifyBagging"]); Func <Dictionary <String, TissuAnnotaionEnum>, Color> drawOwnClassificationJ48Func = classifyDic => TissuAnnotaionToColor(classifyDic["ownClassificationJ48"]); Func <Dictionary <String, TissuAnnotaionEnum>, Color> drawOwnClassificationJRipFunc = classifyDic => TissuAnnotaionToColor(classifyDic["ownClassifyJRip"]); /* using (var heatMap = tissueSlidePartitioner.GenerateHeatMap(drawWekaClassificationBaggingFunc)) * { * slideCache.SetImage("ClassificationDetection_wekaClassifyBagging", heatMap); * }*/ using (var heatMap = tissueSlidePartitioner.GenerateHeatMap(drawOwnClassificationJ48Func)) { slideCache.SetImage("ClassificationDetection_ownClassifyJ48", heatMap); } using (var heatMap = tissueSlidePartitioner.GenerateHeatMap(drawOwnClassificationJRipFunc)) { slideCache.SetImage("ClassificationDetection_ownClassifyJRip", heatMap); } }
private static void Main(string[] args) { foreach (var slideName in Util.GetSlideFilenames(args)) { using (var slideCache = new SlideCache(slideName)){ var scale = 0.2f; var tileSize = 200; var slidePartitionerFileName = slideCache.DataPath + "BudDetection.Tissue.xml"; var slidePartitioner = File.Exists(slidePartitionerFileName)?SlidePartitioner <bool?> .Load(slidePartitionerFileName):new SlidePartitioner <bool?>(slideCache.Slide, scale, new Size(tileSize, tileSize)); using (var overViewImage = slideCache.Slide.GetImagePart(0, 0, slideCache.Slide.Size.Width, slideCache.Slide.Size.Height, slidePartitioner.Columns, slidePartitioner.Rows)){ slideCache.SetImage("overview", overViewImage); //speichert unter C:\ProgramData\processingRepository\[slideCache.SlideName]\... //ggf. heatmap hier erstellen } int i = 0; int max = slidePartitioner.Count; double percent = 0; foreach (var tile in slidePartitioner.Values) { percent = 100.0 * i++ / max; if (tile.Data.HasValue) { Console.WriteLine(slideCache.SlideName + "-" + tile.Index + ":" + tile.Data.Value + " skipped " + percent + "%"); continue; } using (var tileImage = slideCache.Slide.GetImagePart(tile)){ if (false) { var tileCache = slideCache.GetTileCache(tile.Index); tileCache.SetImage("rgb", tileImage); //speichert unter C:\ProgramData\processingRepository\[slideCache.SlideName]\[Index]\... ansonsten tileImage.Save("[uri].png") } var r = BudDetection.MyColorDeconvolution.Execute(tileImage); tile.Data = r.Value; //Wert zur Kachel speichern } Console.WriteLine(slideCache.SlideName + "-" + tile.Index + " done " + percent + "%"); if (Console.KeyAvailable) { break; } } slidePartitioner.Save(slidePartitionerFileName); using (var heatMap = slidePartitioner.GenerateHeatMap(b => b.HasValue?(b.Value?Color.Green:Color.White):Color.Black)) slideCache.SetImage("tissueHeatMap", heatMap); } } }
private static void Main(string[] args) { const double GRENZ_ENTROPIE = 0.1; foreach (var slideName in Util.GetSlideFilenames(new string[] { args[0] })) { using (var slideCache = new SlideCache(slideName)){ // scale=1 -> baselayer , sollte so klein wie möglich sein um die Rechenzeit zu minimieren // targetSize Größe der zu prozessierenden Bilder, hängt von der hardware ab und bestimmt die Auflösung der Heatmap, für niedrige scale-Werte sollte auch die Größe reduziert werden // Auflösung: Breite=tissueSlidePartitioner.Columns Höhe=tissueSlidePartitioner.Rows // var: implizit typisiert, tatsächlich stark typisiert da der Compiler den Typ kennt; RMT->Goto To Definition // Empfehlung: http://shop.oreilly.com/product/0636920040323.do die 5.0 gibt es auch als pdf im Internet var tissueSlidePartitioner = new SlidePartitioner <bool>(slideCache.Slide, 0.2f, new Size(500, 500)); //Nicht unbedingt auf dem Baselayerr arbeiten zB. 1f --> 0.1 using (var overViewImage = slideCache.Slide.GetImagePart(0, 0, slideCache.Slide.Size.Width, slideCache.Slide.Size.Height, tissueSlidePartitioner.Columns, tissueSlidePartitioner.Rows)){ //TODO falls die Gewebeerkennung auf dem Übersichtsbild stattfinden soll, dann hier slideCache.SetImage("overview", overViewImage); //speichert unter C:\ProgramData\processingRepository\[slideCache.SlideName]\... } //Multithreading Parallel.ForEach(tissueSlidePartitioner.Values, (tile) => { using (var tileImage = slideCache.Slide.GetImagePart(tile)) { var containsTissue = false; double entropie = 0.0; #region hier sollte containsTissue richtig bestimmt werden var bitmapProcessor = new BitmapProcessor(tileImage);//liefert schnelleren Zugriff auf die Pixel-Werte, alternativ auch SharpAccessory.Imaging.Processors.GrayscaleProcessor int[] greyArray = new int[256]; for (var y = 0; y < bitmapProcessor.Height; y++) { for (var x = 0; x < bitmapProcessor.Width; x++) { var r = bitmapProcessor.GetRed(x, y); var g = bitmapProcessor.GetGreen(x, y); var b = bitmapProcessor.GetBlue(x, y); var grauwert = (int)(r + g + b) / 3; greyArray[grauwert]++; } } bitmapProcessor.Dispose(); //Calculate Shannon Entropie entropie = calcEntropie(greyArray); //Contains Tissue ermitteln if (0 == tile.Index.Y) { containsTissue = false;//oberste Reihe sollte kein Gewebe enthalten } else { //if (slideCache.Slide.GetAnnotationsInArea(tile.SourceArea).Any()) containsTissue = true;//Kacheln mit Annotationen enthalten Gewebe if (entropie > GRENZ_ENTROPIE) { containsTissue = true; } } #endregion //Wert zur Kachel speichern tile.Data = containsTissue; //Only for Debug var saveImage = false; if (saveImage) { string path = args[1] + @"\" + slideCache.SlideName + @"\"; if (containsTissue) { path += @"isTissue\"; } else { path += @"noTissue\"; } if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } tileImage.Save(path + tile.Index.X + "-" + tile.Index.Y + ".png"); //var tileCache = slideCache.GetTileCache(tile.Index); //tileCache.SetImage("rgb",tileImage);//speichert unter C:\ProgramData\processingRepository\[slideCache.SlideName]\[Index]\... ansonsten tileImage.Save("[uri].png") } Console.WriteLine(slideCache.SlideName + "-" + tile.Index + " done - containsTissue: " + containsTissue.ToString() + " - entropie: " + entropie.ToString()); } }); //true wird zu grün, false zu rot; syntax ist lambda (=>) mit einem conditional operator (?) Func <bool, Color> f = b => { if (b) { return(Color.Red); } else { return(Color.Green); } }; using (var heatMap = tissueSlidePartitioner.GenerateHeatMap(f)) { slideCache.SetImage("tissueHeatMap", heatMap); } } } }
private static void Main(string[] args) { Console.WriteLine("Start SlideProzessor"); Console.WriteLine(args); foreach (var slideName in Util.GetSlideFilenames(args)) { Console.WriteLine("progress: " + slideName); using (var slideCache = new SlideCache(slideName)){ // Skalierung des Bildes var scale = 0.5f; // 0.1 var tileSize = 100; // 100 // Partionierung und speichern var slidePartitionerFileName = slideCache.DataPath + "BudDetection.Tissue.xml"; var slidePartitioner = File.Exists(slidePartitionerFileName)?SlidePartitioner <bool?> .Load(slidePartitionerFileName):new SlidePartitioner <bool?>(slideCache.Slide, scale, new Size(tileSize, tileSize)); using (var overViewImage = slideCache.Slide.GetImagePart(0, 0, slideCache.Slide.Size.Width, slideCache.Slide.Size.Height, slidePartitioner.Columns, slidePartitioner.Rows)){ slideCache.SetImage("overview", overViewImage); //speichert unter C:\ProgramData\processingRepository\[slideCache.SlideName]\... //ggf. heatmap hier erstellen } // über alle Kacheln var counter = 0; foreach (var tile in slidePartitioner.Values) { counter = counter + 1; // ist bereits ein wert vorhanden, dann überspringen if (tile.Data.HasValue) { if (counter % 100 == 0) { Console.WriteLine(slideCache.SlideName + "-" + tile.Index + ":" + tile.Data.Value + " skipped"); } continue; } // bitmap erzeugen aus der Kachel using (var tileImage = slideCache.Slide.GetImagePart(tile)){ // für debugging zwecke if (false) { var tileCache = slideCache.GetTileCache(tile.Index); tileCache.SetImage("rgb", tileImage); //speichert unter C:\ProgramData\processingRepository\[slideCache.SlideName]\[Index]\... ansonsten tileImage.Save("[uri].png") } // Wert Berechnung var r = BudDetection.ColorDeconvolution.Execute(tileImage); tile.Data = r.Value; //Wert zur Kachel speichern } if (counter % 100 == 0) { Console.WriteLine(slideCache.SlideName + "-" + tile.Index + " done"); } // unterbrechbar via key eingabe if (Console.KeyAvailable) { break; } } // zustand der bearbeitng speichern slidePartitioner.Save(slidePartitionerFileName); using (var heatMap = slidePartitioner.GenerateHeatMap(b => b.HasValue?(b.Value?Color.Green:Color.White):Color.Black)) slideCache.SetImage("tissueHeatMap", heatMap); } } }
private static void Main(string[] args) { foreach (var slideName in Util.GetSlideFilenames(args)) { using (var slideCache = new SlideCache(slideName)){ var scale = 0.5f; var tileSize = 500; var slidePartitionerFileName = slideCache.DataPath + "BudDetection.Buds.xml"; var slidePartitioner = File.Exists(slidePartitionerFileName)?SlidePartitioner <int?> .Load(slidePartitionerFileName):new SlidePartitioner <int?>(slideCache.Slide, scale, new Size(tileSize, tileSize)); var heatMapHelper = new HeatMapHelper(slideCache.GetImage("tissueHeatMap")); var budCountRange = new Range <int>(); foreach (var tile in slidePartitioner.Values) { if (tile.Data.HasValue) { Console.WriteLine(slideCache.SlideName + "-" + tile.Index + ":" + tile.Data.Value + " skipped"); budCountRange.Add(tile.Data.Value); continue; } var colors = heatMapHelper.GetAffectedColors(slideCache.Slide.Size, tile.SourceArea); var values = heatMapHelper.GetAffectedValues(slideCache.Slide.Size, tile.SourceArea); if (values.All(v => 0 != v)) { Console.WriteLine(slideCache.SlideName + "-" + tile.Index + ": no tissue"); continue; } using (var tileImage = slideCache.Slide.GetImagePart(tile)){ if (false) { var tileCache = slideCache.GetTileCache(tile.Index); tileCache.SetImage("rgb", tileImage); //speichert unter C:\ProgramData\processingRepository\[slideCache.SlideName]\[Index]\... ansonsten tileImage.Save("[uri].png") } var r = BudDetection.Detector.Execute(tileImage); //var r = ColorDeconvolution.Detect(tileImage); var layer = r.Value; tile.Data = layer.Objects.Count; budCountRange.Add(layer.Objects.Count); foreach (var io in layer.Objects) { //var bb=io.Contour.FindBoundingBox(); var offset = tile.SourceArea.Location; var sourcePoints = new List <Point>(); foreach (var contourPoint in io.Contour.GetPoints()) { double x = Math.Round(contourPoint.X / scale + offset.X); double y = Math.Round(contourPoint.Y / scale + offset.Y); var sourcePoint = new Point((int)x, (int)y); sourcePoints.Add(sourcePoint); } var annotation = slideCache.Slide.CreateAnnotation(AnnotationType.PolygonLine); foreach (var point in sourcePoints) { annotation.AppendPoints(point); } annotation.Color = Color.OrangeRed; annotation.Name = null == io.Class?"bud":io.Class.Name; } } Console.WriteLine(slideCache.SlideName + "-" + tile.Index + " done"); if (Console.KeyAvailable) { break; } } slidePartitioner.Save(slidePartitionerFileName); using (var heatMap = slidePartitioner.GenerateHeatMap(b => { if (!b.HasValue) { return(Color.LightSeaGreen); } var c = (int)Math.Round(budCountRange.Normalize(b.Value) * 255d); return(Color.FromArgb(c, c, c)); })) slideCache.SetImage("budHeatMap", heatMap); } } }
private static void Main(string[] args) { foreach (var slideName in Util.GetSlideFilenames(args)) { using (var slideCache = new SlideCache(slideName)){ // var scale = 0.1f; var scale = 0.5f; // besser so laut 19.07.2018 var tileSize = 100; var slidePartitionerFileName = slideCache.DataPath + "BudDetection.Buds.xml"; var slidePartitioner = File.Exists(slidePartitionerFileName)?SlidePartitioner <int?> .Load(slidePartitionerFileName):new SlidePartitioner <int?>(slideCache.Slide, scale, new Size(tileSize, tileSize)); var heatMapHelper = new HeatMapHelper(slideCache.GetImage("tissueHeatMap")); var budCountRange = new Range <int>(); var counter = 0; foreach (var tile in slidePartitioner.Values) { // test, ob schon was für die kackel berechnet wurde if (tile.Data.HasValue) { Console.WriteLine(slideCache.SlideName + "-" + tile.Index + ":" + tile.Data.Value + " skipped"); budCountRange.Add(tile.Data.Value); continue; } // soll kachel bearbeitet werden var colors = heatMapHelper.GetAffectedColors(slideCache.Slide.Size, tile.SourceArea); var values = heatMapHelper.GetAffectedValues(slideCache.Slide.Size, tile.SourceArea); if (values.All(v => 255 == v)) // 255 weiß { Console.WriteLine(slideCache.SlideName + "-" + tile.Index + ": no tissue"); continue; } using (var tileImage = slideCache.Slide.GetImagePart(tile)){ counter = counter + 1; if (false) { var tileCache = slideCache.GetTileCache(tile.Index); tileCache.SetImage("rgb", tileImage); //speichert unter C:\ProgramData\processingRepository\[slideCache.SlideName]\[Index]\... ansonsten tileImage.Save("[uri].png") } var r = BudDetection.Detector.Execute(tileImage); // importent call var layer = r.Value; tile.Data = layer.Objects.Count; budCountRange.Add(layer.Objects.Count); // für alle gefundene objekte wird eine annotation angelegt foreach (var io in layer.Objects) { //var bb=io.Contour.FindBoundingBox(); var offset = tile.SourceArea.Location; var sourcePoints = new List <Point>(); foreach (var contourPoint in io.Contour.GetPoints()) { double x = Math.Round(contourPoint.X / scale + offset.X); double y = Math.Round(contourPoint.Y / scale + offset.Y); var sourcePoint = new Point((int)x, (int)y); sourcePoints.Add(sourcePoint); } var annotation = slideCache.Slide.CreateAnnotation(AnnotationType.PolygonLine); foreach (var point in sourcePoints) { annotation.AppendPoints(point); } annotation.Color = Color.PaleVioletRed; annotation.Name = null == io.Class?"bud":io.Class.Name; } } if (counter % 100 == 0) { Console.WriteLine(slideCache.SlideName + "-" + tile.Index + " done"); } if (Console.KeyAvailable) { break; } } slidePartitioner.Save(slidePartitionerFileName); // normalisierung using (var heatMap = slidePartitioner.GenerateHeatMap(b => { if (!b.HasValue) { return(Color.LightSeaGreen); } var c = (int)Math.Round(budCountRange.Normalize(b.Value) * 255d); return(Color.FromArgb(c, c, c)); // grauwert(hell == viele butts) })) slideCache.SetImage("budHeatMap", heatMap); } } }