private static DataRectangle <double> Normalise(DataRectangle <double> values) { var max = values.Enumerate().Max(pointAndValue => pointAndValue.Item2); return((max == 0) ? values : values.Transform(value => (value / max))); }
private static IEnumerable <IEnumerable <Point> > GetDistinctObjects(DataRectangle <bool> mask) { // Flood fill areas in the looks-like-bar-code mask to create distinct areas var allPoints = new HashSet <Point>( mask.Enumerate(optionalFilter: (point, isMasked) => isMasked).Select(point => point.Item1) ); while (allPoints.Any()) { var currentPoint = allPoints.First(); var pointsInObject = GetPointsInObject(currentPoint).ToArray(); foreach (var point in pointsInObject) { allPoints.Remove(point); } yield return(pointsInObject); } // Inspired by code at // https://simpledevcode.wordpress.com/2015/12/29/flood-fill-algorithm-using-c-net/ IEnumerable <Point> GetPointsInObject(Point startAt) { var pixels = new Stack <Point>(); pixels.Push(startAt); var valueAtOriginPoint = mask[startAt.X, startAt.Y]; var filledPixels = new HashSet <Point>(); while (pixels.Count > 0) { var currentPoint = pixels.Pop(); if ((currentPoint.X < 0) || (currentPoint.X >= mask.Width) || (currentPoint.Y < 0) || (currentPoint.Y >= mask.Height)) { continue; } if ((mask[currentPoint.X, currentPoint.Y] == valueAtOriginPoint) && !filledPixels.Contains(currentPoint)) { filledPixels.Add(new Point(currentPoint.X, currentPoint.Y)); pixels.Push(new Point(currentPoint.X - 1, currentPoint.Y)); pixels.Push(new Point(currentPoint.X + 1, currentPoint.Y)); pixels.Push(new Point(currentPoint.X, currentPoint.Y - 1)); pixels.Push(new Point(currentPoint.X, currentPoint.Y + 1)); } } return(filledPixels); } }