//Scan-line flood fill, much faster //https://lodev.org/cgtutor/floodfill.html#Scanline_Floodfill_Algorithm_With_Stack public static PixelMatrix FloodFillLine(PixelMatrix bmp, int x, int y, Color replacementColor) { Point pt = new Point(x, y); Color targetColor = bmp.GetPixel(pt.x, pt.y); if (targetColor == replacementColor) { return(bmp); } Stack <Point> pixels = new Stack <Point>(); pixels.Push(pt); while (pixels.Count != 0) { Point temp = pixels.Pop(); int y1 = temp.y; while (y1 >= 0 && bmp.GetPixel(temp.x, y1) == targetColor) { y1--; } y1++; bool spanLeft = false; bool spanRight = false; while (y1 < bmp.height && bmp.GetPixel(temp.x, y1) == targetColor) { bmp.SetPixelSafe(temp.x, y1, replacementColor); Color clm1 = bmp.GetPixel(temp.x - 1, y1); Color clp1 = bmp.GetPixel(temp.x + 1, y1); if (!spanLeft && temp.x > 0 && clm1 == targetColor) { pixels.Push(new Point(temp.x - 1, y1)); spanLeft = true; } else if (spanLeft && temp.x - 1 >= 0 && clm1 != targetColor) { spanLeft = false; } if (!spanRight && temp.x < bmp.width - 1 && clp1 == targetColor) { pixels.Push(new Point(temp.x + 1, y1)); spanRight = true; } else if (spanRight && temp.x < bmp.width - 1 && clp1 != targetColor) { spanRight = false; } y1++; } } return(bmp); }
/// <summary> /// Calculates the best-fitting character based on Mean squared error. See <see cref="RenderOption.CalculateCharForMatrix(PixelMatrix)"/> and <see cref="https://en.wikipedia.org/wiki/Mean_squared_error"/> for more information. /// </summary> /// <param name="tile">The part of the image to be represented.</param> /// <returns>The best-fitting character and its corresponding PixelMatrix.</returns> public override KeyValuePair <char, PixelMatrix> CalculateCharForMatrix(PixelMatrix tile) { double minScore = double.MaxValue; KeyValuePair <char, PixelMatrix> bestFit = Font.Chars.FirstOrDefault(); foreach (var item in Font.Chars) { double score = 0; for (int y = 0; y < Font.CharSize.Height; y++) { for (int x = 0; x < Font.CharSize.Width; x += Utils.BytesPerPixel) { byte grayChar = Utils.ColorToGray(item.Value.GetPixel(x, y)); byte grayMatrix = Utils.ColorToGray(tile.GetPixel(x, y)); score += (grayMatrix - grayChar) * (grayMatrix - grayChar); } } if (score < minScore) { bestFit = item; minScore = score; } } return(bestFit); }
/// <summary> /// Calculates the best-fitting character based on Structural similarity index. See <see cref="RenderOption.CalculateCharForMatrix(PixelMatrix)"/> and <see cref="https://en.wikipedia.org/wiki/Structural_similarity"/> for more information. /// </summary> /// <param name="tile">The part of the image to be represented.</param> /// <returns>The best-fitting character and its corresponding PixelMatrix.</returns> public override KeyValuePair <char, PixelMatrix> CalculateCharForMatrix(PixelMatrix tile) { double maxScore = RenderingMode == RenderingMode.Default ? double.MinValue : double.MaxValue; KeyValuePair <char, PixelMatrix> bestFit = Font.Chars.FirstOrDefault(); foreach (var item in Font.Chars) { double score = 0; double covariance = 0; for (int y = 0; y < Font.CharSize.Height; y++) { for (int x = 0; x < Font.CharSize.Width; x += Utils.BytesPerPixel) { byte grayChar = Utils.ColorToGray(item.Value.GetPixel(x, y)); byte grayMatrix = Utils.ColorToGray(tile.GetPixel(x, y)); covariance += (grayChar - item.Value.Mean) * (grayMatrix - tile.Mean); } } covariance /= Font.CharSize.Height * Font.CharSize.Width; score = (2 * Math.Sqrt(item.Value.Variance) * Math.Sqrt(tile.Variance) + C1) * (2 * covariance + C2); score /= (item.Value.Mean * item.Value.Mean + tile.Mean * tile.Mean + C1) * (covariance * covariance + C2); if (RenderingMode == RenderingMode.Default && score > maxScore) { bestFit = item; maxScore = score; } else if (RenderingMode == RenderingMode.Inverted && score < maxScore) { bestFit = item; maxScore = score; } } return(bestFit); }
/// <summary> /// Copies the pixel values to the output image. See <see cref="Converter{T}.AddToOutput(KeyValuePair{char, PixelMatrix}, Point, PixelMatrix)"/> for more information. /// </summary> /// <param name="character">The character to be drawn.</param> /// <param name="point">A point that represents the coordinates of the upper left corner to be drawn.</param> /// <param name="tile">The PixelMatrix representing a tile of the source image.</param> protected override void AddToOutput(KeyValuePair <char, PixelMatrix> character, Point point, PixelMatrix tile) { for (int y = point.Y; y < point.Y + RenderOptions.TileSize.Height; y++) { for (int x = point.X * Utils.BytesPerPixel; x < (point.X + RenderOptions.TileSize.Width) * Utils.BytesPerPixel; x += Utils.BytesPerPixel) { int index = y * _size.Width * Utils.BytesPerPixel; System.Drawing.Color c = DrawingMode.CalculateColor(character.Value.GetPixel(x - Utils.BytesPerPixel * point.X, y - point.Y), tile.GetPixel(x - Utils.BytesPerPixel * point.X, y - point.Y)); _pixels[index + x] = c.B; // b _pixels[index + x + 1] = c.G; // g _pixels[index + x + 2] = c.R; // r _pixels[index + x + 3] = c.A; // a } } }