public static bool IsTissue(Bitmap image) { const double GRENZ_ENTROPIE = 0.5; var bitmapProcessor = new BitmapProcessor(image);//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 return(calcEntropie(greyArray) > GRENZ_ENTROPIE); }
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 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); } } } }
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 var part = new WsiPartitioner(new Rectangle(new Point(0, 0), slide.Size), new Size(1000, 1000), new Size(0, 0), 1.0); var tissueData = new TiledProcessInformation<bool>(part, slideName); #region global tissue detection int overviewImageWidth = slide.Size.Width / OverviewTileSize; int overviewImageHeight = slide.Size.Height / OverviewTileSize; Bitmap overviewImage = slide.GetImagePart(0, 0, slide.Size.Width, slide.Size.Height, overviewImageWidth, overviewImageHeight); var bitmapProcessor = new BitmapProcessor(overviewImage); ObjectLayer overviewLayer = new TissueDetector().Execute(bitmapProcessor, Radius, NoiseLevel); bitmapProcessor.Dispose(); DrawObjectsToImage(overviewImage, overviewLayer, Color.Black); overviewImage.Save(processinHelper.DataPath + "tissueDetectionOverview.png"); #endregion global tissue detection //part.Tiles[] foreach (var tile in part) { #region global tissue detection var rect = tile.SourceRect; int overviewX = rect.X / OverviewTileSize; int overviewY = rect.Y / OverviewTileSize; int windowSize = rect.Width / OverviewTileSize; bool tileInObject = true; int partsOutside = 0; for (int y = 0; y < windowSize; y++) { for (int x = 0; x < windowSize; x++) { int newX = overviewX + x; int newY = overviewY + y; if (newX < 0 || newX >= overviewLayer.Map.Width || newY < 0 || newY >= overviewLayer.Map.Height) { continue; } uint id = overviewLayer.Map[newX, newY]; if (id != 0) continue; partsOutside++; if (!(partsOutside >= Math.Pow(windowSize + 1, 2) * 0.75)) continue; tileInObject = false; break; } if (!tileInObject) { break; } } tissueData.AddDataToCurrentTile(tileInObject); #endregion global tissue detection if (tileInObject) Console.WriteLine(tile.SourceRect + ":" + partsOutside); } tissueData.ToFile(processinHelper.DataPath + "tissueData.tpi"); using (Bitmap b = tissueData.GenerateHeatMap(tissue => tissue ? Color.Green : Color.Red)) b.Save(processinHelper.DataPath + "tissueData.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" } ); } }