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. 实时应用需要考虑性能优化和资源管理

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

相关推荐
阿登林3 小时前
C#调用钉钉API实现安全企业内部通知推送
安全·c#·钉钉
咕白m6255 小时前
通过 C# 复制 Excel 工作表
c#·.net
Humbunklung6 小时前
C# 获取docx文档页数的古怪方法
开发语言·microsoft·c#
软件黑马王子17 小时前
C#练习题——泛型实现单例模式和增删改查
开发语言·单例模式·c#
wangyue417 小时前
Doxygen with C#
c#
爱吃小胖橘17 小时前
Unity-动画基础
unity·c#·游戏引擎
arbboter18 小时前
【代码】关于C#支持文件和文本框的简单日志实现
数据库·c#·日志·log·日志库
Eiceblue19 小时前
使用 C# 操作 Excel 工作表:添加、删除、复制、移动、重命名
服务器·开发语言·c#·excel
娶不到胡一菲的汪大东19 小时前
C#第五讲 函数的用法
开发语言·c#