资讯动态

基于YOLO与ONNX Runtime的Java车牌识别系统实战

发布时间:2026/8/8 6:43:29 来源:尧图企业网站定制
1. 为什么选择YOLOONNX Runtime做车牌识别车牌识别是计算机视觉的经典应用场景传统方案依赖手工特征提取和模板匹配但遇到角度倾斜、光照变化时效果直线下降。我在实际项目中测试过多种方案最终发现YOLOv5ONNX Runtime的组合最能兼顾精度和效率。YOLO的检测速度有天然优势实测在RTX 3060显卡上能跑到150FPS。而ONNX Runtime作为跨平台推理引擎比直接加载PyTorch模型体积小40%在Java环境下内存占用减少35%。更关键的是这个方案可以轻松部署到树莓派等边缘设备。2. 环境搭建与依赖配置2.1 开发环境准备推荐使用JDK 17和Maven 3.8的组合我在Windows和Linux平台都验证过。pom.xml关键依赖如下dependencies !-- ONNX Runtime -- dependency groupIdcom.microsoft.onnxruntime/groupId artifactIdonnxruntime/artifactId version1.16.1/version /dependency !-- OpenCV -- dependency groupIdorg.openpnp/groupId artifactIdopencv/artifactId version4.7.0-0/version /dependency !-- Spring Boot -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId version3.2.4/version /dependency /dependencies踩坑提醒OpenCV的Java版有多个实现实测openpnp的封装最稳定。如果遇到动态库加载失败可以尝试显式指定库路径static { nu.pattern.OpenCV.loadShared(); System.loadLibrary(Core.NATIVE_LIBRARY_NAME); }2.2 模型准备与转换需要准备两个ONNX模型车牌检测模型推荐YOLOv5s改造版车牌识别模型CRNNCTC结构我用Python转换的示例代码import torch model torch.load(yolov5s_plate.pt) model.eval() dummy_input torch.randn(1, 3, 640, 640) torch.onnx.export(model, dummy_input, plate_detect.onnx, input_names[images], output_names[output], dynamic_axes{images: {0: batch}, output: {0: batch}})转换时务必注意添加dynamic_axes支持多batch推理验证输出节点名称与Java代码匹配用onnxruntime-tools检查模型有效性3. 核心实现逻辑剖析3.1 图像预处理流水线车牌识别效果80%取决于预处理质量。我的标准处理流程颜色空间转换BGR→RGBOpenCV默认读取为BGR格式Imgproc.cvtColor(src, dst, Imgproc.COLOR_BGR2RGB);尺寸归一化采用letterbox保持宽高比Letterbox letterbox new Letterbox(640, 640); Mat processed letterbox.letterbox(src);数值归一化像素值缩放到0-1范围processed.convertTo(processed, CvType.CV_32FC3, 1.0/255);通道顺序调整HWC→CHW格式转换float[] chw new float[3*640*640]; for(int c0; c3; c){ for(int h0; h640; h){ System.arraycopy(rgbData, h*640*3c, chw, c*640*640h*640, 640); } }3.2 双模型协同工作流程检测阶段// 创建输入tensor OnnxTensor tensor OnnxTensor.createTensor(env, FloatBuffer.wrap(chw), shape); // 执行推理 try(OrtSession.Result results session.run(Collections.singletonMap(images, tensor))) { float[][] outputs ((float[][][])results.get(0).getValue())[0]; }NMS后处理Listfloat[] filtered bboxes.stream() .filter(b - b[4] confThreshold) .sorted(Comparator.comparing(b - -b[4])) .collect(Collectors.toList());识别阶段// 裁剪车牌区域 Mat plateROI new Mat(src, new Rect(x1,y1,x2-x1,y2-y1)); // 执行字符识别 OrtSession.Result recResult recSession.run(recInputs); int[] charIndexes argmax((float[][][])recResult.get(0).getValue());3.3 结果可视化技巧在原始图像上标注结果时我推荐使用自适应绘制策略// 根据图像尺寸动态计算线宽和字体大小 int baseSize Math.min(img.width(), img.height()); int thickness baseSize / 300; int fontSize baseSize / 40; // 绘制识别结果 Imgproc.putText(img, plateText, new Point(rect.x, rect.y-5), Imgproc.FONT_HERSHEY_SIMPLEX, fontSize, new Scalar(0,255,0), thickness);4. Spring Boot服务化实战4.1 高效文件上传处理PostMapping(/upload) public ListPlateResult handleUpload(RequestParam MultipartFile file) { // 临时文件转换 Mat img Imgcodecs.imdecode( new MatOfByte(file.getBytes()), Imgcodecs.IMREAD_COLOR); // 执行识别流程 return plateService.detect(img); }性能优化点使用内存映射避免磁盘IO预加载模型到内存采用线程池处理并发请求4.2 接口响应设计推荐结构化的返回格式public class PlateResult { private String plateNumber; private String plateColor; private float confidence; private Rect position; private long processTime; }4.3 性能监控方案通过Spring Actuator添加指标Bean MeterRegistryCustomizerMeterRegistry metrics() { return registry - { registry.gauge(plate.detect.time, Tags.of(model,yolov5), detectTimer); }; }我在压力测试中发现的主要瓶颈图像解码耗时占比30%ONNX初始会话创建耗时2-3秒大尺寸图像resize消耗CPU对应的优化手段启用OpenCV的IPP加速实现会话池化管理添加图片尺寸限制5. 常见问题解决方案5.1 车牌颜色识别不准根本原因是颜色分类模型训练数据不均衡。我的改进方案在HSV空间进行颜色增强添加难例样本反光、污损车牌改用HSV直方图特征辅助判断5.2 小尺寸车牌漏检通过修改YOLO锚点参数提升小目标检测能力# yolov5s.yaml anchors: - [5,6, 8,14, 15,11] # P3/8 - [10,13, 16,30, 33,23] # P4/16 - [30,61, 62,45, 59,119] # P5/325.3 复杂背景干扰采用两阶段检测策略先用YOLO检测车辆在车辆ROI内做二次车牌检测实测准确率提升27%但推理时间增加15ms。可以根据场景需求灵活选择方案。6. 效果优化与部署建议6.1 模型量化加速将FP32模型转为INT8格式python -m onnxruntime.tools.quantize \ --input plate_detect.onnx \ --output plate_detect_int8.onnx \ --quantize_type QInt8实测效果精度类型推理速度(ms)内存占用(MB)FP3245320INT8281906.2 多线程流水线设计ExecutorService pool Executors.newFixedThreadPool(3); CompletableFutureMat decodeFuture CompletableFuture.supplyAsync(() - { return Imgcodecs.imdecode(buf, IMREAD_COLOR); }, pool); CompletableFutureDetectionResult detectFuture decodeFuture.thenApplyAsync(img - { return detector.detect(img); }, pool);6.3 边缘设备部署树莓派4B上的优化技巧使用ARM64版本的ONNX Runtime启用OpenVINO后端限制识别区域减少计算量降低检测模型输入分辨率到480x480实测在树莓派上能达到800ms的单帧处理速度满足大部分实时场景需求。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价