自动裁剪位图来最小尺寸?

编程入门 行业动态 更新时间:2024-10-26 17:21:33
本文介绍了自动裁剪位图来最小尺寸?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

假设我在32bpp的ARGB模式有一个 System.Drawing.Bitmap 。这是一个大的位图,但是它在中间某处的大多完全透明的像素具有相对小的图像。

Suppose I have a System.Drawing.Bitmap in 32bpp ARGB mode. It's a large bitmap, but it's mostly fully transparent pixels with a relatively small image somewhere in the middle.

什么是快速算法来检测真实形象的边界,这样我就可以从它周围的裁剪了所有的透明像素?

What is a fast algorithm to detect the borders of the "real" image, so I can crop away all the transparent pixels from around it?

另外,有已经在中的函数,我可以用这个?

Alternatively, is there a function already in .Net that I can use for this?

推荐答案

的基本思想是对检查图像的每一个像素,找到顶,左,右和图象的底部边界。为了有效地做到这一点,不要使用 GetPixel 方法,这是pretty缓慢。使用 LockBits 代替。

The basic idea is to check every pixel of the image to find the top, left, right and bottom bounds of the image. To do this efficiently, don't use the GetPixel method, which is pretty slow. Use LockBits instead.

这是我想出了实现:

static Bitmap TrimBitmap(Bitmap source) { Rectangle srcRect = default(Rectangle); BitmapData data = null; try { data = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); byte[] buffer = new byte[data.Height * data.Stride]; Marshal.Copy(data.Scan0, buffer, 0, buffer.Length); int xMin = int.MaxValue; int xMax = 0; int yMin = int.MaxValue; int yMax = 0; for (int y = 0; y < data.Height; y++) { for (int x = 0; x < data.Width; x++) { byte alpha = buffer[y * data.Stride + 4 * x + 3]; if (alpha != 0) { if (x < xMin) xMin = x; if (x > xMax) xMax = x; if (y < yMin) yMin = y; if (y > yMax) yMax = y; } } } if (xMax < xMin || yMax < yMin) { // Image is empty... return null; } srcRect = Rectangle.FromLTRB(xMin, yMin, xMax, yMax); } finally { if (data != null) source.UnlockBits(data); } Bitmap dest = new Bitmap(srcRect.Width, srcRect.Height); Rectangle destRect = new Rectangle(0, 0, srcRect.Width, srcRect.Height); using (Graphics graphics = Graphics.FromImage(dest)) { graphics.DrawImage(source, destRect, srcRect, GraphicsUnit.Pixel); } return dest; }

大概可以优化,但我不是一个GDI +专家,所以这是最好的,我可以不用做进一步的研究...

It can probably be optimized, but I'm not a GDI+ expert, so it's the best I can do without further research...

编辑:实际上,有一个简单的方法来优化它,通过不扫描图像的某些部分:

actually, there's a simple way to optimize it, by not scanning some parts of the image :

  • 扫描从左到右,直到找到一个非透明像素;存储(X,Y)成(XMIN,YMIN)
  • 扫描从上到下,直到找到一个非透明像素(仅对于x> = XMIN);店内Y考虑YMIN
  • 扫描从右到左,直到找到一个非透明像素(仅适用于Y> = YMIN);店内x转换成XMAX
  • 扫描下往上,直到找到一个非透明像素(仅适用于XMIN&LT; = X&LT; = XMAX);店内Y考虑YMAX
  • EDIT2:这里的方法的实现上面:

    here's an implementation of the approach above:

    static Bitmap TrimBitmap(Bitmap source) { Rectangle srcRect = default(Rectangle); BitmapData data = null; try { data = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); byte[] buffer = new byte[data.Height * data.Stride]; Marshal.Copy(data.Scan0, buffer, 0, buffer.Length); int xMin = int.MaxValue, xMax = int.MinValue, yMin = int.MaxValue, yMax = int.MinValue; bool foundPixel = false; // Find xMin for (int x = 0; x < data.Width; x++) { bool stop = false; for (int y = 0; y < data.Height; y++) { byte alpha = buffer[y * data.Stride + 4 * x + 3]; if (alpha != 0) { xMin = x; stop = true; foundPixel = true; break; } } if (stop) break; } // Image is empty... if (!foundPixel) return null; // Find yMin for (int y = 0; y < data.Height; y++) { bool stop = false; for (int x = xMin; x < data.Width; x++) { byte alpha = buffer[y * data.Stride + 4 * x + 3]; if (alpha != 0) { yMin = y; stop = true; break; } } if (stop) break; } // Find xMax for (int x = data.Width - 1; x >= xMin; x--) { bool stop = false; for (int y = yMin; y < data.Height; y++) { byte alpha = buffer[y * data.Stride + 4 * x + 3]; if (alpha != 0) { xMax = x; stop = true; break; } } if (stop) break; } // Find yMax for (int y = data.Height - 1; y >= yMin; y--) { bool stop = false; for (int x = xMin; x <= xMax; x++) { byte alpha = buffer[y * data.Stride + 4 * x + 3]; if (alpha != 0) { yMax = y; stop = true; break; } } if (stop) break; } srcRect = Rectangle.FromLTRB(xMin, yMin, xMax, yMax); } finally { if (data != null) source.UnlockBits(data); } Bitmap dest = new Bitmap(srcRect.Width, srcRect.Height); Rectangle destRect = new Rectangle(0, 0, srcRect.Width, srcRect.Height); using (Graphics graphics = Graphics.FromImage(dest)) { graphics.DrawImage(source, destRect, srcRect, GraphicsUnit.Pixel); } return dest; }

    有将不会是一个显著增益如果非透明部分是小当然,因为它仍然会扫描大部分像素。但是,如果它的大,大约只有非透明部分的矩形将被扫描。

    There won't be a significant gain if the non-transparent part is small of course, since it will still scan most of the pixels. But if it's big, only the rectangles around the non-transparent part will be scanned.

    更多推荐

    自动裁剪位图来最小尺寸?

    本文发布于:2023-08-02 03:45:34,感谢您对本站的认可!
    本文链接:https://www.elefans.com/category/jswz/34/1274346.html
    版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
    本文标签:位图   最小   尺寸

    发布评论

    评论列表 (有 0 条评论)
    草根站长

    >www.elefans.com

    编程频道|电子爱好者 - 技术资讯及电子产品介绍!