裁剪图像中的空白/零空间

时间:2020-06-24 21:08:10

标签: c# winforms crop wia

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

enter image description here

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

在寻找解决方案时,我遇到了类似的问题,并尝试使用this answer中的代码,但似乎无法按预期工作。

该代码有什么问题?还有其他什么方法可以使我想要做的事吗?

这是我尝试过的:

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);
    }
}

1 个答案:

答案 0 :(得分:0)

如果在白色区域(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值,以查看是否为真。