关注

基于OpenCV的车牌识别系统实现与解析

## 一、项目背景与应用场景

车牌识别技术(Vehicle License Plate Recognition, VLPR)是智能交通系统中的关键技术之一,广泛应用于停车场管理、交通违章监控、高速公路收费等领域。本文将介绍如何使用OpenCV和Python实现一个基础的车牌识别系统,帮助读者理解计算机视觉在字符识别中的应用。

## 二、技术栈与环境配置

- **编程语言**: Python 3.x

- **核心库**: OpenCV (cv2)、NumPy、Matplotlib

- **开发环境**: Jupyter Notebook

安装依赖库的命令:

pip install opencv-python numpy matplotlib

## 三、系统架构与实现流程

车牌识别系统主要包含以下几个核心步骤:

1. **车牌定位**: 从输入图像中检测并提取车牌区域

2. **图像预处理**: 对车牌图像进行去噪、灰度化和二值化处理

3. **字符分割**: 将车牌中的单个字符分离出来

4. **字符识别**: 与预定义的模板进行匹配,识别出每个字符

下面我们将逐步解析每个模块的实现代码。

## 四、核心代码实现

### 1. 导入必要的库

# ==========================导入库==============================

import cv2

from matplotlib import pyplot as plt

import numpy as np

import glob

### 2. 车牌提取模块

此模块负责从原始图像中定位并提取车牌区域,通过一系列图像处理操作增强车牌特征并检测轮廓。

# ==========================提取车牌函数==============================

def getPlate(image):

    rawImage = image.copy()

    # 去噪处理

    image = cv2.GaussianBlur(image, (3, 3), 0)

    # 色彩空间转换(RGB-->GRAY)

    image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # Sobel算子(X方向边缘梯度)增强垂直边缘

    Sobel_x = cv2.Sobel(image, cv2.CV_16S, 1, 0)

    absX = cv2.convertScaleAbs(Sobel_x)  # 映射到[0,255]范围内

    image = absX

    # 阈值处理(自适应阈值)

    ret, image = cv2.threshold(image, 0, 255, cv2.THRESH_OTSU)

    # 闭运算:先膨胀后腐蚀,将车牌连成一个整体

    kernelX = cv2.getStructuringElement(cv2.MORPH_RECT, (17, 5))

    image = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernelX)

    # 开运算:先腐蚀后膨胀,去除噪声

    kernelY = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 19))

    image = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernelY)

    # 中值滤波:进一步去除噪声

    image = cv2.medianBlur(image, 15)

    # 查找轮廓

    contours, w1 = cv2.findContours(image, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

   

    # 遍历所有轮廓,筛选出宽高比符合车牌特征的区域(宽度>3倍高度)

    for item in contours:

        rect = cv2.boundingRect(item)

        x = rect[0]

        y = rect[1]

        weight = rect[2]

        height = rect[3]

        if weight > (height * 3):

            plate = rawImage[y:y + height, x:x + weight]

    return plate

### 3. 图像预处理模块

预处理模块对提取出的车牌图像进行去噪、灰度化和二值化处理,为后续的字符分割做准备。

#======================预处理函数,图像去噪等处理=================

def preprocessor(image):

    # 图像去噪灰度处理

    image = cv2.GaussianBlur(image, (3, 3), 0)

    # 色彩空间转换

    gray_image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)

    # 阈值处理(二值化)

    ret, image = cv2.threshold(gray_image, 0, 255, cv2.THRESH_OTSU)

    # 膨胀处理,让单个字符连接成一个整体

    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2))

    image = cv2.dilate(image, kernel)

    return image

### 4. 字符分割模块

字符分割模块负责将车牌中的单个字符分离出来,以便进行后续的字符识别。

#===========拆分车牌函数,将车牌内各个字符分离==================

def splitPlate(image):

    # 查找轮廓,各个字符的轮廓

    contours, hierarchy = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    words = []

    # 遍历所有轮廓,获取轮廓的外接矩形

    for item in contours:

        rect = cv2.boundingRect(item)

        words.append(rect)

   

    # 按照x轴坐标值排序(自左向右排序)

    words = sorted(words, key=lambda s: s[0], reverse=False)

   

    # 存储分割后的字符图像

    plateChars = []

    for word in words:

        # 筛选字符的轮廓(高宽比在1.5-8之间,宽度大于3)

        if (word[3] > (word[2] * 1.5)) and (word[3] < (word[2] * 8)) and (word[2] > 3):

            plateChar = image[word[1]:word[1] + word[3], word[0]:word[0] + word[2]]

            plateChars.append(plateChar)

    return plateChars

### 5. 模板定义与加载模块

此模块定义了字符模板字典和加载模板的函数,支持数字、字母和中文字符的识别。

#=================模板,部分省份,使用字典表示==============================

templateDict = {0:'0',1:'1',2:'2',3:'3',4:'4',5:'5',6:'6',7:'7',8:'8',9:'9',

            10:'A',11:'B',12:'C',13:'D',14:'E',15:'F',16:'G',17:'H',

            18:'J',19:'K',20:'L',21:'M',22:'N',23:'P',24:'Q',25:'R',

            26:'S',27:'T',28:'U',29:'V',30:'W',31:'X',32:'Y',33:'Z',

            34:'京',35:'津',36:'冀',37:'晋',38:'蒙',39:'辽',40:'吉',41:'黑',

            42:'沪',43:'苏',44:'浙',45:'皖',46:'闽',47:'赣',48:'鲁',49:'豫',

            50:'鄂',51:'湘',52:'粤',53:'桂',54:'琼',55:'渝',56:'川',57:'贵',

            58:'云',59:'藏',60:'陕',61:'甘',62:'青',63:'宁',64:'新',

            65:'港',66:'澳',67:'台'}
# ==================获取所有字符的路径信息===================

def getcharacters():

    c = []

    for i in range(0, 67):

        words = []

        words.extend(glob.glob('template/'+templateDict.get(i)+'/*.*'))

        c.append(words)

    return c

### 6. 字符识别模块

字符识别模块是系统的核心,负责计算待识别字符与模板之间的匹配度,并返回最佳匹配结果。

#=============计算匹配值函数=====================

def getMatchValue(template, image):

    # 读取模板图像(支持中文路径)

    templateImage = cv2.imdecode(np.fromfile(template, dtype=np.uint8), 1)

    # 模板图像色彩空间转换,BGR-->灰度

    templateImage = cv2.cvtColor(templateImage, cv2.COLOR_BGR2GRAY)

    # 模板图像阈值处理, 灰度-->二值

    ret, templateImage = cv2.threshold(templateImage, 0, 255, cv2.THRESH_OTSU)

    # 获取待识别图像的尺寸

    height, width = image.shape

    # 将模板图像调整为与待识别图像尺寸一致

    templateImage = cv2.resize(templateImage, (width, height))

    # 计算模板图像与待识别图像的匹配值

    result = cv2.matchTemplate(image, templateImage, cv2.TM_CCOEFF)

    # 返回匹配结果

    return result[0][0]
# ===========对车牌内字符进行识别====================

def matchChars(plates, chars):

    results = []   # 存储所有的识别结果

   

    # 遍历每个待识别的字符

    for plateChar in plates:

        bestMatch = []      # 存储每个模板字符的最佳匹配值

       

        # 遍历每个模板字符

        for words in chars:

            match = []      # 存储当前模板字符的所有匹配值

           

            # 遍历当前字符的所有模板

            for word in words:

                result = getMatchValue(word, plateChar)

                match.append(result)

           

            # 取当前字符的最佳匹配值

            bestMatch.append(max(match))

       

        # 找到最佳匹配的字符索引

        i = bestMatch.index(max(bestMatch))

        # 获取对应的字符

        r = templateDict[i]

        results.append(r)

       

    return results  # 返回所有字符的识别结果

## 五、完整系统集成

将上述各个模块整合起来,形成完整的车牌识别系统:

# ==================主函数=====================

def main():

    # 读取测试图像

    image = cv2.imread('测试图像路径.jpg')

   

    # 1. 提取车牌

    plate = getPlate(image)

   

    # 2. 预处理车牌图像

    processed_plate = preprocessor(plate)

   

    # 3. 分割字符

    chars = splitPlate(processed_plate)

   

    # 4. 加载模板

    templates = getcharacters()

   

    # 5. 识别字符

    result = matchChars(chars, templates)

   

    # 6. 显示结果

    print('识别结果:', ''.join(result))

   

    # 显示原始图像和处理结果

    cv2.imshow('原始图像', image)

    cv2.imshow('提取的车牌', plate)

    cv2.imshow('预处理后的车牌', processed_plate)

   

    # 显示分割后的字符

    for i, char_img in enumerate(chars):

        cv2.imshow(f'字符{i}', char_img)

   

    cv2.waitKey(0)

    cv2.destroyAllWindows()



if __name__ == '__main__':

    main()

## 六、关键技术点解析

### 1. 车牌定位技术

系统通过以下步骤实现车牌定位:

- **高斯模糊**:去除图像噪声

- **边缘检测**:使用Sobel算子提取垂直边缘特征

- **自适应阈值**:将图像转换为二值图像

- **形态学操作**:通过开闭运算增强车牌区域特征

- **轮廓筛选**:根据车牌的宽高比特征(宽度>3倍高度)筛选出车牌区域

### 2. 字符分割技术

字符分割主要基于以下原理:

- **轮廓检测**:检测车牌中的所有字符轮廓

- **坐标排序**:按照x轴坐标从左到右排序,确保字符顺序正确

- **尺寸筛选**:根据字符的高宽比特征筛选出有效的字符区域

### 3. 模板匹配识别技术

字符识别采用模板匹配算法:

- **模板库**:建立包含数字、字母和中文字符的模板库

- **图像预处理**:确保待识别字符与模板具有相同的尺寸和特征

- **相关系数匹配**:使用`cv2.TM_CCOEFF`方法计算匹配度

- **最佳匹配**:选择匹配度最高的模板作为识别结果

## 七、系统优化与改进方向

虽然本系统能够实现基础的车牌识别功能,但在实际应用中仍有一些优化空间:

1. **光照适应性优化**:增加图像增强算法,提高在不同光照条件下的识别率

2. **角度校正**:添加车牌倾斜检测和校正功能,提高对倾斜车牌的识别能力

3. **深度学习识别**:引入CNN等深度学习方法代替传统的模板匹配,提高识别准确率和鲁棒性

4. **多线程处理**:优化图像处理流程,提高识别速度

5. **车牌类型扩展**:支持更多类型的车牌识别

## 八、总结

本文介绍了基于OpenCV的车牌识别系统的完整实现过程,包括车牌定位、图像预处理、字符分割和字符识别四个主要模块。该系统采用传统的计算机视觉方法,通过图像增强、形态学操作和模板匹配等技术实现车牌识别功能。

通过学习和理解这个系统,读者可以掌握计算机视觉在字符识别领域的基本应用方法,为进一步研究更复杂的图像处理和模式识别系统奠定基础。

## 九、代码获取与运行说明 

1. 安装了所需的依赖库(OpenCV、NumPy、Matplotlib)

2. 在项目目录下创建了template文件夹,并放入字符模板图像

3. 修改代码中的图像路径为实际的测试图像路径

**注意**:模板图像需要按照本文提供的templateDict字典中的字符分类存放,以便系统正确加载和匹配。

转载自CSDN-专业IT技术社区

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/2301_78102409/article/details/150986284

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--