裁剪/删除图像边缘的不需要的空间

我搜索了很多,以删除不需要的空间,但无法找到。 我只找到了可用于删除黑白背景空间的链接。 但我的背景图片可以是任何东西。 那么,如果我有这些图像,

在此处输入图像描述

此搜索

在此处输入图像描述

如何提取我需要的图像部分。 例如,

在此处输入图像描述在此处输入图像描述在此处输入图像描述

这是我的问题解决方案:

我已经声明了一个获取原始图像的方法然后它通过检查提供的图像的角来查找背景颜色,如果至少3个角具有相似的颜色(最多10%偏移),那么我们找到了背景颜色然后它试图在图像中找到那些形状的边界,当然这些形状具有与背景颜色不同的颜色

查找边界后,函数裁剪图像并将新的裁剪区域作为新的位图返回!

这是演示文件: 下载

完整解决方案: 下载

以下是结果:

Image 1

在此处输入图像描述

Image 2

在此处输入图像描述

Image 3

在此处输入图像描述

这里是ImageProcessingTools类中的函数简化,

 public class ImageHelper { #region CropUnwantedBackground public static Bitmap CropUnwantedBackground(Bitmap bmp) { var backColor = GetMatchedBackColor(bmp); if (backColor.HasValue) { var bounds = GetImageBounds(bmp, backColor); var diffX = bounds[1].X - bounds[0].X + 1; var diffY = bounds[1].Y - bounds[0].Y + 1; var croppedBmp = new Bitmap(diffX, diffY); var g = Graphics.FromImage(croppedBmp); var destRect = new Rectangle(0, 0, croppedBmp.Width, croppedBmp.Height); var srcRect = new Rectangle(bounds[0].X, bounds[0].Y, diffX, diffY); g.DrawImage(bmp, destRect, srcRect, GraphicsUnit.Pixel); return croppedBmp; } else { return null; } } #endregion #region Private Methods #region GetImageBounds private static Point[] GetImageBounds(Bitmap bmp, Color? backColor) { //-------------------------------------------------------------------- // Finding the Bounds of Crop Area bu using Unsafe Code and Image Proccesing Color c; int width = bmp.Width, height = bmp.Height; bool upperLeftPointFounded = false; var bounds = new Point[2]; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { c = bmp.GetPixel(x, y); bool sameAsBackColor = ((cR <= backColor.Value.R * 1.1 && cR >= backColor.Value.R * 0.9) && (cG <= backColor.Value.G * 1.1 && cG >= backColor.Value.G * 0.9) && (cB <= backColor.Value.B * 1.1 && cB >= backColor.Value.B * 0.9)); if (!sameAsBackColor) { if (!upperLeftPointFounded) { bounds[0] = new Point(x, y); bounds[1] = new Point(x, y); upperLeftPointFounded = true; } else { if (x > bounds[1].X) bounds[1].X = x; else if (x < bounds[0].X) bounds[0].X = x; if (y >= bounds[1].Y) bounds[1].Y = y; } } } } return bounds; } #endregion #region GetMatchedBackColor private static Color? GetMatchedBackColor(Bitmap bmp) { // Getting The Background Color by checking Corners of Original Image var corners = new Point[]{ new Point(0, 0), new Point(0, bmp.Height - 1), new Point(bmp.Width - 1, 0), new Point(bmp.Width - 1, bmp.Height - 1) }; // four corners (Top, Left), (Top, Right), (Bottom, Left), (Bottom, Right) for (int i = 0; i < 4; i++) { var cornerMatched = 0; var backColor = bmp.GetPixel(corners[i].X, corners[i].Y); for (int j = 0; j < 4; j++) { var cornerColor = bmp.GetPixel(corners[j].X, corners[j].Y);// Check RGB with some offset if ((cornerColor.R <= backColor.R * 1.1 && cornerColor.R >= backColor.R * 0.9) && (cornerColor.G <= backColor.G * 1.1 && cornerColor.G >= backColor.G * 0.9) && (cornerColor.B <= backColor.B * 1.1 && cornerColor.B >= backColor.B * 0.9)) { cornerMatched++; } } if (cornerMatched > 2) { return backColor; } } return null; } #endregion #endregion } 

这是ASP.NET中的一个简单用法,

 if (IsPostBack && Request.Files.Count > 0) { var file = Request.Files[0]; var bmp = new Bitmap(file.InputStream); var croppedBmp = ImageHelper.CropUnwantedBackground(bmp); Response.ContentType = file.ContentType; croppedBmp.Save(Response.OutputStream, ImageFormat.Jpeg); Response.End(); } 

最后我要提一下,这些神奇的教程在图像处理方面给了我很多帮助:

用C#和GDI +处理虚拟对象的图像处理

使用C#进行图像处理

希望能帮助到你 :)

这是一种更可靠的方法,它使用Sobel能量filter和快速边界框检测程序(从ImageResizer的WhitespaceTrimmer插件中提取)。

 namespace ImageResizer.Plugins.WhitespaceTrimmer { public class BoundingBoxFinder { ///  /// Returns a rectangle inside 'lookInside' that bounds any energy greater than 'threshold'. ///  ///  /// A rectangle of 'image' to look inside.  /// 1-255, the energy threshold to detect activity. 80-150 is a good range. ///  public Rectangle FindBoxSobel(Bitmap originalImage, Rectangle lookInside, byte threshold) { Bitmap image = originalImage; try { //Convert if needed (makes an extra copy) if (image.PixelFormat != PixelFormat.Format24bppRgb && image.PixelFormat != PixelFormat.Format32bppArgb && image.PixelFormat != PixelFormat.Format32bppRgb) { image = AForge.Imaging.Image.Clone(image, PixelFormat.Format24bppRgb); } //Crop if needed (makes an extra copy unless we converted too, then only 1 extra copy) if (!lookInside.Equals(new Rectangle(0, 0, image.Width, image.Height))) { Bitmap oldImage = image; try { image = new Crop(lookInside).Apply(image); } finally { if (oldImage != originalImage) oldImage.Dispose(); //Dispose the cloned } } //Makes 1 more copy at 1/3rd the size, in grayscale Rectangle result = FindBoxSobel(image, threshold); return new Rectangle(lookInside.X + result.X, lookInside.Y + result.Y, result.Width, result.Height); } finally { if (image != originalImage) image.Dispose(); } } ///  /// Requires 24 bit or 32 bit (A) RGB image. ///  ///  ///  ///  public Rectangle FindBoxSobel(Bitmap rgb, byte threshold) { using (Bitmap gray = Grayscale.CommonAlgorithms.Y.Apply(rgb)) { //Apply sobel operator to grayscale image new SobelEdgeDetector().ApplyInPlace(gray); //Threshold into black and white. new Threshold(threshold).ApplyInPlace(gray); //Trim only exact black pixels // lock source bitmap data BitmapData data = gray.LockBits(new Rectangle(0, 0, gray.Width, gray.Height), ImageLockMode.ReadOnly, gray.PixelFormat); try { return FindBoxExactGrayscale(data, 0); } finally { gray.UnlockBits(data); } } } ///  /// Returns a bounding box that only excludes the specified color. /// Only works on 8-bit images. ///  ///  /// The palette index to remove. ///  public Rectangle FindBoxExactGrayscale(BitmapData sourceData, byte indexToRemove) { if (sourceData.PixelFormat != PixelFormat.Format8bppIndexed) throw new ArgumentOutOfRangeException("FindBoxExact only operates on 8-bit grayscale images"); // get source image size int width = sourceData.Width; int height = sourceData.Height; int offset = sourceData.Stride - width; int minX = width; int minY = height; int maxX = 0; int maxY = 0; // find rectangle which contains something except color to remove unsafe { byte* src = (byte*)sourceData.Scan0; for (int y = 0; y < height; y++) { if (y > 0) src += offset; //Don't adjust for offset until after first row for (int x = 0; x < width; x++) { if (x > 0 || y > 0) src++; //Don't increment until after the first pixel. if (*src != indexToRemove) { if (x < minX) minX = x; if (x > maxX) maxX = x; if (y < minY) minY = y; if (y > maxY) maxY = y; } } } } // check if ((minX == width) && (minY == height) && (maxX == 0) && (maxY == 0)) { minX = minY = 0; } return new Rectangle(minX,minY,maxX - minX + 1, maxY - minY + 1); } } }