public static SCalcRegionTask calcRegions(CancellationToken cToken, SCalcRegionTask data) { Rectangle roiRect = data.roiRect; // Flatten RGA to 1 byte pixel buffer with 1 indicating segment // if(!FlattenImage(cToken, roiRect, data.pixelData)) { // return data; // } // ******************************************************** // DETECT REGIONS // ******************************************************** // Allocate stuff List <Point> points = new List <Point>(128 * 128); SCalcRegionBuffers buffers = new SCalcRegionBuffers(); buffers.Prepare(256 * 256); bool isEDM = true; // Get regions at tags bool propertiesSet = false; int test = 0; foreach (Tag tag in data.tags) { Point posROI = new Point((int)tag.Pos.X - roiRect.Location.X, (int)tag.Pos.Y - roiRect.Location.Y); int index = posROI.Y * roiRect.Size.Width + posROI.X; uint val = data.pixelData[index]; if (val == 0x00FFFFFF) { points.Clear(); QuickFill <uint> .FloodFill(posROI, data.pixelData, roiRect.Size, val, 0, points); if (!propertiesSet) { propertiesSet = true; // Get bounds Rectangle regionBounds; Region.Transform(points, Point.Empty, out regionBounds); if (cToken.IsCancellationRequested) { return(data); } // Prepare buffers int regionsize = regionBounds.Width * regionBounds.Height; buffers.Prepare(regionsize); // Load binary map Region.loadBinaryMap(points, new Point(-regionBounds.X, -regionBounds.Y), buffers.EDMMap, regionBounds.Width); if (cToken.IsCancellationRequested) { return(data); } // Create EDM EDM.createEDM(buffers.EDMMap, regionBounds.Width, regionBounds.Height); int[] globalMinMax; Segmentation.FindGlobalMinMax(buffers.EDMMap, regionBounds.Width, regionBounds.Height, out globalMinMax); test = globalMinMax[1]; } } if (cToken.IsCancellationRequested) { return(data); } } // Create regions from segmentation map int height = roiRect.Size.Height; int width = roiRect.Size.Width; int count = height * width; float invWidth = 1.0f / (float)width; for (int index = 0; index < count; index++) { uint val = data.pixelData[index]; if (val == 0x00FFFFFF) { int x2 = index % width - 1; int y2 = (int)((float)(index - x2) * invWidth); Point pos = new Point(x2, y2); points.Clear(); // QuickFill<uint>.FloodFill(pos, data.pixelData, roiRect.Size, val, 0, points); QuickFillUint.FloodFill(pos, data.pixelData, roiRect.Size, val, 0, points); if (cToken.IsCancellationRequested) { return(data); } // Transform region points to image space Rectangle regionBounds; Region.Transform(points, roiRect.Location, out regionBounds); // Prepare buffers int regionsize = regionBounds.Width * regionBounds.Height; buffers.Prepare(regionsize); // Load binary map Region.loadBinaryMap(points, new Point(-regionBounds.X, -regionBounds.Y), buffers.EDMMap, regionBounds.Width); if (cToken.IsCancellationRequested) { return(data); } // Create EDM EDM.createEDM(buffers.EDMMap, regionBounds.Width, regionBounds.Height); if (cToken.IsCancellationRequested) { return(data); } // Debug render EDM if (data.bDebugDrawEDM) { DebugDragEDM(regionBounds, buffers, data); } if (cToken.IsCancellationRequested) { return(data); } // Find maxima int minSize = Math.Min(regionBounds.Width, regionBounds.Height); double tolerance = 20; // double findMaxThreshold = 4*EDM.ONE; double findMaxThreshold = (float)test * 0.5f; Segmentation.MaxPoint[] maxPoints; int[] globalMinMax; Segmentation.FindGlobalMinMax(buffers.EDMMap, regionBounds.Width, regionBounds.Height, out globalMinMax); Segmentation.findMaxima(buffers.EDMMap, regionBounds.Width, regionBounds.Height, tolerance, findMaxThreshold, buffers.maxMap, isEDM, globalMinMax, out maxPoints); // Count max points int iMaxPointCount = 0; foreach (Segmentation.MaxPoint maxPoint in maxPoints) { int ri = maxPoint.y * regionBounds.Width + maxPoint.x; int iVal = buffers.maxMap[ri]; if ((iVal & Segmentation.MAX_POINT) > 0) { iMaxPointCount++; } } // Skip all regions with no max if (iMaxPointCount == 0) { continue; } // Debug Render maxima if (data.bDebugDrawEDM) { DebugDragMaxima(regionBounds, buffers, data, maxPoints, iMaxPointCount); } if (cToken.IsCancellationRequested) { return(data); } if (iMaxPointCount == 1) { Region region = new Region(points, regionBounds); data.regions.Add(region); data.SendRegionAdded(region); } else { // TODO: could watershed write region map in different colors (so we dont have to quickfill) double watershedThreshold = 1; Segmentation.performWatershed(buffers.EDMMap, regionBounds.Width, regionBounds.Height, watershedThreshold, buffers.maxMap, isEDM, buffers.regionMap, maxPoints, globalMinMax); // Debug render region map if (data.bDebugDrawRegions) { int offsetX = regionBounds.X - roiRect.X; int offsetY = regionBounds.Y - roiRect.Y; int ri = 0; for (int ry = 0; ry < regionBounds.Height; ry++) { for (int rx = 0; rx < regionBounds.Width; rx++) { int iVal = buffers.regionMap[ri]; data.debugTexture.SetPixel(rx + offsetX, ry + offsetY, iVal, 0, 0, 1); ri++; } } } if (cToken.IsCancellationRequested) { return(data); } for (int ry = 0; ry < regionBounds.Height; ry++) { for (int rx = 0; rx < regionBounds.Width; rx++) { int ri = (regionBounds.Width * ry) + rx; uint iVal = (uint)(buffers.regionMap[ri] & 0xFF); if (iVal == 255) { points.Clear(); // QuickFill<byte>.FloodFill(new Point(rx, ry), buffers.regionMap, regionBounds.Size, (byte)iVal, 0, points); QuickFillByte.FloodFill(new Point(rx, ry), buffers.regionMap, regionBounds.Size, (byte)iVal, 0, points); if (cToken.IsCancellationRequested) { return(data); } Rectangle bounds; Region.Transform(points, regionBounds.Location, out bounds); Region region = new Region(points, bounds); data.regions.Add(region); data.SendRegionAdded(region); } } } } if (cToken.IsCancellationRequested) { return(data); } } } return(data); }