课程设计(毕业设计)—基于机器学习(CNN+opencv+python)的车牌识别—(可远程调试)计算机专业课程设计(毕业设计)

news2024/11/23 1:38:18

基于机器学习(CNN+opencv+python)的车牌识别

  • 下载本文机器学习(CNN+opencv+python)的车牌识别系统完整的代码和参考报告链接(或者可以联系博主koukou(壹壹23七2五六98),获取源码和报告)https://download.csdn.net/download/shooter7/88548767
  • 此处是另外一个系统描述的链接:机器学习Opencv和SVM的车牌识别系统,可用于毕设课设。https://blog.csdn.net/shooter7/article/details/129935028

文章目录

      • 基于机器学习(CNN+opencv+python)的车牌识别
      • 摘要
      • 调试导入和运行结果展示
      • 识别流程分解
        • 车牌定位
        • 字符分割
      • 源码操作流程

摘要

车牌识别是计算机视觉领域的一个重要应用,它利用图像处理和模式识别技术对车辆的车牌进行自动识别。CNN(卷积神经网络)是一种深度学习模型,近年来在图像识别任务中取得了显著的成果。CNN车牌识别的过程包括以下几个步骤:1.图像预处理:对输入的车辆图片进行灰度化、二值化、去噪等处理,以减少噪声和不必要的信息。2.特征提取:利用卷积层和池化层从预处理后的图像中提取出有用的特征,如边缘、角点、纹理等。3.分类器训练:将提取出的特征输入到全连接层中,通过反向传播算法对网络参数进行优化,使网络能够准确地识别车牌号码。4.车牌定位:在识别过程中,还需要对车牌进行定位,以便准确地提取出车牌上的数字和字母。5.输出结果:最后,将识别出的车牌号码输出给用户或其他应用程序使用。

调试导入和运行结果展示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

识别流程分解

关于车牌预处理,网上有很多说法,不过都差不太多。预处理的目的在于找到“疑似车牌”的大概位置,为下一步定位车牌做准备

  1. 加载原始图片加载原始图片
  2. RGB图片转灰度图:减少数据量
  3. 均值模糊
  4. sobel获取垂直边缘
  5. 原始图片从RGB转HSV:车牌背景色一般是蓝色或黄色(至于h、s、v的设置参考这里:
  6. 从sobel处理后的图片找到蓝色或黄色区域:从HSV中取出蓝色、黄色区域,和sobel处理后的图片相乘
  7. 二值化
  8. 闭运算
车牌定位

在CNN车牌识别中,车牌定位是一个重要的过程。这个过程主要包括以下步骤:

  1. 图像预处理:对输入的车辆图片进行灰度化、二值化、去噪等处理,以减少噪声和不必要的信息。
  2. 车牌区域定位:通过图像处理技术,如边缘检测、形状分析等方法,从预处理后的图像中找出可能包含车牌的区域。这是定位车牌的第一步。
  3. 车牌截取:在确定了可能包含车牌的区域后,需要从原图中截取出这个区域,以便后续进行字符分割和识别。
  4. 字符分割与识别:将截取的车牌区域分割成一个一个的小图,即字符图片。然后依次对这些字符图片进行识别,先识别省份,再识别城市、再识别号码。
  5. 输出结果:最后,将识别出的车牌号码以及对应的省份、城市信息输出给用户或其他应用程序使用。

    这里主要用到漫水填充算法(类似PS的魔术棒),通过在矩形区域生成种子点,种子点的颜色必须是蓝色或黄色,在填充后的掩模上绘制外接矩形,再依次判断这个外接矩形的尺寸是否符合车牌要求,最后再把矩形做仿射变换校准位置。
    在这里插入图片描述
字符分割

字符轮廓提取:利用卷积神经网络等技术,对预处理后的图像进行特征提取,并进一步提取出字符的轮廓。
字符分割:根据字符轮廓,将车牌中的字符一个个分割出来。这一步骤通常需要设定一个合适的阈值,通过阈值处理来找出波峰,即字符的分隔点。
返回字符图像列表:分割完成后,将各个字符的图片整理成一个列表,以便后续进行识别。
在这里插入图片描述
分割完后,用CNN算法进行车牌识别

源码操作流程

在这里插入图片描述

  • 部分源码
import cv2
import os
import sys
import numpy as np
import tensorflow._api.v2.compat.v1 as tf
tf.disable_v2_behavior()

char_table = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
              'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '川', '鄂', '赣', '甘', '贵',
              '桂', '黑', '沪', '冀', '津', '京', '吉', '辽', '鲁', '蒙', '闽', '宁', '青', '琼', '陕', '苏', '晋',
              '皖', '湘', '新', '豫', '渝', '粤', '云', '藏', '浙']

def hist_image(img):
    assert img.ndim==2
    hist = [0 for i in range(256)]
    img_h,img_w = img.shape[0],img.shape[1]

    for row in range(img_h):
        for col in range(img_w):
            hist[img[row,col]] += 1
    p = [hist[n]/(img_w*img_h) for n in range(256)]
    p1 = np.cumsum(p)
    for row in range(img_h):
        for col in range(img_w):
            v = img[row,col]
            img[row,col] = p1[v]*255
    return img

def find_board_area(img):
    assert img.ndim==2
    img_h,img_w = img.shape[0],img.shape[1]
    top,bottom,left,right = 0,img_h,0,img_w
    flag = False
    h_proj = [0 for i in range(img_h)]
    v_proj = [0 for i in range(img_w)]

    for row in range(round(img_h*0.5),round(img_h*0.8),3):
        for col in range(img_w):
            if img[row,col]==255:
                h_proj[row] += 1
        if flag==False and h_proj[row]>12:
            flag = True
            top = row
        if flag==True and row>top+8 and h_proj[row]<12:
            bottom = row
            flag = False

    for col in range(round(img_w*0.3),img_w,1):
        for row in range(top,bottom,1):
            if img[row,col]==255:
                v_proj[col] += 1
        if flag==False and (v_proj[col]>10 or v_proj[col]-v_proj[col-1]>5):
            left = col
            break
    return left,top,120,bottom-top-10
# 车牌定位
def locate_carPlate(orig_img,pred_image):
    carPlate_list = []
    temp1_orig_img = orig_img.copy() #调试用
    temp2_orig_img = orig_img.copy() #调试用
    contours,heriachy = cv2.findContours(pred_image,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
    for i,contour in enumerate(contours):
        cv2.drawContours(temp1_orig_img, contours, i, (0, 255, 255), 2)
        # 获取轮廓最小外接矩形,返回值rotate_rect
        rotate_rect = cv2.minAreaRect(contour)
        # 根据矩形面积大小和长宽比判断是否是车牌
        if verify_scale(rotate_rect):
            print("1")
            ret,rotate_rect2 = verify_color(rotate_rect,temp2_orig_img)
            if ret == False:
                continue
            # 车牌位置矫正
            car_plate = img_Transform(rotate_rect2, temp2_orig_img)
            car_plate = cv2.resize(car_plate,(car_plate_w,car_plate_h)) #调整尺寸为后面CNN车牌识别做准备
            #========================调试看效果========================#
            box = cv2.boxPoints(rotate_rect2)
            for k in range(4):
                n1,n2 = k%4,(k+1)%4
                cv2.line(temp1_orig_img,(int(box[n1][0]),int(box[n1][1])),(int(box[n2][0]),int(box[n2][1])),(255,0,0),2)
            cv2.imshow('opencv_' + str(i), car_plate)
            print("2")
            #========================调试看效果========================#
            carPlate_list.append(car_plate)

    cv2.imshow('contour', temp1_orig_img)
    #cv2.waitKey(0)
    return carPlate_list

# 左右切割
def horizontal_cut_chars(plate):
    char_addr_list = []
    area_left,area_right,char_left,char_right= 0,0,0,0
    img_w = plate.shape[1]

    # 获取车牌每列边缘像素点个数
    def getColSum(img,col):
        sum = 0
        for i in range(img.shape[0]):
            sum += round(img[i,col]/255)
        return sum;

    sum = 0
    for col in range(img_w):
        sum += getColSum(plate,col)
    # 每列边缘像素点必须超过均值的60%才能判断属于字符区域
    col_limit = 0#round(0.5*sum/img_w)
    # 每个字符宽度也进行限制
    charWid_limit = [round(img_w/12),round(img_w/5)]
    is_char_flag = False

    for i in range(img_w):
        colValue = getColSum(plate,i)
        if colValue > col_limit:
            if is_char_flag == False:
                area_right = round((i+char_right)/2)
                area_width = area_right-area_left
                char_width = char_right-char_left
                if (area_width>charWid_limit[0]) and (area_width<charWid_limit[1]):
                    char_addr_list.append((area_left,area_right,char_width))
                char_left = i
                area_left = round((char_left+char_right) / 2)
                is_char_flag = True
        else:
            if is_char_flag == True:
                char_right = i-1
                is_char_flag = False
    # 手动结束最后未完成的字符分割
    if area_right < char_left:
        area_right,char_right = img_w,img_w
        area_width = area_right - area_left
        char_width = char_right - char_left
        if (area_width > charWid_limit[0]) and (area_width < charWid_limit[1]):
            char_addr_list.append((area_left, area_right, char_width))
    return char_addr_list

def get_chars(car_plate):
    img_h,img_w = car_plate.shape[:2]
    h_proj_list = [] # 水平投影长度列表
    h_temp_len,v_temp_len = 0,0
    h_startIndex,h_end_index = 0,0 # 水平投影记索引
    h_proj_limit = [0.2,0.8] # 车牌在水平方向得轮廓长度少于20%或多余80%过滤掉
    char_imgs = []

    # 将二值化的车牌水平投影到Y轴,计算投影后的连续长度,连续投影长度可能不止一段
    h_count = [0 for i in range(img_h)]
    for row in range(img_h):
        temp_cnt = 0
        for col in range(img_w):
            if car_plate[row,col] == 255:
                temp_cnt += 1
        h_count[row] = temp_cnt
        if temp_cnt/img_w<h_proj_limit[0] or temp_cnt/img_w>h_proj_limit[1]:
            if h_temp_len != 0:
                h_end_index = row-1
                h_proj_list.append((h_startIndex,h_end_index))
                h_temp_len = 0
            continue
        if temp_cnt > 0:
            if h_temp_len == 0:
                h_startIndex = row
                h_temp_len = 1
            else:
                h_temp_len += 1
        else:
            if h_temp_len > 0:
                h_end_index = row-1
                h_proj_list.append((h_startIndex,h_end_index))
                h_temp_len = 0

    # 手动结束最后得水平投影长度累加
    if h_temp_len != 0:
        h_end_index = img_h-1
        h_proj_list.append((h_startIndex, h_end_index))
    # 选出最长的投影,该投影长度占整个截取车牌高度的比值必须大于0.5
    h_maxIndex,h_maxHeight = 0,0
    for i,(start,end) in enumerate(h_proj_list):
        if h_maxHeight < (end-start):
            h_maxHeight = (end-start)
            h_maxIndex = i
    if h_maxHeight/img_h < 0.5:
        return char_imgs
    chars_top,chars_bottom = h_proj_list[h_maxIndex][0],h_proj_list[h_maxIndex][1]

    plates = car_plate[chars_top:chars_bottom+1,:]
    cv2.imwrite('./carIdentityData/opencv_output/car.jpg',car_plate)
    cv2.imwrite('./carIdentityData/opencv_output/plate.jpg', plates)
    char_addr_list = horizontal_cut_chars(plates)

    for i,addr in enumerate(char_addr_list):
        char_img = car_plate[chars_top:chars_bottom+1,addr[0]:addr[1]]
        char_img = cv2.resize(char_img,(char_w,char_h))
        char_imgs.append(char_img)
    return char_imgs

def cnn_recongnize_char(img_list,model_path):
    g2 = tf.Graph()
    sess2 = tf.Session(graph=g2)
    text_list = []

    if len(img_list) == 0:
        return text_list
    with sess2.as_default():
        with sess2.graph.as_default():
            model_dir = os.path.dirname(model_path)
            saver = tf.train.import_meta_graph(model_path)
            saver.restore(sess2, tf.train.latest_checkpoint(model_dir))
            graph = tf.get_default_graph()
            net2_x_place = graph.get_tensor_by_name('x_place:0')
            net2_keep_place = graph.get_tensor_by_name('keep_place:0')
            net2_out = graph.get_tensor_by_name('out_put:0')

            data = np.array(img_list)
            # 数字、字母、汉字,从67维向量找到概率最大的作为预测结果
            net_out = tf.nn.softmax(net2_out)
            preds = tf.argmax(net_out,1)
            my_preds= sess2.run(preds, feed_dict={net2_x_place: data, net2_keep_place: 1.0})

            for i in my_preds:
                text_list.append(char_table[i])
            return text_list

if __name__ == '__main__':
    cur_dir = sys.path[0]
    car_plate_w,car_plate_h = 136,36
    char_w,char_h = 20,20
    plate_model_path = os.path.join(cur_dir, './carIdentityData/model/plate_recongnize/model.ckpt-510.meta')
    char_model_path = os.path.join(cur_dir,'./carIdentityData/model/char_recongnize/model.ckpt-550.meta')
    img = cv2.imread('../images/images/pictures/3.jpg')

    # 预处理
    pred_img = pre_process(img)

    # 车牌定位
    car_plate_list = locate_carPlate(img,pred_img)
    print(car_plate_list)
    # CNN车牌过滤
    ret,car_plate = cnn_select_carPlate(car_plate_list,plate_model_path)
    if ret == False:
        print("未检测到车牌")
        sys.exit(-1)
    cv2.imshow('cnn_plate',car_plate)

    # 字符提取
    char_img_list = extract_char(car_plate)

    # CNN字符识别
    text = cnn_recongnize_char(char_img_list,char_model_path)
    print(text)

    cv2.waitKey(0)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1223972.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

操作系统·进程同步

进程同步&#xff1a;异步环境下的一组并发进程因直接制约而互相发送消息、互相合作、互相等待&#xff0c;使得各进程按照一定的速度执行的过程。 进程同步的主要任务是使并发执行的诸进程之间能有效地共享资源和相互合作&#xff0c;使执行的结果具有可再现性。 4.1 进程同…

智慧城市指挥中心,大屏幕究竟有什么用?

目前很多地区有在兴建智慧城市的项目&#xff0c;其城市指挥中心内一般都建有一张巨大的屏幕&#xff0c;这张屏幕究竟有什么用&#xff1f;是否可以用普通的电脑显示器进行代替呢&#xff1f; 智慧城市指挥中心内的巨大屏幕是智慧城市项目中的重要组成部分&#xff0c;其作用不…

​软考-高级-系统架构设计师教程(清华第2版)【第14章 云原生架构设计理论与实践(P496~526)-思维导图】​

软考-高级-系统架构设计师教程&#xff08;清华第2版&#xff09;【第14章 云原生架构设计理论与实践&#xff08;P496~526&#xff09;-思维导图】 课本里章节里所有蓝色字体的思维导图

Springboot+vue的应急物资管理系统(有报告),Javaee项目,springboot vue前后端分离项目

演示视频&#xff1a; Springbootvue的应急物资管理系统&#xff08;有报告&#xff09;&#xff0c;Javaee项目&#xff0c;springboot vue前后端分离项目 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。…

【GUI】-- 09 JComboBox JList、JTextField JPasswordField JTextArea

GUI编程 03 Swing 3.6 列表 下拉框 package com.duo.lesson06;import javax.swing.*; import java.awt.*;public class ComboBoxDemo01 extends JFrame {public ComboBoxDemo01() throws HeadlessException {Container contentPane getContentPane();JComboBox<Object&…

Flutter 3.16 中带来的更新

Flutter 3.16 中带来的更新 目 录 1. 概述2. 框架更新2.1 Material 3 成为新默认2.2 支持 Material 3 动画2.3 TextScaler2.4 SelectionArea 更新2.5 MatrixTransition 动画2.6 滚动更新2.7 在编辑菜单中添加附加选项2.8 PaintPattern 添加到 flutter_test 3. 引擎更新&#xf…

STM32 HAL库函数HAL_SPI_Receive_IT和HAL_SPI_Receive的区别

背景 前段时间开发一个按键板驱动&#xff0c;该板用的STM32F103系列单片机&#xff0c;前任工程师用STM32CubeMX生成的工程&#xff0c;里面全是HAL库调用&#xff0c;我接手后&#xff0c;学习了下HAL库的用法&#xff0c;踩坑不少&#xff0c;特别是带IT后缀的函数&#xf…

S7-1200PLC 作为MODBUSTCP服务器通信(多客户端访问)

S7-1200PLC作为MODBUSTCP服务器端通信编程应用&#xff0c;详细内容请查看下面文章链接&#xff1a; ModbusTcp通信(S7-1200PLC作为服务器端)-CSDN博客文章浏览阅读239次。S7-200Smart plc作为ModbusTcp服务器端的通信S7-200SMART PLC ModbusTCP通信(ModbusTcp服务器)_s7-200 …

基于MS16F3211芯片的触摸控制灯的状态变化和亮度控制(11.17,PWM控制与状态切换)

1.今天做了什么 2.过程思路 看了两天文档才慢慢看懂&#xff0c;有点满了 现在接着前一天的思路&#xff0c;可以通过代码来控制pwm的占空比。我这里采用的是TP0定时器 初步控制pwm的占空比 void LED_PWM_OPEN(void) {//占空比 PWM1-Y-PB2PWM1DH 0X0F;PWM1DL 0X00; //占…

python3:turtle绘图 .2023-11-18

绘制一个菱形:四边相等且都为200像素;四个内角两边各为60度,上下各为120度 import turtle #导入turtle #画笔默认绘制方向为水平向右 turtle.right(-30) #画笔绘制方向向左(逆时针)旋转30度. turtle.fd(200) #画笔沿绘制方向绘制200像素长度 turtle.right(60) #画笔绘制方向在…

OSS服务和MinIO存储做一个区分解析

日落金山&#xff0c;明天我们继续… 什么是OSS服务和MinIO存储 OSS&#xff08;Object Storage Service&#xff09;和MinIO都是对象存储服务&#xff0c;但它们有一些区别。以下是对它们的简要分析&#xff1a; 1. 部署和管理&#xff1a; OSS&#xff1a; 由阿里云提供&a…

HDMI之EDID析义篇

DisplayID Type X Video Timing Data Block 实例 F0 2A 10 93 FF 0E 6F 08 8F 10 93 7F 07 37 04 8F 10该数据来源于SHARP AQUOS-TVE23A 4K144Hz电视机的第3个EDID块(基于HF-EEODB)。 定义 解释 VTDB 1: 3840x2160 144.000009 Hz 16:9 333.216 kHz 1343.527000 MHz (RBv3,h…

UE 程序化网格 计算横截面

首先在构造函数内加上程序化网格&#xff0c;然后复制网格体到程序化网格组件上&#xff0c;将Static Mesh&#xff08;类型StaticMeshActor&#xff09;的静态网格体组件给到程序化网格体上 然后把StaticMesh&#xff08;类型为StaticMeshActor&#xff09;Instance暴漏出去 …

python基础练习题库实验1

题目1 使用以下变量 product_code“377B” product_name“牛肉汤” product_size“250mL” product_price2.15 使用字符串加法编写一个print语句&#xff0c;以便生成以下精确输出&#xff1a; 377B&#xff1a;牛肉汤&#xff0c;250mL 代码 product_code "377B"…

深入了解Java 8 新特性:lambda表达式进阶

阅读建议 嗨&#xff0c;伙计&#xff01;刷到这篇文章咱们就是有缘人&#xff0c;在阅读这篇文章前我有一些建议&#xff1a; 本篇文章大概7000多字&#xff0c;预计阅读时间长需要10分钟。本篇文章的实战性、理论性较强&#xff0c;是一篇质量分数较高的技术干货文章&#…

这个双11,阿里云经历了可能是历史级的大故障!

2023年11月12日17&#xff1a;44开始&#xff0c;阿里云发生严重故障&#xff0c;导致阿里巴巴大量产品无法连接&#xff0c;一时间&#xff0c;“阿里云盘崩了”、“淘宝又崩了”、“闲鱼崩了”、“钉钉崩了”等话题相继登上热搜。 此外&#xff0c;像纳思云充电桩、乐爽coole…

Git安装与常用命令

Git简介&#xff1a; Git是一个开源的分布式版本控制系统&#xff0c;用于敏捷高效地处理任何或大或小的项目。Git是Linus Torvalds为了帮助管理Linux内核开发而开发的一个开放源代码的版本控制软件。Git与常用的版本控制工具CVS、Subversion等不同&#xff0c;它采用了分布式…

机器学习算法——集成学习

目录 1. Bagging 1. Bagging Bagging&#xff08;bootstrap aggregating&#xff1a;自举汇聚法&#xff09;也叫装袋法&#xff0c;其思想是通过将许多相互独立的学习器的结果进行结合&#xff0c;从而提高整体学习器的泛化能力&#xff0c;是一种并行集成学习方法。 工作流…

IO流-框架

一&#xff0c;框架概念 二&#xff0c;Commons-io框架 三&#xff0c;使用案例 package BigDecimal;import org.apache.commons.io.FileUtils;import java.io.File; import java.io.IOException;public class Main12 {public static void main(String[] args) throws IOExcept…

centos7安装mongodb

1、下载mongodb https://www.mongodb.com/try/download/community 2、解压 3、重命名 4、创建mongodb的data、logs目录 5、启动mongodb, bin/mongod --port27017 --dbpath/data/program/mongodb/data --logpath/data/program/mongodb/logs/mongodb.log --bind_ip0.0.0.0 --f…