加速CropTransparentPixels方法的最佳方法

时间:2017-12-11 19:37:41

标签: c# algorithm

我刚刚编写了这种方法来从图像中裁剪透明像素。

似乎工作正常,但由于GetPixel而非常慢 - 有关如何使算法逻辑更快的任何想法?

我知道我可以更改GetPixel以获得更快(但不安全)的访问代码,我可能会这样做,但是我想办法避免进行全面扫描。我想知道如何更快地使这个算法背后的逻辑。

public Bitmap CropTransparentPixels(Bitmap originalBitmap)
{
    // Find the min/max transparent pixels
    Point min = new Point(int.MaxValue, int.MaxValue);
    Point max = new Point(int.MinValue, int.MinValue);

    for (int x = 0; x < originalBitmap.Width; ++x)
    {
        for (int y = 0; y < originalBitmap.Height; ++y)
        {
            Color pixelColor = originalBitmap.GetPixel(x, y);

            if (pixelColor.A == 255)
            {
                if (x < min.X) min.X = x;
                if (y < min.Y) min.Y = y;

                if (x > max.X) max.X = x;
                if (y > max.Y) max.Y = y;
            }
        }
    }

    // Create a new bitmap from the crop rectangle
    Rectangle cropRectangle = new Rectangle(min.X, min.Y, max.X - min.X, max.Y - min.Y);
    Bitmap newBitmap = new Bitmap(cropRectangle.Width, cropRectangle.Height);
    using (Graphics g = Graphics.FromImage(newBitmap))
    {
        g.DrawImage(originalBitmap, 0, 0, cropRectangle, GraphicsUnit.Pixel);
    }

    return newBitmap;
}

1 个答案:

答案 0 :(得分:1)

这是我写作的方法,速度要快得多。

public static Bitmap CropTransparentPixels(this Bitmap bmp)
{
    BitmapData bmData = null;

    try
    {
        bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

        int scanline = bmData.Stride;

        IntPtr Scan0 = bmData.Scan0;

        Point top = new Point(), left = new Point(), right = new Point(), bottom = new Point();
        bool complete = false;

        unsafe
        {
            byte* p = (byte*)(void*)Scan0;

            for (int y = 0; y < bmp.Height; y++)
            {
                for (int x = 0; x < bmp.Width; x++)
                {
                    if (p[3] != 0)
                    {
                        top = new Point(x, y);
                        complete = true;
                        break;
                    }

                    p += 4;
                }
                if (complete)
                    break;
            }

            p = (byte*)(void*)Scan0;
            complete = false;

            for (int y = bmp.Height - 1; y >= 0; y--)
            {
                for (int x = 0; x < bmp.Width; x++)
                {
                    if (p[x * 4 + y * scanline + 3] != 0)
                    {
                        bottom = new Point(x + 1, y + 1);
                        complete = true;
                        break;
                    }
                }
                if (complete)
                    break;
            }

            p = (byte*)(void*)Scan0;
            complete = false;

            for (int x = 0; x < bmp.Width; x++)
            {
                for (int y = 0; y < bmp.Height; y++)
                {
                    if (p[x * 4 + y * scanline + 3] != 0)
                    {
                        left = new Point(x, y);
                        complete = true;
                        break;
                    }
                }
                if (complete)
                    break;
            }

            p = (byte*)(void*)Scan0;
            complete = false;

            for (int x = bmp.Width - 1; x >= 0; x--)
            {
                for (int y = 0; y < bmp.Height; y++)
                {
                    if (p[x * 4 + y * scanline + 3] != 0)
                    {
                        right = new Point(x + 1, y + 1);
                        complete = true;
                        break;
                    }
                }
                if (complete)
                    break;
            }
        }

        bmp.UnlockBits(bmData);

        System.Drawing.Rectangle rectangle = new Rectangle(left.X, top.Y, right.X - left.X, bottom.Y - top.Y);

        Bitmap b = new Bitmap(rectangle.Width, rectangle.Height);

        Graphics g = Graphics.FromImage(b);

        g.DrawImage(bmp, 0, 0, rectangle, GraphicsUnit.Pixel);

        g.Dispose();

        return b;
    }
    catch
    {
        try
        {
            bmp.UnlockBits(bmData);
        }
        catch { }
        return null;
    }
}