目录[-]

一、背景

公司采购了一批车牌识别摄像头,准备部署在多个停车场。但实际测试中发现,部分设备在夜间、绿牌、倾斜角度等场景下识别率很低,导致车辆无法自动开闸。

更棘手的是:

  • 市面上有几十种设备,供应商都说自己好

  • 不可能把每种都买回来试一遍(成本太高)

  • 就算现场测试,也只能测几个场景,覆盖不全

结果:设备买了,不好用,钱白花了,业务还受影响。

我的任务是:建立一套可量化的车牌识别设备评估体系,让每次采购都有数据支撑,不再靠供应商“说得好”做决定。


二、整体架构

测试图片生成器(PIL) → 测试集(500+张) → 调用设备API → 多维度评估 → HTML报告
                         ↓
              合成图片 + 真实场景图片
模块 技术栈 职责
图片生成 PIL(Pillow) 批量生成合成车牌(不同颜色、省份、格式)
测试管理 Excel + pandas 管理图片路径、正确答案、关键词
API调用 requests 调用设备/平台的车牌识别接口
评估器 Python + 正则 关键词位置得分、BLEU、相似度等
报告生成 HTML + CSS 可视化测试报告,附带图片缩略图

三、核心设计

1. 测试图片生成(合成数据)

用PIL生成合成车牌图片,覆盖多维度:

def generate_plate_number(plate_type):
    """生成符合真实规则的车牌号"""
    province = random.choice(provinces)
    city_code = random.choice(city_letters)

    if plate_type == "green":  # 新能源绿牌
        energy_type = random.choice(['D', 'F'])
        middle_part = ''.join(random.choice(allowed_chars) for _ in range(4))
        last_char = random.choice(digits)
        rest = energy_type + middle_part + last_char
    else:  # 蓝牌
        num_digits = random.choice([3, 4])
        num_letters = 5 - num_digits
        digits_part = ''.join(random.choice(digits) for _ in range(num_digits))
        letters_part = ''.join(random.choice(letters) for _ in range(num_letters))
        rest = ''.join(random.sample(list(digits_part + letters_part), 5))

    return province + city_code + rest

生成的图片覆盖维度:

维度 覆盖场景 示例
省份 京、沪、粤、苏、浙、鲁、冀、辽、川、渝 冀J66618
颜色 蓝牌、绿牌、黄牌、白牌 blue/ green/ yellow/ white
字体 黑体,80px
格式 带点(辽A·12345) 符合真实车牌样式

此外,还采集了真实场景图片:夜间、地库、逆光、倾斜、脏污等,确保测试集覆盖真实环境。

2. API适配器

class PlateClient(BaseTranslator):
    def translate(self, image_path: str) -> str:
        with open(image_path, 'rb') as f:
            files = {'file': (image_path.name, f, 'image/jpeg')}
            response = requests.post(self.extract_url, files=files, headers=self.headers)
            result = response.json()
            # 解析返回的text字段,取第一个识别结果
            return result['content']['text'][0]

3. 评估器强化:关键词位置得分

车牌识别和普通文字识别不同——前两个字符(省份+字母)的权重极高。识别错了省份,后面全对也没用。

def keyword_position_score(text, keywords):
    """带位置的关键词评分,专门用于车牌识别"""
    if not text or not keywords:
        return 0
    if len(text) != len(keywords):
        return 0
    # 逐个字符比对,必须全部正确
    for i, k in enumerate(keywords):
        if i >= len(text) or text[i] != k:
            return 0.0
    return 1.0

权重分配:

指标 权重 说明
关键词位置得分 0.5 前两位字符权重极高
BLEU分数 0.3 整体字符匹配度
相似度 0.1 辅助判断
长度比率 0.05 防止漏字
重复惩罚 0.05 检测重复

核心逻辑:如果省份或城市代码识别错误,综合得分直接打1折。

4. HTML报告增强

报告附带图片缩略图,点击可放大,便于人工复核:

<img src="file:///{image_path}" 
     style="width: 80px; cursor: pointer;" 
     onclick="this.style.width=this.style.width=='80px'?'400px':'160px'">

四、测试结果

总体统计

指标 数值
总测试图片 19张
通过数 7张
失败数 12张
通过率 36.8%
综合得分 0.38

通过案例(部分)

图片 原始车牌 识别结果 得分
blue_冀J66618.jpg 冀J66618 冀J·66618 1.00
green_京UREKHY.jpg 京UREKHY 京U·REKHY 1.00
green_浙DHMBW2.jpg 浙DHMBW2 浙D·HMBW2 1.00

通过的都是标准角度、清晰度好的图片。

失败案例分析

图片 原始车牌 识别结果 问题类型
T-blue_皖A37X93.jpg 皖A37X93 峯A·37X93 省份识别错误
T-blue_皖A3E388.jpg 皖A3E388 225204 完全识别失败
T-blue_皖AAV951.jpg 皖AAV951 版1 5 百 3... 乱码
T-blue_皖ABG382.jpg 皖ABG382 中国工商银行 识别成无关文字
T-green_辽AD75582.jpg 辽AD75582 1A.D75592 省份+字母全错
T-green_辽AF46066.jpg 辽AF46066 长安深蓝... 识别成车辆型号

问题集中在:

  • 倾斜角度图片(文件名带T-前缀)

  • 绿牌识别率低

  • 复杂背景干扰

  • 省份和城市代码识别不准


五、采购验收流程

这套体系建立后,采购流程变为:

  1. 建立基准:用本地代码或已知好模型跑一遍测试集,得出基准准确率(约98%)

  2. 设备送测:供应商提供设备,用同一套测试集评估

  3. 数据对比:输出准确率报告,与基准对比

  4. 决策依据:准确率低于95%直接淘汰,低于98%要求供应商优化

实际效果:用这套体系评估了5家供应商,淘汰了2家(准确率分别只有82%和89%),避免了至少几十万的无效采购。


六、踩坑记录

坑1:车牌生成规则不真实

一开始随机生成字符,但真实车牌有规则(蓝牌5位,绿牌6位,新能源有D/F标识)。

解决:研究真实车牌规则,实现符合规范的生成逻辑。

坑2:识别结果带点,和正确答案不匹配

API返回冀J·66618,正确答案是冀J66618,直接比对失败。

解决:评估前去点(translation.replace('·', '')),再用关键词位置得分逐字比对。

坑3:前两位字符错,后面全对,综合得分还很高

用普通关键词匹配,1A.D75592辽AD75582相似度很高,但实际完全错误。

解决:增加keyword_position_score,强制前两位必须完全正确。

坑4:图片文件路径在HTML报告中无法显示

报告中用相对路径或绝对路径,浏览器可能禁止访问本地文件。

解决:用file:///协议,添加点击放大功能,便于人工复核。


七、总结

这套框架的核心价值不在于“测准了”,而在于:

  • 帮公司做决策:用数据说话,淘汰不合格供应商

  • 建立可复用标准:后续人脸识别、车辆识别项目都参考了这个方案

  • 量化评估:从“感觉不太行”变成“通过率36.8%,综合得分0.38”

  • 框架复用:评估体系直接复用了翻译/音生文的5维指标

你不是在“做测试”,你是在“帮公司省钱”。

测试报告