如何基于印度车牌规则与OCR检测框坐标对识别字符进行正确排序
印度车牌OCR识别乱序问题解决方案
一、检测框参数提取与坐标排序
1. 四点坐标转(x,y,w,h)参数
keras-ocr返回的每个文本块对应4个顶点的多边形坐标,按如下方式计算外接矩形参数:
import numpy as np def get_box_xywh(box): # box为keras-ocr返回的4*2坐标数组 x_coords = box[:, 0] y_coords = box[:, 1] x = np.min(x_coords) y = np.min(y_coords) w = np.max(x_coords) - x h = np.max(y_coords) - y # 额外返回y轴中心坐标用于分行判断 y_center = np.mean(y_coords) return (x, y, w, h, y_center)
2. 基于坐标的排序逻辑
印度车牌多为1行或2行布局,按以下规则排序即可得到基础的正确顺序:
- 先按文本块的y_center值分组:两个文本块y_center差值小于任意一个块高度h的1/2时,判定为同一行
- 行与行之间按y_center从小到大排序(从上到下读取)
- 同一行内的文本块按x坐标从小到大排序(从左到右读取)
排序代码示例:
def sort_by_coordinate(ocr_results): # ocr_results为keras-ocr返回的原生列表,元素格式为(识别文本, 框坐标) processed = [] for text, box in ocr_results: x, y, w, h, y_center = get_box_xywh(box) processed.append((text, x, y, w, h, y_center)) # 先按y轴中心预排序再分行 processed_sorted_by_y = sorted(processed, key=lambda x: x[-1]) lines = [] current_line = [processed_sorted_by_y[0]] for item in processed_sorted_by_y[1:]: last_item = current_line[-1] if abs(item[-1] - last_item[-1]) < min(item[3], last_item[3]) * 0.5: current_line.append(item) else: lines.append(current_line) current_line = [item] lines.append(current_line) # 每行内按x坐标排序后拼接结果 sorted_text = [] for line in lines: line_sorted = sorted(line, key=lambda x: x[1]) sorted_text.extend([item[0] for item in line_sorted]) return ' '.join(sorted_text).upper()
二、结合印度车牌规则的结果优化
你适配的德里(DL)、哈里亚纳邦(HR)、北方邦(UP)车牌遵循印度标准格式:[两位邦代码] [1~2位地区代码] [1~2位字母序列] [4位数字],按以下步骤做二次校验修正,可解决坐标排序的残留误差:
- 预处理:将所有识别结果转大写,提前替换易混淆字符(如数字
0转字母O、数字1转字母I等,可根据自身识别准确率调整规则),同时将地区代码字典统一为字符串格式,避免匹配失败 - 匹配邦代码:从排序后的字符串中提取所有连续两位的字母,匹配目标邦列表
['DL','HR','UP'],确定邦代码位置 - 匹配地区代码:取邦代码后紧邻的1~2位数字,匹配对应邦的地区代码列表
- 格式重排:将识别出的内容按
邦代码-地区代码-字母序列-4位数字的固定顺序重排,修正坐标排序的误差
优化代码示例:
# 预处理地区代码字典,统一为2位字符串格式 district_codes['HR'] = [str(i).zfill(2) for i in district_codes['HR']] district_codes['DL'] = [i.zfill(2) for i in district_codes['DL']] # UP的地区代码可按同样逻辑补充 target_states = {'DL','HR','UP'} def optimize_by_plate_rule(raw_text): # 去掉空格方便匹配 text_no_space = raw_text.replace(' ', '') # 匹配邦代码 state_code = None state_pos = -1 for i in range(len(text_no_space)-1): candidate = text_no_space[i:i+2] if candidate in target_states: state_code = candidate state_pos = i break if not state_code: # 未匹配到目标邦代码时返回坐标排序的原始结果 return raw_text # 匹配地区代码 district_code = None remaining = text_no_space[state_pos+2:] # 优先匹配2位地区代码,再匹配1位 for l in [2,1]: if len(remaining) >= l: cand_dist = remaining[:l] if cand_dist in district_codes.get(state_code, []): district_code = cand_dist break # 拆分剩余的字母序列和4位数字 rest = remaining[len(district_code):] if district_code else remaining digit_part = ''.join([c for c in rest if c.isdigit()])[-4:] alpha_part = ''.join([c for c in rest if c.isalpha()])[:2] # 拼接为标准格式 return f"{state_code} {district_code} {alpha_part} {digit_part}"
补充优化建议
- 针对OCR识别的字符混淆问题,可在邦代码、地区代码匹配环节增加容错规则,比如单字符差异的模糊匹配
- 如果车牌存在形变、倾斜的情况,可先对检测框做透视校正后再排序,准确率会更高
内容的提问来源于stack exchange,提问作者dev1ce
相关产品推荐
相关产品推荐

