首页 > 解决方案 > 从图像中裁剪空白/空空格

问题描述

您好,我有一个扫描仪应用程序,我将扫描的图像返回到位图,然后显示到图片框中。我有一个要求,包括自动裁剪图像并删除空白/空空格。例如,这是我在图片框上向用户展示的图像。

在此处输入图像描述

如您所见,扫描的图像是一张小卡片,图像是带有很多空格的全字母纸,我期望的是自动裁剪图像或使用按钮仅向用户显示红色边框部分

在寻找解决方案时,我看到了一个类似的问题,并尝试使用此答案中的代码,但似乎没有按预期工作。

该代码有什么问题?有没有其他方法可以让我做我想做的事?

这是我尝试过的:

public Bitmap CropImage(Bitmap bitmap)
{
    int w = bitmap.Width;
    int h = bitmap.Height;

    Func<int, bool> IsAllWhiteRow = row =>
    {
        for (int i = 0; i < w; i++)
        {
            if (bitmap.GetPixel(i, row).R != 255)
            {
                return false;
            }
        }
        return true;
    };

    Func<int, bool> IsAllWhiteColumn = col =>
    {
        for (int i = 0; i < h; i++)
        {
            if (bitmap.GetPixel(col, i).R != 255)
            {
                return false;
            }
        }
        return true;
    };

    int leftMost = 0;
    for (int col = 0; col < w; col++)
    {
        if (IsAllWhiteColumn(col)) leftMost = col + 1;
        else break;
    }

    int rightMost = w - 1;
    for (int col = rightMost; col > 0; col--)
    {
        if (IsAllWhiteColumn(col)) rightMost = col - 1;
        else break;
    }

    int topMost = 0;
    for (int row = 0; row < h; row++)
    {
        if (IsAllWhiteRow(row)) topMost = row + 1;
        else break;
    }

    int bottomMost = h - 1;
    for (int row = bottomMost; row > 0; row--)
    {
        if (IsAllWhiteRow(row)) bottomMost = row - 1;
        else break;
    }

    if (rightMost == 0 && bottomMost == 0 && leftMost == w && topMost == h)
    {
        return bitmap;
    }

    int croppedWidth = rightMost - leftMost + 1;
    int croppedHeight = bottomMost - topMost + 1;

    try
    {
        Bitmap target = new Bitmap(croppedWidth, croppedHeight);
        using (Graphics g = Graphics.FromImage(target))
        {
            g.DrawImage(bitmap,
                    new RectangleF(0, 0, croppedWidth, croppedHeight),
                    new RectangleF(leftMost, topMost, croppedWidth, croppedHeight),
                    GraphicsUnit.Pixel);
        }
        return target;
    }
    catch (Exception ex)
    {
        throw new Exception(string.Format("Values are top={0} bottom={1} left={2} right={3}", topMost, bottomMost, leftMost, rightMost), ex);
    }
}

标签: c#winformscropwia

解决方案


如果您的图像在 R=G=B=255 的白色区域中不是真正的“纯白色”,我建议将 IsAllWhiteRow 的函数修改为更像:

int thresholdValue = 250;
double percentAllowedBelowThreshold = 0.95;

Func<int, bool> IsAllWhiteRow = row =>
{
    int numberPixelsBelowThreshold = 0;
    for (int i = 0; i < w; i++)
    {
        if (bitmap.GetPixel(i, row).R < thresholdValue)
        {
            numberPixelsBelowThreshold++;
        }
    }
    return (numberPixelsBelowThreshold / w) > percentAllowedBelowThreshold;
};

然后对列做类似的事情。您可能需要更改阈值,具体取决于您的图像输入。例如,如果图像的真实部分中有很多白色,则可能需要 0.98 或更高的阈值!加上这段代码没有优化,等等。

您还需要逐步浏览您的图像,看看我为 250 选择的值是否合理;我还没有查看位图“白色”区域中的实际 RGB 值,以查看它是否存在。


推荐阅读