/// <summary> /// Adds a shape to a colored image using the original color image. /// </summary> /// <param name="Shape">The pretzel / shape to add</param> /// <param name="FinalImg">Add to this picture</param> /// <param name="Image">Original colored picture</param> /// <returns>Colored image with shapes</returns> public static Color[,] AddShapeToColorImage( Shape Shape, Color[ , ] FinalImg, Color[ , ] Image ) { int XOffset = Shape.Origin.X; int YOffset = Shape.Origin.Y; for ( int y = 0; y < Shape.Grid.GetLength( 1 ); y++ ) for ( int x = 0; x < Shape.Grid.GetLength( 0 ); x++ ) if ( Shape.Grid[ x, y ] ) FinalImg[ x + XOffset, y + YOffset ] = Image[ x + XOffset, y + YOffset ]; return FinalImg; }
/// <summary> /// Sets the current and neighboring white pixels to the current label color. Applies /// recursively onto the pixels to the left, right, up and down (using a stack) /// </summary> /// <param name="input"> The input picture </param> /// <param name="x"> Pixel's x coordinate </param> /// <param name="y"> Pixel's y coordinate </param> /// <param name="Shapes"> The target list of shapes </param> private static void LabelPixel( byte[ , ] input, int x, int y, List<Shape> Shapes ) { if ( input[ x, y ] != 255 ) return; Color = NextColor( Color ); // Bounding values of the shape int maxX = 0, minX = int.MaxValue; int maxY = 0, minY = int.MaxValue; ConcurrentStack<Point> NeighbouringPixels = new ConcurrentStack<Point>( ); ConcurrentDictionary<Point, byte> NeighbouringPixelsUsed = new ConcurrentDictionary<Point, byte>( ); Point StartPoint = new Point( x, y ); NeighbouringPixels.Push( StartPoint ); NeighbouringPixelsUsed.AddOrUpdate( StartPoint, key => 0, ( key, value ) => value ); // Lock for when editing shared members object Lock = new object( ); while ( NeighbouringPixels.Count != 0 ) { // Parallel for faster calculations Parallel.For( 0, NeighbouringPixels.Count, index => { Point CurrentPoint; if ( !NeighbouringPixels.TryPop( out CurrentPoint ) ) return; NeighbouringPixelsUsed.AddOrUpdate( CurrentPoint, key => 0, ( key, value ) => value ); lock ( Lock ) { // Values for the bounding rectangle if ( CurrentPoint.Y < minY ) minY = CurrentPoint.Y; if ( CurrentPoint.Y > maxY ) maxY = CurrentPoint.Y; if ( CurrentPoint.X < minX ) minX = CurrentPoint.X; if ( CurrentPoint.X > maxX ) maxX = CurrentPoint.X; // Set the pixel to the label's value input[ CurrentPoint.X, CurrentPoint.Y ] = Color; } // Makes sure you do not exceed boundaries. int smallestX = CurrentPoint.X > 0 ? -1 : 0; int smallestY = CurrentPoint.Y > 0 ? -1 : 0; int biggestX = CurrentPoint.X < ( input.GetLength( 0 ) - 1 ) ? 1 : 0; int biggestY = CurrentPoint.Y < ( input.GetLength( 1 ) - 1 ) ? 1 : 0; // For every neighbor... for ( int ver = smallestY; ver <= biggestY; ver++ ) { for ( int hor = smallestX; hor <= biggestX; hor++ ) { Point NextPixel = new Point( CurrentPoint.X + hor, CurrentPoint.Y + ver ); //Check if the next pixel is white and if it isn't already in the stack. if ( input[ NextPixel.X, NextPixel.Y ] == 255 && !NeighbouringPixelsUsed.ContainsKey( NextPixel ) ) NeighbouringPixels.Push( new Point( NextPixel.X, NextPixel.Y ) ); } } } ); } Shape S = new Shape( input, new Rectangle( minX, minY, maxX - minX, maxY - minY ), Color ); Shapes.Add( S ); }