private static void Main(string[] args)
 {
     foreach (var slideName in Util.GetSlideFilenames(new string[] { args[1] }))
     {
         using (var slideCache = new SlideCache(slideName)){
             foreach (var annotation in slideCache.Slide.GetAnnotations())
             {
                 var contained = new List <IAnnotation>();
                 foreach (var candidate in slideCache.Slide.GetAnnotations())
                 {
                     if (candidate == annotation)
                     {
                         continue;
                     }
                     var rectangle = annotation.BoundingBox;
                     rectangle.Intersect(candidate.BoundingBox);
                     if (rectangle.IsEmpty)
                     {
                         continue;
                     }
                     if (annotation.BoundingBox.Contains(candidate.BoundingBox))
                     {
                         contained.Add(candidate);
                     }
                 }
                 var name = annotation.Name + "." + slideCache.SlideName + "." + annotation.Id;
                 using (var b = annotation.Extract(1, contained)) b.Save(args[0] + "\\" + name + ".png");
                 Console.WriteLine(name + " exc:" + contained.Count);
             }
         }
     }
 }
Exemple #2
0
        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 Main(string[] args)
        {
            //Eingabe Parameter
            var inPathSlide      = args[0];
            var inPathDataset    = args[1];
            var inPathClassifier = args[2];

            //Start der Verarbeitung
            var startProcTime = DateTime.Now;

            Console.WriteLine("Start: " + startProcTime);
            Console.WriteLine("Verarbeite Daten...");

            //Verarbeitung

            //Load Dataset
            _dataSet = Glaukopis.Adapters.PicNetML.Util.LoadInstancesFromWekaArff(inPathDataset);

            //Load Classifier
            _classifier = (Classifier)SerializationHelper.read(inPathClassifier);


            foreach (var slideName in Glaukopis.SlideProcessing.Util.GetSlideFilenames(new string[] { inPathSlide }))
            {
                using (var slideCache = new SlideCache(slideName))
                {
                    //Compute Class
                    var tissueSlidePartitioner = new SlidePartitioner <Dictionary <string, TissuAnnotaionEnum> >(slideCache.Slide, 1f,
                                                                                                                 new Size(500, 500));
                    ComputeClass(tissueSlidePartitioner, slideCache);

                    //Draw Heatmaps
                    DrawHeatMapAll(tissueSlidePartitioner, slideCache);
                }
            }


            //Ender der Verarbeitung
            var endProcTime = DateTime.Now;

            Console.WriteLine("\n############ FINISHED ###############");
            Console.WriteLine("Ende: " + endProcTime);

            //FINISH
            Console.Write("Benötigte Zeit: {0:F} Minuten", endProcTime.Subtract(startProcTime).TotalMinutes);
            Console.ReadKey();
        }
        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);
                }
            }
        }
        // This method creates and initializes the slide at the specified index and returns it.
        // The new slide is cached in the _slides array.
        private Slide GetSlide(int slideIndex, bool loadIfNeeded)
        {
            if (slideIndex < 0 || slideIndex >= SlideSettings.Slides.Count())
            {
                return(null);
            }

            // Look into the cache first
            if (SlideCache.ContainsKey(slideIndex.ToString()))
            {
                return(SlideCache [slideIndex.ToString()]);
            }

            if (!loadIfNeeded)
            {
                return(null);
            }

            // Create the new slide
            Type slideClass = ClassOfSlide(slideIndex);
            var  slide      = (Slide)Activator.CreateInstance(slideClass);

            // Update its parameters
            var slideSettings = SlideSettings.Slides [slideIndex].Slide;

            if (slideSettings != null)
            {
                slide.Fetch(slideSettings);
            }

            SlideCache [slideIndex.ToString()] = slide;

            if (slide == null)
            {
                return(null);
            }

            // Setup the slide
            slide.SetupSlide(this);

            return(slide);
        }
        private void WillOrderOutSlide(int slideIndex)
        {
            var slide = GetSlide(slideIndex, false);

            if (slide != null)
            {
                var node = slide.ContentNode;

                // Fade out and remove on completion
                SCNTransaction.Begin();
                SCNTransaction.AnimationDuration = 0.75f;
                SCNTransaction.SetCompletionBlock(() => node.RemoveFromParentNode());
                node.Opacity = 0.0f;
                SCNTransaction.Commit();

                slide.WillOrderOut(this);

                SlideCache.Remove(slideIndex.ToString());
            }
        }
        private static void ComputeClass(SlidePartitioner <Dictionary <string, TissuAnnotaionEnum> > tissueSlidePartitioner,
                                         SlideCache slideCache)
        {
            Parallel.ForEach(tissueSlidePartitioner.Values, (tile) =>
            {
                using (var tileImage = slideCache.Slide.GetImagePart(tile))
                {
                    var tissueAnnotaion = ComputeFeatues(tileImage);
                    var classifyDic     = new Dictionary <string, TissuAnnotaionEnum>();

                    classifyDic.Add("ownClassificationJ48", ClassificationOwn.ClassifyJ48(tissueAnnotaion));
                    classifyDic.Add("ownClassifyJRip", ClassificationOwn.ClassifyJRip(tissueAnnotaion));

                    //Funktioiert leider nicht, immer leer ""
                    //classifyDic.Add("wekaClassifyBagging",ClassifyWeka(tissueAnnotaion, _classifier, _dataSet));

                    tile.Data = classifyDic;
                    Console.WriteLine(slideCache.SlideName + "-" + tile.Index + " done - Class: " + showOutput(tile.Data["ownClassificationJ48"]));
                }
            });
        }
        private static TissueAnnotaionList GetAnnotaions(String srcSlides, String outputPics)
        {
            TissueAnnotaionList annotationList = new TissueAnnotaionList();
            int i = 0;

            //Get Anotaions from silde
            foreach (var slideName in Util.GetSlideFilenames(new String[] { srcSlides }))
            {
                using (var slideCache = new SlideCache(slideName))
                {
                    Parallel.ForEach(slideCache.Slide.GetAnnotations(), (annotation) =>
                    {
                        if (abort != 0)
                        {
                            if (i >= abort)
                            {
                                return;
                            }
                            i++;
                        }

                        //Annotaions Bitmap extrahieren
                        var contained = new List <IAnnotation>();
                        foreach (var candidate in slideCache.Slide.GetAnnotations())
                        {
                            if (candidate == annotation)
                            {
                                continue;
                            }
                            var rectangle = annotation.BoundingBox;
                            rectangle.Intersect(candidate.BoundingBox);
                            if (rectangle.IsEmpty)
                            {
                                continue;
                            }
                            if (annotation.BoundingBox.Contains(candidate.BoundingBox))
                            {
                                contained.Add(candidate);
                            }
                        }

                        using (Bitmap annotationBitmap = annotation.Extract(1, contained))
                        {
                            TissueAnnotationClass tissueAnnotation = new TissueAnnotationClass(annotation.Id, annotation.Name, slideCache.SlideName);

                            //Werte Berechnsen
                            tissueAnnotation = tissueAnnotation.ComputeFeatureValues(annotationBitmap);

                            //Zur Liste hinzufügren
                            annotationList.add(tissueAnnotation);

                            //FOR DEBUG Save Image
                            if (isSave)
                            {
                                annotationBitmap.Save(outputPics + "\\" + tissueAnnotation + ".png");
                            }

                            Console.WriteLine(tissueAnnotation + " exc:" + contained.Count);
                        }
                    });
                    if (abort != 0 && i >= abort)
                    {
                        return(annotationList);
                    }
                }
            }
            return(annotationList);
        }
Exemple #9
0
        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 DrawHeatMapOneClass(SlidePartitioner <Dictionary <String, TissuAnnotaionEnum> > tissueSlidePartitioner, SlideCache slideCache, TissuAnnotaionEnum annotaion)
 {
 }
        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);
            }
        }
Exemple #12
0
        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);
                }
            }
        }
Exemple #13
0
        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);
                }
            }
        }