/// <summary> /// Finds the bounding rectangle based on the first instance of any color component other /// than the given one. /// </summary> /// <typeparam name="TColor">The pixel format.</typeparam> /// <param name="bitmap">The <see cref="Image"/> to search within.</param> /// <param name="componentValue">The color component value to remove.</param> /// <param name="channel">The <see cref="RgbaComponent"/> channel to test against.</param> /// <returns> /// The <see cref="Rectangle"/>. /// </returns> public static Rectangle GetFilteredBoundingRectangle <TColor>(ImageBase <TColor> bitmap, float componentValue, RgbaComponent channel = RgbaComponent.B) where TColor : struct, IPixel <TColor> { int width = bitmap.Width; int height = bitmap.Height; Point topLeft = default(Point); Point bottomRight = default(Point); Func <PixelAccessor <TColor>, int, int, float, bool> delegateFunc; // Determine which channel to check against switch (channel) { case RgbaComponent.R: delegateFunc = (pixels, x, y, b) => MathF.Abs(pixels[x, y].ToVector4().X - b) > Constants.Epsilon; break; case RgbaComponent.G: delegateFunc = (pixels, x, y, b) => MathF.Abs(pixels[x, y].ToVector4().Y - b) > Constants.Epsilon; break; case RgbaComponent.B: delegateFunc = (pixels, x, y, b) => MathF.Abs(pixels[x, y].ToVector4().Z - b) > Constants.Epsilon; break; default: delegateFunc = (pixels, x, y, b) => MathF.Abs(pixels[x, y].ToVector4().W - b) > Constants.Epsilon; break; } Func <PixelAccessor <TColor>, int> getMinY = pixels => { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { if (delegateFunc(pixels, x, y, componentValue)) { return(y); } } } return(0); }; Func <PixelAccessor <TColor>, int> getMaxY = pixels => { for (int y = height - 1; y > -1; y--) { for (int x = 0; x < width; x++) { if (delegateFunc(pixels, x, y, componentValue)) { return(y); } } } return(height); }; Func <PixelAccessor <TColor>, int> getMinX = pixels => { for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (delegateFunc(pixels, x, y, componentValue)) { return(x); } } } return(0); }; Func <PixelAccessor <TColor>, int> getMaxX = pixels => { for (int x = width - 1; x > -1; x--) { for (int y = 0; y < height; y++) { if (delegateFunc(pixels, x, y, componentValue)) { return(x); } } } return(height); }; using (PixelAccessor <TColor> bitmapPixels = bitmap.Lock()) { topLeft.Y = getMinY(bitmapPixels); topLeft.X = getMinX(bitmapPixels); bottomRight.Y = (getMaxY(bitmapPixels) + 1).Clamp(0, height); bottomRight.X = (getMaxX(bitmapPixels) + 1).Clamp(0, width); } return(GetBoundingRectangle(topLeft, bottomRight)); }
/// <summary> /// Finds the bounding rectangle based on the first instance of any color component other /// than the given one. /// </summary> /// <param name="bitmap"> /// The <see cref="Image"/> to search within. /// </param> /// <param name="componentValue"> /// The color component value to remove. /// </param> /// <param name="channel"> /// The <see cref="RgbaComponent"/> channel to test against. /// </param> /// <returns> /// The <see cref="Rectangle"/>. /// </returns> public static Rectangle GetFilteredBoundingRectangle(ImageBase bitmap, float componentValue, RgbaComponent channel = RgbaComponent.B) { const float Epsilon = .00001f; int width = bitmap.Width; int height = bitmap.Height; Point topLeft = new Point(); Point bottomRight = new Point(); Func<ImageBase, int, int, float, bool> delegateFunc; // Determine which channel to check against switch (channel) { case RgbaComponent.R: delegateFunc = (imageBase, x, y, b) => Math.Abs(imageBase[x, y].R - b) > Epsilon; break; case RgbaComponent.G: delegateFunc = (imageBase, x, y, b) => Math.Abs(imageBase[x, y].G - b) > Epsilon; break; case RgbaComponent.A: delegateFunc = (imageBase, x, y, b) => Math.Abs(imageBase[x, y].A - b) > Epsilon; break; default: delegateFunc = (imageBase, x, y, b) => Math.Abs(imageBase[x, y].B - b) > Epsilon; break; } Func<ImageBase, int> getMinY = imageBase => { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { if (delegateFunc(imageBase, x, y, componentValue)) { return y; } } } return 0; }; Func<ImageBase, int> getMaxY = imageBase => { for (int y = height - 1; y > -1; y--) { for (int x = 0; x < width; x++) { if (delegateFunc(imageBase, x, y, componentValue)) { return y; } } } return height; }; Func<ImageBase, int> getMinX = imageBase => { for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (delegateFunc(imageBase, x, y, componentValue)) { return x; } } } return 0; }; Func<ImageBase, int> getMaxX = imageBase => { for (int x = width - 1; x > -1; x--) { for (int y = 0; y < height; y++) { if (delegateFunc(imageBase, x, y, componentValue)) { return x; } } } return height; }; topLeft.Y = getMinY(bitmap); topLeft.X = getMinX(bitmap); bottomRight.Y = (getMaxY(bitmap) + 1).Clamp(0, height); bottomRight.X = (getMaxX(bitmap) + 1).Clamp(0, width); return GetBoundingRectangle(topLeft, bottomRight); }
/// <summary> /// Finds the bounding rectangle based on the first instance of any color component other /// than the given one. /// </summary> /// <typeparam name="TPixel">The pixel format.</typeparam> /// <param name="bitmap">The <see cref="Image{TPixel}"/> to search within.</param> /// <param name="componentValue">The color component value to remove.</param> /// <param name="channel">The <see cref="RgbaComponent"/> channel to test against.</param> /// <returns> /// The <see cref="Rectangle"/>. /// </returns> public static Rectangle GetFilteredBoundingRectangle <TPixel>(ImageFrame <TPixel> bitmap, float componentValue, RgbaComponent channel = RgbaComponent.B) where TPixel : struct, IPixel <TPixel> { int width = bitmap.Width; int height = bitmap.Height; Point topLeft = default; Point bottomRight = default; Func <ImageFrame <TPixel>, int, int, float, bool> delegateFunc; // Determine which channel to check against switch (channel) { case RgbaComponent.R: delegateFunc = (pixels, x, y, b) => MathF.Abs(pixels[x, y].ToVector4().X - b) > Constants.Epsilon; break; case RgbaComponent.G: delegateFunc = (pixels, x, y, b) => MathF.Abs(pixels[x, y].ToVector4().Y - b) > Constants.Epsilon; break; case RgbaComponent.B: delegateFunc = (pixels, x, y, b) => MathF.Abs(pixels[x, y].ToVector4().Z - b) > Constants.Epsilon; break; default: delegateFunc = (pixels, x, y, b) => MathF.Abs(pixels[x, y].ToVector4().W - b) > Constants.Epsilon; break; } int GetMinY(ImageFrame <TPixel> pixels) { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { if (delegateFunc(pixels, x, y, componentValue)) { return(y); } } } return(0); } int GetMaxY(ImageFrame <TPixel> pixels) { for (int y = height - 1; y > -1; y--) { for (int x = 0; x < width; x++) { if (delegateFunc(pixels, x, y, componentValue)) { return(y); } } } return(height); } int GetMinX(ImageFrame <TPixel> pixels) { for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (delegateFunc(pixels, x, y, componentValue)) { return(x); } } } return(0); } int GetMaxX(ImageFrame <TPixel> pixels) { for (int x = width - 1; x > -1; x--) { for (int y = 0; y < height; y++) { if (delegateFunc(pixels, x, y, componentValue)) { return(x); } } } return(height); } topLeft.Y = GetMinY(bitmap); topLeft.X = GetMinX(bitmap); bottomRight.Y = (GetMaxY(bitmap) + 1).Clamp(0, height); bottomRight.X = (GetMaxX(bitmap) + 1).Clamp(0, width); return(GetBoundingRectangle(topLeft, bottomRight)); }
/// <summary> /// Finds the bounding rectangle based on the first instance of any color component other /// than the given one. /// </summary> /// <param name="bitmap"> /// The <see cref="Image"/> to search within. /// </param> /// <param name="componentValue"> /// The color component value to remove. /// </param> /// <param name="channel"> /// The <see cref="RgbaComponent"/> channel to test against. /// </param> /// <returns> /// The <see cref="Rectangle"/>. /// </returns> public static Rectangle GetFilteredBoundingRectangle(Image bitmap, byte componentValue, RgbaComponent channel = RgbaComponent.B) { int width = bitmap.Width; int height = bitmap.Height; Point topLeft = new Point(); Point bottomRight = new Point(); Func <FastBitmap, int, int, byte, bool> delegateFunc; // Determine which channel to check against switch (channel) { case RgbaComponent.R: delegateFunc = (fastBitmap, x, y, b) => fastBitmap.GetPixel(x, y).R != b; break; case RgbaComponent.G: delegateFunc = (fastBitmap, x, y, b) => fastBitmap.GetPixel(x, y).G != b; break; case RgbaComponent.A: delegateFunc = (fastBitmap, x, y, b) => fastBitmap.GetPixel(x, y).A != b; break; default: delegateFunc = (fastBitmap, x, y, b) => fastBitmap.GetPixel(x, y).B != b; break; } Func <FastBitmap, int> getMinY = fastBitmap => { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { if (delegateFunc(fastBitmap, x, y, componentValue)) { return(y); } } } return(0); }; Func <FastBitmap, int> getMaxY = fastBitmap => { for (int y = height - 1; y > -1; y--) { for (int x = 0; x < width; x++) { if (delegateFunc(fastBitmap, x, y, componentValue)) { return(y); } } } return(height); }; Func <FastBitmap, int> getMinX = fastBitmap => { for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (delegateFunc(fastBitmap, x, y, componentValue)) { return(x); } } } return(0); }; Func <FastBitmap, int> getMaxX = fastBitmap => { for (int x = width - 1; x > -1; x--) { for (int y = 0; y < height; y++) { if (delegateFunc(fastBitmap, x, y, componentValue)) { return(x); } } } return(height); }; using (FastBitmap fastBitmap = new FastBitmap(bitmap)) { topLeft.Y = getMinY(fastBitmap); topLeft.X = getMinX(fastBitmap); bottomRight.Y = getMaxY(fastBitmap) + 1; bottomRight.X = getMaxX(fastBitmap) + 1; } return(GetBoundingRectangle(topLeft, bottomRight)); }
/// <summary> /// Finds the bounding rectangle based on the first instance of any color component other /// than the given one. /// </summary> /// <typeparam name="T">The pixel format.</typeparam> /// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam> /// <param name="bitmap">The <see cref="Image"/> to search within.</param> /// <param name="componentValue">The color component value to remove.</param> /// <param name="channel">The <see cref="RgbaComponent"/> channel to test against.</param> /// <returns> /// The <see cref="Rectangle"/>. /// </returns> public static Rectangle GetFilteredBoundingRectangle <T, TP>(ImageBase <T, TP> bitmap, float componentValue, RgbaComponent channel = RgbaComponent.B) where T : IPackedVector <TP> where TP : struct { const float Epsilon = .00001f; int width = bitmap.Width; int height = bitmap.Height; Point topLeft = new Point(); Point bottomRight = new Point(); Func <IPixelAccessor <T, TP>, int, int, float, bool> delegateFunc; // Determine which channel to check against switch (channel) { case RgbaComponent.R: delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToBytes()[0] - b) > Epsilon; break; case RgbaComponent.G: delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToBytes()[1] - b) > Epsilon; break; case RgbaComponent.B: delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToBytes()[2] - b) > Epsilon; break; default: delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToBytes()[3] - b) > Epsilon; break; } Func <IPixelAccessor <T, TP>, int> getMinY = pixels => { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { if (delegateFunc(pixels, x, y, componentValue)) { return(y); } } } return(0); }; Func <IPixelAccessor <T, TP>, int> getMaxY = pixels => { for (int y = height - 1; y > -1; y--) { for (int x = 0; x < width; x++) { if (delegateFunc(pixels, x, y, componentValue)) { return(y); } } } return(height); }; Func <IPixelAccessor <T, TP>, int> getMinX = pixels => { for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (delegateFunc(pixels, x, y, componentValue)) { return(x); } } } return(0); }; Func <IPixelAccessor <T, TP>, int> getMaxX = pixels => { for (int x = width - 1; x > -1; x--) { for (int y = 0; y < height; y++) { if (delegateFunc(pixels, x, y, componentValue)) { return(x); } } } return(height); }; using (IPixelAccessor <T, TP> bitmapPixels = bitmap.Lock()) { topLeft.Y = getMinY(bitmapPixels); topLeft.X = getMinX(bitmapPixels); bottomRight.Y = (getMaxY(bitmapPixels) + 1).Clamp(0, height); bottomRight.X = (getMaxX(bitmapPixels) + 1).Clamp(0, width); } return(GetBoundingRectangle(topLeft, bottomRight)); }