C# 如何读取低质量的条码?

C# how to read a low quality barcode?

目标:

我的目标是读取质量较差的条形码。如果条形码是最高质量的,代码就可以正常工作。

图片:

代码:

裁剪条码:

    private Point LocationXY;
    private Point LocationX1Y1;

    private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
            LocationXY = e.Location;
    }

    private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            LocationX1Y1 = e.Location;
            pictureBox1.Invalidate();
        }
    }

    private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            LocationX1Y1 = e.Location;

            pictureBox1.Invalidate();
            pictureBox2.Invalidate();
        }
    }

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        Rectangle currentSelection = GetRect();
        if (currentSelection != Rectangle.Empty)
        {
            e.Graphics.DrawRectangle(Pens.Red, currentSelection);
        }
    }

    private void pictureBox2_Paint(object sender, PaintEventArgs e)
    {
        var src = GetRect();

        if (src == Rectangle.Empty) return;

        var des = new Rectangle(0, 0, src.Width, src.Height);

        e.Graphics.DrawImage(pictureBox1.Image,
            des, src, GraphicsUnit.Pixel);
    }

    private Rectangle GetRect()
    {
        return new Rectangle(
            Math.Min(LocationXY.X, LocationX1Y1.X),
            Math.Min(LocationXY.Y, LocationX1Y1.Y),
            Math.Abs(LocationXY.X - LocationX1Y1.X),
            Math.Abs(LocationXY.Y - LocationX1Y1.Y)
            );
    }


    private Bitmap GetCroppedImage()
    {
        var des = GetRect();

        if (des == Rectangle.Empty) return null;

        var b = new Bitmap(des.Width, des.Height);

        using (var g = Graphics.FromImage(b))
        {
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.SmoothingMode = SmoothingMode.HighQuality;
            g.DrawImage(pictureBox1.Image, new Rectangle(0, 0, des.Width, des.Height), des, GraphicsUnit.Pixel);
        }
        return b;


    }

Class图片保存的地方可以return图片:

public class BarcodeImage
{
    private static Image _image;

    public static Image _Image
    {
        get
        {
            return _image;
        }
        set
        {
            _image = value;
        }
    }
}

这里我点击一个按钮将图片保存到class,查看条码:

   private void checkBarcode_Click(object sender, EventArgs e)
    {
        BarcodeImage._Image = GetCroppedImage();

        ZXing.BarcodeReader reader = new ZXing.BarcodeReader();
        var result = reader.Decode((Bitmap)BarcodeImage._Image);
        if (result != null)
        {
            MessageBox.Show(result.ToString());
        }
    }

使用代码:

这里我高亮显示条形码保存到picturebox2.

接下来单击 checkBarcode_Click 它应该显示条形码值 - 但它没有。由于图像质量。

我已经用高质量的条形码图像对其进行了测试,效果很好!

问题:

如何提高裁剪图像的质量和 return 我的条码值?

编辑:2020 年 5 月 29 日

我在这个社区问了一个新问题,看看我是否可以增加裁剪图像的大小。但这并没有改善任何东西:

高质量条码:

图片是从特定程序中取出来的

我打印屏幕图像,它们必须是这样的:

但是没有检测到条码。

这是在程序中使用 2x 放大后的图像:

不幸的是,我无法使用 x2 放大选项,因为一些数据会在图像上移动,无法提供准确的最终图像。最重要的是,条形码被识别了!

您发现此处的子像素数据丢失过多,无法使用任何软件读取此条形码。

条形码使用条形的相对宽度来工作 - 它们在如何做到这一点方面非常聪明,并且存在一定的公差空间,但只有很小的空间。

这是您的原始条形码、放大版本和可读版本:

如果您查看最右边的条形码与可读条形码,您会发现它们的大小不相等 - 它们应该是,但它们不是。

仅当原始图像的分辨率足以正确捕获所有条形图的相对大小时,原始图像才足够。

您需要从任何来源获取更好的数据。

编辑:

根据您的评论,您说您正在使用调酒师标签的 print-screen - 没有理由不能缩放以获得更高分辨率 print-screen,但是如果你不能那么你可以将标签打印成 file/image(例如 PDF)并使用它。

还值得注意的是,BarTender 有一个 .NET API,如果需要,您可以直接与之对话,并且 BarTender 的数据可以导出为 Excel/CSV 格式(假设您正在将其用作条形码输出的驱动程序)。

您还提到您想要检查条形码是否已存在于您的数据库中 - 您也许可以使用 API 来执行此操作。

我真的不能告诉你更多,因为我不知道你从什么数据生成标签,或者标签是否全部 ad-hoc;但我知道,如果您将图像放大到足以让足够的像素使各个条形码条能够相对于它们的全宽正确呈现,那么您想要实现的目标是完全可能的 - 这很重要!

所以...如果您要获得 x2 缩放图像,将其水平除以 2,然后裁剪条码,zxing 将为您提供信息!因此,您只需要 - 裁剪时没有任何扭曲。 所以,你需要完成你的任务 - 只需找到条形码的边界(我认为如果你一直使用相同的格式,它可能是硬编码的)。如果没有 - 很容易扫描图像并通过右下角的黑色像素找到它。

代码的文本版本:

static void Main(string[] args)
    {
        var barcodeFull = Bitmap.FromFile("barcode-x2-zoomed-dividedx2.jpg");
        var cropFromPoint = new Point(64, 578);
        var cropSize = new Size(360, 142);

        var barcode = CropAtRect((Bitmap)barcodeFull, new Rectangle(cropFromPoint, cropSize));
        ZXing.BarcodeReader reader = new ZXing.BarcodeReader();
        var result = reader.Decode(barcode);
        if (result != null)
        {
            Console.WriteLine("result : "+result.Text);
        }

        Console.ReadLine();
    }

    public static Bitmap CropAtRect(Bitmap b, Rectangle r)
    {
        Bitmap nb = new Bitmap(r.Width, r.Height);
        using (Graphics g = Graphics.FromImage(nb))
        {
            g.DrawImage(b, -r.X, -r.Y);
            return nb;
        }
    }