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
相关产品推荐
相关产品推荐

