在C#中裁剪图像的空白部分

3

你是在寻找第三方库还是本地代码?遍历边缘以检查空白并调整图像大小相当容易,但并不是最优的方法。有第三方库可以更加优化地为您提供此类功能。 - Graymatter
我对第三方库没有问题 - 最好是免费的,因为这是一个内部项目。 - Richard West
请查看此答案。它假设透明空格,但您可以轻松调整逻辑以满足您的需求。 - Thomas Levesque
1个回答

16

在这里找到了一个解决方案但修改了返回代码部分以允许输入空白图像,在这种情况下将返回原始图像。

class ImageCrop
{
    public static byte[][] GetRGB(Bitmap bmp)
    {
        BitmapData bmp_data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
        IntPtr ptr = bmp_data.Scan0;
        int num_pixels = bmp.Width * bmp.Height, num_bytes = bmp_data.Stride * bmp.Height, padding = bmp_data.Stride - bmp.Width * 3, i = 0, ct = 1;
        byte[] r = new byte[num_pixels], g = new byte[num_pixels], b = new byte[num_pixels], rgb = new byte[num_bytes];
        System.Runtime.InteropServices.Marshal.Copy(ptr, rgb, 0, num_bytes);

        for (int x = 0; x < num_bytes - 3; x += 3)
        {
            if (x == (bmp_data.Stride * ct - padding)) { x += padding; ct++; };
            r[i] = rgb[x]; g[i] = rgb[x + 1]; b[i] = rgb[x + 2]; i++;
        }
        bmp.UnlockBits(bmp_data);
        return new byte[3][] { r, g, b };
    }
    public static Image AutoCrop(Bitmap bmp)
    {
        //Get an array containing the R,G,B components of each pixel
        var pixels = GetRGB(bmp);

        int h = bmp.Height - 1, w = bmp.Width, top = 0, bottom = h, left = bmp.Width, right = 0, white = 0;
        int tolerance = 95; // 95%

        bool prev_color = false;
        for (int i = 0; i < pixels[0].Length; i++)
        {
            int x = (i % (w)), y = (int)(Math.Floor((decimal)(i / w))), tol = 255 * tolerance / 100;
            if (pixels[0][i] >= tol && pixels[1][i] >= tol && pixels[2][i] >= tol) { white++; right = (x > right && white == 1) ? x : right; }
            else { left = (x < left && white >= 1) ? x : left; right = (x == w - 1 && white == 0) ? w - 1 : right; white = 0; }
            if (white == w) { top = (y - top < 3) ? y : top; bottom = (prev_color && x == w - 1 && y > top + 1) ? y : bottom; }
            left = (x == 0 && white == 0) ? 0 : left; bottom = (y == h && x == w - 1 && white != w && prev_color) ? h + 1 : bottom;
            if (x == w - 1) { prev_color = (white < w) ? true : false; white = 0; }
        }
        right = (right == 0) ? w : right; left = (left == w) ? 0 : left;

        //Crop the image
        if (bottom - top > 0)
        {
            Bitmap bmpCrop = bmp.Clone(new Rectangle(left, top, right - left + 1, bottom - top), bmp.PixelFormat);

            return (Bitmap)(bmpCrop);
        }
        else
        {
            return bmp;
        }
    }


}

干得好,应该有更多的赞。 - Max Favilli
我遇到了一个问题,与传递到.Clone()调用中的无效维度有关,导致出现了"内存不足"异常。你可以在https://dev59.com/yHVC5IYBdhLWcg3wvTxa中找到更多信息。当整个图像应被裁剪时,在“right - left + 1”中的+1似乎是一个错误。最终,我编写了自己的版本该方法更加清晰,并且使用的内存更少,但简洁性则有所牺牲。你可以在链接的重复项中找到它。 - Brian Hasden
效果不是很好。我使用了这个 https://dev59.com/vG445IYBdhLWcg3wg6pm#4821100,它非常棒!!而且速度超快! - Shiroy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接