C#搭建车牌识别系统(附完整源码)
·
车牌识别是计算机视觉在智能交通领域的重要应用。本文将深入解析一个基于ONNX Runtime的高效车牌识别系统,重点介绍其核心技术亮点和实现原理。
展示效果:
识别成功率达到百分之90%以上

系统架构概述
该车牌识别系统采用两阶段检测识别架构:
核心技术亮点
1. 高效的车牌检测
车牌检测采用基于YOLO的轻量级模型,实现实时检测:
private List<CarDetection> DetectPlates(Mat img)
{
var inputName = _detectSession.InputNames[0];
// 图像预处理
var processed = PreprocessImage(img, 640, 640);
var inputTensor = new DenseTensor<float>(processed.Data, processed.Shape);
var inputs = new List<NamedOnnxValue>
{
NamedOnnxValue.CreateFromTensor(inputName, inputTensor)
};
// ONNX Runtime推理
using var results = _detectSession.Run(inputs);
var output = results.First().AsTensor<float>();
return PostProcessDetection(output, processed, img.Width, img.Height);
}
技术亮点:
- Letterbox预处理:保持图像长宽比的同时统一输入尺寸
- 多尺度特征融合:检测不同大小的车牌
- 双层车牌检测:同时识别单层和双层车牌类型
2. 智能的双层车牌处理
双层车牌识别是系统的核心挑战,我们采用分层识别策略:
private string RecognizeDoubleDeckerSeparate(Mat plateMat)
{
int width = plateMat.Width;
int height = plateMat.Height;
// 动态计算最优分割点
int upperHeight = CalculateOptimalUpperHeight(plateMat);
// 分别识别上下部分
Rect upperRect = new Rect(0, 0, width, upperHeight);
using var upperImage = new Mat(plateMat, upperRect);
string upperText = RecognizeSinglePlate(upperImage);
Rect lowerRect = new Rect(0, upperHeight + 2, width, height - upperHeight - 2);
using var lowerImage = new Mat(plateMat, lowerRect);
string lowerText = RecognizeSinglePlate(lowerImage);
// 智能合并识别结果
return MergePlateParts(upperText, lowerText);
}
分割点检测算法:
3. 精准的字符识别
字符识别采用基于CTC的序列识别模型:
private string DecodePlate(Tensor<float> plateOutput)
{
var shape = plateOutput.Dimensions.ToArray();
int timeSteps = shape[1];
int numClasses = shape[2];
var result = new List<char>();
int lastIndex = -1;
for (int t = 0; t < timeSteps; t++)
{
int maxIndex = 0;
float maxVal = float.MinValue;
// 找到每个时间步最可能的字符
for (int c = 0; c < numClasses; c++)
{
float val = plateOutput[0, t, c];
if (val > maxVal)
{
maxVal = val;
maxIndex = c;
}
}
// CTC解码:去除空白符和重复字符
if (maxIndex != 0 && maxIndex != lastIndex)
{
if (maxIndex < PLATE_NAME.Length)
{
result.Add(PLATE_NAME[maxIndex]);
}
}
lastIndex = maxIndex;
}
return new string(result.ToArray());
}
CTC解码流程:
- 获取每个时间步的字符概率分布
- 选择概率最高的字符
- 去除空白符(类别0)
- 合并重复字符
- 生成最终识别结果
4. 先进的图像预处理
private (Mat resized, double ratio, (int, int) pad) Letterbox(Mat img, int newWidth, int newHeight)
{
var shape = img.Size();
// 计算保持长宽比的缩放比例
var r = Math.Min((double)newHeight / shape.Height, (double)newWidth / shape.Width);
// 计算未填充的尺寸
var unpadWidth = (int)(shape.Width * r);
var unpadHeight = (int)(shape.Height * r);
// 添加灰色边框保持输入尺寸一致
Mat result = new Mat();
Cv2.CopyMakeBorder(resized, result, top, bottom, left, right,
BorderTypes.Constant, new Scalar(114, 114, 114));
return (result, r, (left, top));
}
性能优化策略
1. 内存高效管理
public void Dispose()
{
_detectSession?.Dispose();
_recognitionSession?.Dispose();
}
2. 非极大值抑制(NMS)
private List<CarDetection> NonMaxSuppression(List<CarDetection> detections, float iouThreshold)
{
var result = new List<CarDetection>();
var sortedDetections = detections.OrderByDescending(d => d.Confidence).ToList();
while (sortedDetections.Count > 0)
{
var current = sortedDetections[0];
result.Add(current);
sortedDetections.RemoveAt(0);
// 移除与当前检测框重叠度高的框
sortedDetections = sortedDetections.Where(b =>
CalculateIoU(current.Bbox, b.Bbox) < iouThreshold).ToList();
}
return result;
}
实际应用效果
该系统在多种场景下表现出色:
- 光照适应性:能在不同光照条件下稳定工作
- 角度鲁棒性:支持一定角度的车牌识别
- 多类型支持:同时处理单层和双层车牌
- 实时性能:在普通硬件上达到实时识别速度
总结
本文介绍的车牌识别系统通过结合深度学习模型和传统图像处理技术,实现了高效准确的车牌检测与识别。其中的双层车牌处理策略、CTC序列识别和智能后处理算法是系统的核心创新点,为复杂场景下的车牌识别提供了有效的解决方案。
该系统架构灵活,可以方便地替换不同的检测和识别模型,具有良好的可扩展性和实用性,为智能交通系统的发展提供了有力的技术支撑。
java版参考源码:https://gitee.com/agricultureiot/yolo-onnx-java.git
C#源码地址:https://gitee.com/linsmily/caring1.git
更多推荐

所有评论(0)