c# GDI边缘空白检测算法

发布于 2024-07-12 05:38:41 字数 1296 浏览 4 评论 0原文

我正在寻找一种从 c# 托管 GDI+ 库中检测 c# 位图边缘空白的解决方案。

图像可以是透明白色,大​​多数 400x 图片的尺寸为 8000x8000 像素,边缘周围有大约 2000 像素的空白。

找出边缘、x、y、高度和宽度坐标的最有效方法是什么? 我尝试逐像素进行,但发现速度非常慢。

解决方案更新 --添加了左/右/上/下边界

图像细节中心图像的问题,现在裁剪任何透明(0%)或白色(#FFFFFF)像素。

var top = bitmap.Height;
var left = bitmap.Width;
var right = 0;
var bottom = 0;

……

var pData = pData0 + (y * data.Stride) + (x * 4);
var xyAlpha = pData[3];
var xyBlue = pData[0];
var xyGreen = pData[1];
var xyRed = pData[2];
if ((xyAlpha > 0) || (xyRed != 255 && xyGreen != 255 && xyBlue != 255)) {
    if (y < top)
        top = y;
    if (y > bottom)
        bottom = y;
    if (x < left)
        left = x;
    if (x > right)
        right = x;
}

var cropWidth = right - left;
var cropHeight = bottom - top;
var cropX = top;
var cropY = left;

var cacheBitmap = new Bitmap(cropWidth, cropHeight, PixelFormat.Format32bppArgb);
using (var cacheGraphics = Graphics.FromImage(cacheBitmap)) {
    cacheGraphics.DrawImage(context.Image, new Rectangle(0, 0, cropWidth, cropHeight), cropX, cropY, cropWidth, cropHeight, GraphicsUnit.Pixel);
}

I am looking for a solution for detecting edge whitespace of c# bitmap, from the c# managed GDI+ library.

The images would be either transparent or white, most of the 400x pictures are 8000x8000px with about 2000px whitespace around the edges.

What would be the most efficient way of finding out the edges, x, y, height and width coordinates? I tried a go pixel by pixel but was finding it very slow.

Update to solution
--Added left/right/top/bottom bounds

Problems with images detail center images, now crops any transparent (0%) or white (#FFFFFF) pixels.

var top = bitmap.Height;
var left = bitmap.Width;
var right = 0;
var bottom = 0;

...

var pData = pData0 + (y * data.Stride) + (x * 4);
var xyAlpha = pData[3];
var xyBlue = pData[0];
var xyGreen = pData[1];
var xyRed = pData[2];
if ((xyAlpha > 0) || (xyRed != 255 && xyGreen != 255 && xyBlue != 255)) {
    if (y < top)
        top = y;
    if (y > bottom)
        bottom = y;
    if (x < left)
        left = x;
    if (x > right)
        right = x;
}

...

var cropWidth = right - left;
var cropHeight = bottom - top;
var cropX = top;
var cropY = left;

var cacheBitmap = new Bitmap(cropWidth, cropHeight, PixelFormat.Format32bppArgb);
using (var cacheGraphics = Graphics.FromImage(cacheBitmap)) {
    cacheGraphics.DrawImage(context.Image, new Rectangle(0, 0, cropWidth, cropHeight), cropX, cropY, cropWidth, cropHeight, GraphicsUnit.Pixel);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

秋心╮凉 2024-07-19 05:38:41

Bob Powell 的 GDI+ 常见问题解答

您没有说明如何访问图像中的像素,因此我假设您使用了缓慢的 GetPixel 方法。 您可以使用指针和 LockBits 以更快的方式访问像素: 参见 Bob Powells 对 LockBits 的解释

下面的代码使用 LockBits 方法(对于 PixelFormat.Format32bppArgb )并将用发现图像中第一个和最后一个像素不具有参数颜色中描述的颜色的值填充开始点和结束点。 该方法还忽略完全透明的像素,如果您想检测可见“内容”开始的图像区域,这非常有用。

    Point start = Point.Empty;
    Point end = Point.Empty;
    
    int bitmapWidth = bmp.Width;
    int bitmapHeight = bmp.Height;
    
    #region find start and end point
    BitmapData data = bmp.LockBits(new Rectangle(0, 0, bitmapWidth, bitmapHeight), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
    try
    {
        unsafe
        {
            byte* pData0 = (byte*)data.Scan0;
            for (int y = 0; y < bitmapHeight; y++)
            {
                for (int x = 0; x < bitmapWidth; x++)
                {
                    byte* pData = pData0 + (y * data.Stride) + (x * 4);
    
                    byte xyBlue = pData[0];
                    byte xyGreen = pData[1];
                    byte xyRed = pData[2];
                    byte xyAlpha = pData[3];
    
    
                    if (color.A != xyAlpha
                            || color.B != xyBlue
                            || color.R != xyRed
                            || color.G != xyGreen)
                    {
                        //ignore transparent pixels
                        if (xyAlpha == 0)
                            continue;
                        if (start.IsEmpty)
                        {
                            start = new Point(x, y);
                        }
                        else if (start.Y > y)
                        {
                            start.Y = y;
                        }
                        if (end.IsEmpty)
                        {
                            end = new Point(x, y);
                        }
                        else if (end.X < x)
                        {
                            end.X = x;
                        }
                        else if (end.Y < y)
                        {
                            end.Y = y;
                        }
                    }
                }
            }
        }
    }
    finally
    {
        bmp.UnlockBits(data);
    }
    #endregion

A great GDI+ resource is Bob Powell's GDI+ FAQ!

You didn't say how you accessed the pixels in the image so I will assume that you used the slow GetPixel methods. You can use pointers and LockBits to access pixels in a faster way: see Bob Powells explanation of LockBits

The below code uses the LockBits approach (for the PixelFormat.Format32bppArgb) and will fill the start and end Points with the value where the first and last pixels in an image are discovered that do not have the color described in the argument color. The method also ignores completely transparent pixels which is useful if you want to detect the area of an image where the visible 'content' starts.

    Point start = Point.Empty;
    Point end = Point.Empty;
    
    int bitmapWidth = bmp.Width;
    int bitmapHeight = bmp.Height;
    
    #region find start and end point
    BitmapData data = bmp.LockBits(new Rectangle(0, 0, bitmapWidth, bitmapHeight), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
    try
    {
        unsafe
        {
            byte* pData0 = (byte*)data.Scan0;
            for (int y = 0; y < bitmapHeight; y++)
            {
                for (int x = 0; x < bitmapWidth; x++)
                {
                    byte* pData = pData0 + (y * data.Stride) + (x * 4);
    
                    byte xyBlue = pData[0];
                    byte xyGreen = pData[1];
                    byte xyRed = pData[2];
                    byte xyAlpha = pData[3];
    
    
                    if (color.A != xyAlpha
                            || color.B != xyBlue
                            || color.R != xyRed
                            || color.G != xyGreen)
                    {
                        //ignore transparent pixels
                        if (xyAlpha == 0)
                            continue;
                        if (start.IsEmpty)
                        {
                            start = new Point(x, y);
                        }
                        else if (start.Y > y)
                        {
                            start.Y = y;
                        }
                        if (end.IsEmpty)
                        {
                            end = new Point(x, y);
                        }
                        else if (end.X < x)
                        {
                            end.X = x;
                        }
                        else if (end.Y < y)
                        {
                            end.Y = y;
                        }
                    }
                }
            }
        }
    }
    finally
    {
        bmp.UnlockBits(data);
    }
    #endregion
毅然前行 2024-07-19 05:38:41

我首先确保使用 Patrick 描述的 LockBits 方法。 其次,我会检查中间线上的像素以快速确定边缘。 我所说的中间线是指,如果你说一个 2000x1000 的图像,你会首先沿着水平线编号 500(满分 1000)查找左右限制,然后沿着垂直线编号 1000(满分 2000)查找找到上限和下限。 这样应该会很快。

I'd first make sure to use the LockBits method described by Patrick. Second I'd check the pixels on the middle lines to quickly determine the edges. By middle lines I mean, if you have say for example a 2000x1000 image, you'd look first along horizontal line number 500 (out of 1000) to find the left and right limits, then along vertical line number 1000 (out of 2000) to find the top and bottom limits. It should be very fast this way.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文