C# 车牌识别系统实现

基于C#和OpenCV的车牌识别系统实现方案。使用了OpenCVSharp库,它是OpenCV的.NET版本封装。

系统概述

车牌识别系统通常包含以下步骤:

  1. 图像预处理
  2. 车牌定位
  3. 字符分割
  4. 字符识别

代码实现

首先,你需要安装必要的NuGet包:

bash 复制代码
Install-Package OpenCvSharp4
Install-Package OpenCvSharp4.runtime.win
Install-Package OpenCvSharp4.Extensions
csharp 复制代码
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using OpenCvSharp;
using OpenCvSharp.Extensions;

namespace LicensePlateRecognition
{
    public class LicensePlateRecognizer
    {
        // 车牌识别主方法
        public string Recognize(Bitmap image)
        {
            using (var src = image.ToMat())
            {
                // 1. 图像预处理
                var processed = PreprocessImage(src);
                
                // 2. 车牌定位
                var plateRegion = LocateLicensePlate(processed, src);
                
                if (plateRegion == null)
                    return "未检测到车牌";
                
                // 3. 字符分割
                var chars = SegmentCharacters(plateRegion);
                
                // 4. 字符识别
                return RecognizeCharacters(chars);
            }
        }
        
        // 图像预处理
        private Mat PreprocessImage(Mat src)
        {
            // 转换为灰度图
            Mat gray = new Mat();
            Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY);
            
            // 高斯模糊去噪
            Mat blurred = new Mat();
            Cv2.GaussianBlur(gray, blurred, new Size(5, 5), 0);
            
            // 边缘检测
            Mat edges = new Mat();
            Cv2.Canny(blurred, edges, 50, 200);
            
            return edges;
        }
        
        // 车牌定位
        private Mat LocateLicensePlate(Mat processed, Mat src)
        {
            // 查找轮廓
            Point[][] contours;
            HierarchyIndex[] hierarchy;
            Cv2.FindContours(processed, out contours, out hierarchy, 
                            RetrievalModes.List, ContourApproximationModes.ApproxSimple);
            
            // 筛选可能的车牌区域
            var possiblePlates = new List<RotatedRect>();
            foreach (var contour in contours)
            {
                var rect = Cv2.MinAreaRect(contour);
                
                // 根据宽高比和面积筛选
                float aspectRatio = rect.Size.Width / rect.Size.Height;
                float area = rect.Size.Width * rect.Size.Height;
                
                if (aspectRatio > 2.0 && aspectRatio < 5.0 && 
                    area > 2000 && area < 50000)
                {
                    possiblePlates.Add(rect);
                }
            }
            
            if (possiblePlates.Count == 0)
                return null;
                
            // 选择最可能是车牌的矩形
            var plateRect = possiblePlates
                .OrderByDescending(r => r.Size.Width * r.Size.Height)
                .First();
                
            // 提取车牌区域
            return ExtractPlateRegion(src, plateRect);
        }
        
        // 提取车牌区域
        private Mat ExtractPlateRegion(Mat src, RotatedRect rect)
        {
            // 获取旋转矩阵
            var rotationMatrix = Cv2.GetRotationMatrix2D(rect.Center, rect.Angle, 1.0);
            
            // 旋转图像
            Mat rotated = new Mat();
            Cv2.WarpAffine(src, rotated, rotationMatrix, src.Size());
            
            // 裁剪车牌区域
            Rect boundingRect = rect.BoundingRect();
            return new Mat(rotated, boundingRect);
        }
        
        // 字符分割
        private List<Mat> SegmentCharacters(Mat plate)
        {
            // 转换为灰度图
            Mat gray = new Mat();
            Cv2.CvtColor(plate, gray, ColorConversionCodes.BGR2GRAY);
            
            // 二值化
            Mat binary = new Mat();
            Cv2.Threshold(gray, binary, 0, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu);
            
            // 查找字符轮廓
            Point[][] contours;
            HierarchyIndex[] hierarchy;
            Cv2.FindContours(binary, out contours, out hierarchy, 
                            RetrievalModes.External, ContourApproximationModes.ApproxSimple);
            
            // 筛选字符轮廓
            var charRegions = new List<Rect>();
            foreach (var contour in contours)
            {
                var rect = Cv2.BoundingRect(contour);
                float aspectRatio = (float)rect.Width / rect.Height;
                
                if (aspectRatio > 0.2 && aspectRatio < 1.0 && 
                    rect.Width > 10 && rect.Height > 20)
                {
                    charRegions.Add(rect);
                }
            }
            
            // 按X坐标排序(从左到右)
            charRegions = charRegions.OrderBy(r => r.X).ToList();
            
            // 提取字符图像
            var characters = new List<Mat>();
            foreach (var region in charRegions)
            {
                characters.Add(new Mat(binary, region));
            }
            
            return characters;
        }
        
        // 字符识别(简化版)
        private string RecognizeCharacters(List<Mat> characters)
        {
            // 在实际应用中,这里应该使用训练好的机器学习模型
            // 这里使用简单的模板匹配作为示例
            
            string result = "";
            
            // 加载模板字符(实际应用中应该预先准备好)
            var templates = LoadTemplates();
            
            foreach (var character in characters)
            {
                // 调整字符图像大小以匹配模板
                Mat resized = new Mat();
                Cv2.Resize(character, resized, new Size(20, 20));
                
                // 寻找最佳匹配
                string bestMatch = "?";
                double bestScore = double.MaxValue;
                
                foreach (var template in templates)
                {
                    double score = MatchCharacter(resized, template.Value);
                    if (score < bestScore)
                    {
                        bestScore = score;
                        bestMatch = template.Key;
                    }
                }
                
                result += bestMatch;
            }
            
            return result;
        }
        
        // 加载字符模板
        private Dictionary<string, Mat> LoadTemplates()
        {
            var templates = new Dictionary<string, Mat>();
            
            // 这里应该从文件加载模板图像
            // 示例代码中省略了实际加载过程
            
            return templates;
        }
        
        // 字符匹配
        private double MatchCharacter(Mat character, Mat template)
        {
            // 使用模板匹配
            Mat result = new Mat();
            Cv2.MatchTemplate(character, template, result, TemplateMatchModes.CCoeffNormed);
            
            double minVal, maxVal;
            Point minLoc, maxLoc;
            Cv2.MinMaxLoc(result, out minVal, out maxVal, out minLoc, out maxLoc);
            
            return 1 - maxVal; // 返回差异度
        }
    }
    
    // 使用示例
    class Program
    {
        static void Main(string[] args)
        {
            var recognizer = new LicensePlateRecognizer();
            
            // 加载图像
            Bitmap image = new Bitmap("car_plate.jpg");
            
            // 识别车牌
            string plateNumber = recognizer.Recognize(image);
            
            Console.WriteLine($"识别结果: {plateNumber}");
        }
    }
}

改进建议

  1. 使用机器学习改进字符识别

    • 使用CNN(卷积神经网络)训练字符识别模型
    • 可以使用TensorFlow.NET或ML.NET集成预训练模型
  2. 提高车牌定位准确性

    • 结合颜色信息(蓝色/黄色车牌)
    • 使用边缘密度特征
  3. 处理复杂场景

    • 多角度车牌校正
    • 光照条件自适应处理
  4. 性能优化

    • 使用多线程处理视频流
    • GPU加速图像处理

完整解决方案

对于生产环境,建议考虑以下方案:

  1. 使用商业OCR引擎(如百度OCR、腾讯OCR等)的API接口
  2. 集成专业的车牌识别SDK(如OpenALPR)
  3. 使用深度学习框架训练自定义模型
csharp 复制代码
// 使用百度OCR API的示例(需要申请API Key)
public async Task<string> RecognizeWithBaiduOCR(byte[] imageData)
{
    using (var client = new HttpClient())
    {
        var content = new MultipartFormDataContent();
        content.Add(new ByteArrayContent(imageData), "image", "license_plate.jpg");
        
        // 添加其他参数
        content.Add(new StringContent("your_api_key"), "api_key");
        content.Add(new StringContent("your_secret_key"), "secret_key");
        
        var response = await client.PostAsync("https://api.baidu.com/ocr/license_plate", content);
        var result = await response.Content.ReadAsStringAsync();
        
        // 解析JSON结果
        dynamic json = JsonConvert.DeserializeObject(result);
        return json.words_result.number;
    }
}

参考项目 C#车牌识别源代码 www.youwenfan.com/contentcsh/57301.html

注意

  1. 实际应用中需要处理各种光照条件和拍摄角度
  2. 不同国家和地区的车牌格式不同,需要调整识别逻辑
  3. 实时应用需要考虑性能优化和资源管理

这个示例提供了一个基本的车牌识别框架,实际应用中可能需要根据具体需求进行调整和优化。

相关推荐
李建军9 小时前
界止签章宗地号替换工具
c#
qq_425263329 小时前
.net开发框架和语言
c#
武藤一雄9 小时前
C# 关于多线程如何实现需要注意的问题(持续更新)
windows·后端·microsoft·c#·.net·.netcore·死锁
flysh0510 小时前
C# 架构设计:接口 vs 抽象类的深度选型指南
开发语言·c#
flysh0511 小时前
C# 中类型转换与模式匹配核心概念
开发语言·c#
故事不长丨13 小时前
C#字典(Dictionary)全面解析:从基础用法到实战优化
开发语言·c#·wpf·哈希算法·字典·dictionary·键值对
wtsolutions15 小时前
Sheet-to-Doc占位符系统详解:让数据自动填入Word指定位置
开发语言·c#
kylezhao201915 小时前
C#上位机多语言切换实现
c#·工控上位机
我是唐青枫16 小时前
深入理解 System.Lazy<T>:C#.NET 延迟初始化与线程安全
c#·.net
zxy284722530116 小时前
利用C#对接BotSharp本地大模型AI Agent示例(2)
人工智能·c#·api·ai agent·botsharp