【问题标题】:ZXing: Finding the bounding rectangle of BarcodeZXing:寻找条形码的边界矩形
【发布时间】:2023-11-18 04:06:01
【问题描述】:

我正在试验 ResultPoints,它返回与图像中的条形码相关的点。
对于 QR 码,ResultPoints 返回一组 4 个点,它们是 QR 码每个角的四个框的坐标。 当我对条形码进行同样的实验时,它返回两个点,表示条形码的宽度。 如何找到条形码的边界矩形? 有什么方法可以使用 ResultPoints 数组计算条形码左上角和右下角的坐标?

经过一番研究,我找到了 WhiteRectangleDetector 类。这正是我感兴趣的东西,但是当我开始使用它时,它给了我部分结果,但不是确切的结果。 我附上了使用 WhiteRectangleDetector 获得的结果的图像,但正如我们所见,它只是为条形码的中间部分着色,而不是条形码的整个矩形部分。所以我想知道是否可以对条码的整个矩形部分进行着色。

我的代码:

        barcodeBitmap = (Bitmap)Bitmap.FromFile("barcode-image.png");
        var luminanceSource = new ZXing.BitmapLuminanceSource(barcodeBitmap);
        var binarizer = new ZXing.Common.HybridBinarizer(luminanceSource);
        var bitMatrix = binarizer.BlackMatrix;

        var whiterect = WhiteRectangleDetector.Create(bitMatrix);

        ResultPoint[] whiterectpts = whiterect.detect();
        if (whiterectpts != null)
        {
            Console.WriteLine("\nWhiteRectangleDetector\n");
            foreach (var w in whiterectpts)
            {
                Console.WriteLine(w);
            }
            Rectangle whiterectangle = new Rectangle((int)whiterectpts[0].X, (int)whiterectpts[0].Y, (int)(whiterectpts[2].X - whiterectpts[1].X), (int)(whiterectpts[1].Y - whiterectpts[0].Y));
            img = Image.FromFile("barcode-image.png");
            g = Graphics.FromImage(img);
            g.DrawRectangle(pen, whiterectangle);
            img.Save("crop2.png");
        }

Image after cropping

【问题讨论】:

  • 嗨 Mancoolgunnda.. 你得到了条码的边界矩形吗?

标签: barcode qr-code zxing bounding-box


【解决方案1】:

对于二维码:在研究了ZXING的源代码后,我找到了一个简单的解决方案。每个二维码的resultsPoints包含以下点,顺序如下:

索引 0:bottomLeft 索引 1:左上 索引 2:右上

因此,例如,您可以使用 resultPoints 作为构造函数参数创建自己的类,以创建在图像中保存二维码坐标的对象。当我们使用 Xamarin 时,以下代码是用 C# 编写的,但 java 代码看起来很相似:

public class QRCodeCoordinates
{
    public float X1 { get; set; }
    public float X2 { get; set; }
    public float Y1 { get; set; }
    public float Y2 { get; set; }

    public QRCodeCoordinates(ZXing.ResultPoint[] resultPoints)
    {
        this.X1 = resultPoints[0].X; // index 0: bottom left
        this.X2 = resultPoints[2].X; // index 2: top right
        this.Y1 = resultPoints[2].Y; // index 2: top right
        this.Y2 = resultPoints[0].Y; // index 0: bottom left            
    }
}

【讨论】:

  • 为什么会浮动?单位是什么?为什么不只是像素?如何获得像素数?为什么我在整个互联网上都找不到这个?
【解决方案2】:

通过 ResultPoints,您可以获得条形码的侧面。通过 WhiteRectangleDetector (WRDet),您可以获得顶部的 y 坐标和条形码的高度。将所有这些信息放在一起将为您提供准确的坐标!

明确分解:

  • left-top:顶部的 y 值来自 WRDet,x 值来自最左边的 ResultPoint
  • right-top:顶部的 y 值来自 WRDet,x 值来自最右边的 ResultPoint
  • left-bottom:顶部的 y 值来自 WRDet + 高度来自 WRDet,x 值来自最左边的 ResultPoint
  • right-bottom:顶部的 y 值来自 WRDet + 高度来自 WRDet,x 值来自最右边的 ResultPoint

调用 ResultPoints 和调用 WRDet 似乎有点矫枉过正,但如果初始搜索中心位于条形码内,则 WRDet 算法非常快。可以使用以下构造函数修改初始搜索中心:

public WhiteRectangleDetector(BitMatrix image, int initSize, int x, int y)

您知道 x 应该位于左右 ResultPoint 之间,对于 y 值,您可以选择其中一个 ResultPoints 的 y 值。


顺便说一句,这里是关于为什么 WhiteRectangleDetector 只捕获水平部分的简短解释。有一个初始矩形沿其四个边扩展,直到其上不再有黑点。顶部和底部是正确的,而在一维条码中,白条会阻止算法进一步搜索。

WhiteRectangleDetector 更适用于 2D 代码(代码的整个高度上没有垂直白条),因为您当然知道将初始搜索中心放在哪里。

【讨论】:

    【解决方案3】:

    我自己正在研究这个问题,也许您可​​以在不同的构造函数中修改以下参数来解决您的问题:WhiteRectangleDetector.java 中以下构造函数中的 initSize 参数扩大了初始搜索区域并可能导致检测到整个一维条码。

    public WhiteRectangleDetector(BitMatrix image, int initSize, int x, int y) 抛出 NotFoundException {...}

    我想问你:WhiteRectangleDetector 是否适用于 1D 和/或 QR 码?你试过 MonochromeRectangleDetector 了吗?

    【讨论】:

    • 似乎 WhiteRectangleDetector 和 MonochromeRectangleDetector (但我找不到后者的任何文档)都是为了检测白色。一维条码中的黑色“条纹”。 (出于好奇,我仍然使用 QR 码对各种图像进行了测试,但他们没有设法检测到它们。)