YOLOv5验证码识别:如何从检测结果生成所有可能的候选验证码
YOLOv5验证码重叠检测结果生成全候选序列方案
核心思路是先按字符从左到右的排列顺序,把坐标接近的重叠检测框归为同一字符位置的候选集,再通过笛卡尔积生成所有可能的字符组合,避免硬判x坐标完全相等带来的漏判问题。
具体处理步骤
- 原始结果解析:先解包YOLOv5输出的嵌套检测列表,把每个检测项的坐标、置信度字段转为浮点型,提前过滤置信度低于阈值的无效误检结果。
- 排序与位置分组:先把所有有效检测框按x坐标从小到大排序(对应验证码从左到右的字符顺序);设置同位置判定阈值(推荐取所有检测框平均宽度的40%,避免浮点误差影响),把x坐标差小于阈值的检测框归为同一位置的候选集合。
以给出的检测结果为例,排序后9l(x=0.92)和0l(x=0.93)的x差远小于阈值,会被归为最后一个位置的两个候选,其余三个检测结果各自单独成组,最终得到4个位置组。 - 候选序列生成:对所有位置组的类别集合计算笛卡尔积,每个位置选一个候选按顺序拼接,就能得到所有可能的验证码序列。如果多个位置同时存在多候选,这个逻辑会自动生成全量排列组合,比如两个位置各有2个候选时,会输出4组可能的结果。
可直接运行的实现代码
import itertools # 输入原始检测结果 raw_detections = [[ ['7l', 0.19, '0.443182', '0.104895', '0.431818', '0.972055'], ['4l', 0.33, '0.534091', '0.104895', '0.431818', '0.965045'], ['5l', 0.6, '0.238636', '0.118881', '0.431818', '0.974508'], ['9l', 0.92, '0.659091', '0.104895', '0.409091', '0.879532'], ['0l', 0.93, '0.659091', '0.0979021', '0.363636', '0.651053'] ]][0] # 配置参数 conf_threshold = 0.5 # 低置信度过滤阈值 same_pos_threshold_ratio = 0.4 # 同位置判定阈值占平均字符宽度的比例 # 1. 格式转换+低置信度过滤 valid_dets = [] for det in raw_detections: cls_name = det[0] x_center = float(det[1]) box_width = float(det[3]) confidence = float(det[-1]) if confidence >= conf_threshold: valid_dets.append({ "cls": cls_name, "x": x_center, "w": box_width, "conf": confidence }) # 2. 按x坐标从左到右排序 valid_dets.sort(key=lambda item: item["x"]) # 3. 计算同位置判定阈值 avg_char_width = sum(d["w"] for d in valid_dets) / len(valid_dets) same_pos_thresh = avg_char_width * same_pos_threshold_ratio # 4. 按位置分组 pos_groups = [] for d in valid_dets: if not pos_groups: pos_groups.append([d]) continue # 和最后一组的基准x坐标比较 last_group_base_x = pos_groups[-1][0]["x"] if abs(d["x"] - last_group_base_x) < same_pos_thresh: pos_groups[-1].append(d) else: pos_groups.append([d]) # 每个组内按置信度从高到低排序,提取类别列表 group_cls_list = [] for group in pos_groups: group_sorted = sorted(group, key=lambda x: -x["conf"]) group_cls_list.append([item["cls"] for item in group_sorted]) # 5. 笛卡尔积生成所有候选序列 candidate_sequences = [] for seq in itertools.product(*group_cls_list): candidate_sequences.append(" ".join(seq)) # 输出结果 print(candidate_sequences)
运行上述代码会直接输出目标结果:
['7l 4l 5l 9l', '7l 4l 5l 0l']
优化提示
- 不要用x坐标完全相等作为同位置判定标准,预测框坐标会存在微小浮点偏移,基于相对宽度的阈值判定鲁棒性更强
- 生成候选序列后,可以计算每个序列的总置信度(序列内所有字符置信度的乘积),取总置信度最高的序列作为最终识别结果,能进一步提升识别准确率
- 可以根据自己的测试集效果调整置信度阈值、同位置判定比例,减少无意义的候选序列数量
内容的提问来源于stack exchange,提问作者Jake Jin
相关产品推荐
相关产品推荐

