You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中ZXing.Net识别同内容多实例二维码的存储与追踪问题

问题解答

ZXing.Net对同内容多实例二维码的支持

ZXing.Net的DecodeMultiple方法完全可以识别同一帧中内容相同但位置不同的二维码,每个二维码实例会被返回为独立的Result对象。每个Result包含唯一的位置信息(Points属性,记录二维码四个角的坐标),这是区分同内容不同实例的核心依据。

现有代码的问题

你当前用result.Text作为字典detectedQRCodes的Key,这会导致内容相同的二维码被覆盖——因为Key重复时,新的实例会替换旧的,无法区分不同位置的同内容二维码。

解决方案:基于位置区分并追踪实例

1. 调整存储结构

放弃用Dictionary<string, CodeInfo>(以内容为Key),改用以下两种方式之一:

  • List:直接存储所有二维码实例,适合需要保留全部实例的场景。
  • Dictionary<Guid, CodeInfo>:给每个二维码实例分配唯一Guid作为Key,方便快速查找;或Dictionary<string, List<CodeInfo>>:按内容分组,每组下存储多个位置不同的实例。

同时,给CodeInfo类新增唯一标识字段,以及用于追踪的位置特征:

public class CodeInfo
{
    public Guid InstanceId { get; set; } // 唯一实例ID
    public string Content { get; set; }
    public BarcodeFormat Format { get; set; }
    public float RotationAngle { get; set; }
    public PointF MidPoint { get; set; }
    public PointF[] Points { get; set; }
}

2. 识别与追踪逻辑

处理每一帧的Result时,通过位置匹配判断当前二维码是新实例还是已存在的实例(基于前后帧中点的距离阈值):

// 假设detectedQRCodes改为List<CodeInfo>
float distanceThreshold = 20; // 可根据实际场景调整,单位:像素

foreach (var result in results)
{
    // 计算当前二维码的中点
    PointF midPoint = new PointF(
        (result.Points[0].X + result.Points[2].X) / 2,
        (result.Points[0].Y + result.Points[2].Y) / 2
    );
    float rotationAngle = // 你的角度计算逻辑
    PointF[] points = result.Points.Select(p => new PointF(p.X, p.Y)).ToArray();

    // 查找是否存在已追踪的同位置实例
    var existingCode = detectedQRCodes.FirstOrDefault(c => 
        Math.Sqrt(Math.Pow(c.MidPoint.X - midPoint.X, 2) + Math.Pow(c.MidPoint.Y - midPoint.Y, 2)) < distanceThreshold
        && c.Content == result.Text // 确保内容相同,避免误匹配不同内容的二维码
    );

    if (existingCode != null)
    {
        // 更新已有实例的位置和角度
        existingCode.RotationAngle = rotationAngle;
        existingCode.MidPoint = midPoint;
        existingCode.Points = points;

        // 更新DataGridView对应行
        DataRow existingRow = qrCodeDataTable.Rows.Find(existingCode.InstanceId);
        if (existingRow != null)
        {
            existingRow["RotationAngle"] = rotationAngle;
            existingRow["MidPoint"] = $"{midPoint.X:F2}, {midPoint.Y:F2}";
        }
    }
    else
    {
        // 创建新实例
        CodeInfo newCode = new CodeInfo
        {
            InstanceId = Guid.NewGuid(),
            Content = result.Text,
            Format = result.BarcodeFormat,
            RotationAngle = rotationAngle,
            MidPoint = midPoint,
            Points = points
        };
        detectedQRCodes.Add(newCode);

        // 添加到DataGridView
        qrCodeDataTable.Rows.Add(
            newCode.InstanceId,
            newCode.Content,
            newCode.Format.ToString(),
            newCode.RotationAngle,
            $"{midPoint.X:F2}, {midPoint.Y:F2}"
        );
    }
}

3. 调整DataGridView配置

需要给DataTable新增InstanceId列(作为主键),确保每个实例对应独立行:

// 初始化DataTable时添加列
qrCodeDataTable.Columns.Add("InstanceId", typeof(Guid));
qrCodeDataTable.Columns.Add("Content", typeof(string));
qrCodeDataTable.Columns.Add("Format", typeof(string));
qrCodeDataTable.Columns.Add("RotationAngle", typeof(float));
qrCodeDataTable.Columns.Add("MidPoint", typeof(string));
qrCodeDataTable.PrimaryKey = new DataColumn[] { qrCodeDataTable.Columns["InstanceId"] };

关键说明

  • 距离阈值distanceThreshold需要根据你的摄像头分辨率、二维码大小调整,确保能区分不同实例,同时允许同一实例因轻微移动产生的位置变化。
  • Result.Points返回的是二维码四个角的原始坐标,可用于计算中点、边界框等位置特征,是区分同内容实例的核心数据。

内容的提问来源于stack exchange,提问作者Ugur Alp Balta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 08:33:58