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

基于机器学习(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==2hist = [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]] += 1p = [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]*255return imgdef find_board_area(img):assert img.ndim==2img_h,img_w = img.shape[0],img.shape[1]top,bottom,left,right = 0,img_h,0,img_wflag = Falseh_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] += 1if flag==False and h_proj[row]>12:flag = Truetop = rowif flag==True and row>top+8 and h_proj[row]<12:bottom = rowflag = Falsefor 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] += 1if flag==False and (v_proj[col]>10 or v_proj[col]-v_proj[col-1]>5):left = colbreakreturn 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_rectrotate_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)%4cv2.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,0img_w = plate.shape[1]# 获取车牌每列边缘像素点个数def getColSum(img,col):sum = 0for i in range(img.shape[0]):sum += round(img[i,col]/255)return sum;sum = 0for 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 = Falsefor 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_leftchar_width = char_right-char_leftif (area_width>charWid_limit[0]) and (area_width<charWid_limit[1]):char_addr_list.append((area_left,area_right,char_width))char_left = iarea_left = round((char_left+char_right) / 2)is_char_flag = Trueelse:if is_char_flag == True:char_right = i-1is_char_flag = False# 手动结束最后未完成的字符分割if area_right < char_left:area_right,char_right = img_w,img_warea_width = area_right - area_leftchar_width = char_right - char_leftif (area_width > charWid_limit[0]) and (area_width < charWid_limit[1]):char_addr_list.append((area_left, area_right, char_width))return char_addr_listdef get_chars(car_plate):img_h,img_w = car_plate.shape[:2]h_proj_list = [] # 水平投影长度列表h_temp_len,v_temp_len = 0,0h_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 = 0for col in range(img_w):if car_plate[row,col] == 255:temp_cnt += 1h_count[row] = temp_cntif 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-1h_proj_list.append((h_startIndex,h_end_index))h_temp_len = 0continueif temp_cnt > 0:if h_temp_len == 0:h_startIndex = rowh_temp_len = 1else:h_temp_len += 1else:if h_temp_len > 0:h_end_index = row-1h_proj_list.append((h_startIndex,h_end_index))h_temp_len = 0# 手动结束最后得水平投影长度累加if h_temp_len != 0:h_end_index = img_h-1h_proj_list.append((h_startIndex, h_end_index))# 选出最长的投影,该投影长度占整个截取车牌高度的比值必须大于0.5h_maxIndex,h_maxHeight = 0,0for i,(start,end) in enumerate(h_proj_list):if h_maxHeight < (end-start):h_maxHeight = (end-start)h_maxIndex = iif h_maxHeight/img_h < 0.5:return char_imgschars_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_imgsdef cnn_recongnize_char(img_list,model_path):g2 = tf.Graph()sess2 = tf.Session(graph=g2)text_list = []if len(img_list) == 0:return text_listwith 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_listif __name__ == '__main__':cur_dir = sys.path[0]car_plate_w,car_plate_h = 136,36char_w,char_h = 20,20plate_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.hqwc.cn/news/191327.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

腾讯云服务器租用价格,腾讯云服务器价格流量怎么算?

首先&#xff0c;让我们来看看腾讯云服务器租用价格。根据您的需求不同&#xff0c;腾讯云提供了多种不同的配置选项&#xff0c;从轻量级应用服务器到高性能的GPU服务器&#xff0c;都可以满足您的需求。以下是一些常见的腾讯云服务器租用价格&#xff1a; 一、腾讯云服务器租…

代码随想录 Day49 单调栈01 LeetCode LeetCodeT739每日温度 T496 下一个最大元素I

前言 折磨的死去活来的动态规划终于结束啦,今天秋秋给大家带来两题非常经典的单调栈问题,可能你不清楚单调栈是什么,可以用来解决什么问题,今天我们就来一步一步的逐渐了解单调栈,到能够灵活使用单调栈.注意以下讲解中&#xff0c;顺序的描述为 从栈头到栈底的顺序 什么时候用单…

解决:虚拟机远程连接失败

问题 使用FinalShell远程连接虚拟机的时候连接不上 发现 虚拟机用的VMware&#xff0c;Linux发行版是CentOs 7&#xff0c;发现在虚拟机中使用ping www.baidu.com是成功的&#xff0c;但是使用FinalShell远程连接不上虚拟机&#xff0c;本地网络也ping不通虚拟机&#xff0c…

STM32 HAL库函数HAL_SPI_Receive_IT和HAL_SPI_Receive的区别

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

Typecho用宝塔面板建站(保姆级教程)

提前准备&#xff1a; 1 已备案域名 注意:在腾讯云备案的域名部署阿里云服务器的话还需要在阿里云备案&#xff0c;反之亦然 2 服务器 服务器操作系统设置为windows 服务器实例设置&#xff1a;依次开放8888/888/443/3000-4000/21/22端口 个人用的阿里云&#xff0c;到安全组配…

带您识别RJ45网口连接器/网口插座口的LED灯的平脚/斜脚,带弹/不带弹细节区分

Hqst华强盛&#xff08;盈盛电子&#xff09;导读&#xff1a;网口连接器,网口插座&#xff0c;也叫网口母座,因为产品规格众多&#xff0c;常常因为细小差别&#xff0c;耽误工程设计级或者生产排期延误&#xff0c;今天就带大家一起来认识下平脚RJ45网口连接器/网口插座与斜脚…

51.Sentinel微服务保护

目录 &#xff08;1&#xff09;初识Sentinel。 &#xff08;1.1&#xff09;雪崩问题及解决方案。 &#xff08;1.1.1&#xff09;雪崩问题。 &#xff08;1.1.2&#xff09;解决雪崩问题的四种方式。 &#xff08;1.1.3&#xff09;总结。 &#xff08;1.2&#xff09;…

Git 简介及使用

前言 假设有这样一个场景&#xff0c;老板让员工做一个档案&#xff0c;员工这个档案做好了之后交给老板看&#xff0c;此时老板不满意&#xff0c;又让回去改&#xff0c;改完给老板看&#xff0c;但是老板又不是很满意&#xff0c;就这样改了又改&#xff0c;给老板看过之后&…

智慧工地APP全套源码,智慧工地云平台

智慧工地平台 &#xff0c;智慧工地源码&#xff0c;智慧工地APP全套源码 智慧工地以施工现场风险预知和联动预控为目标&#xff0c;将智能AI、传感技术、人像识别、监控、虚拟现实、物联网、5G、大数据、互联网等新一代科技信息技术植入到建筑、机械、人员穿戴设施、场地进出关…

Leetcode—141.环形链表【简单】

2023每日刷题&#xff08;三十三&#xff09; Leetcode—141.环形链表 快慢指针算法思想 关于快慢指针为什么能检测出环&#xff0c;可以这么思考。 假设存在一个环: 慢指针进入环后&#xff0c;快指针和慢指针之间相距为d&#xff0c;每一次移动&#xff0c;d都会缩小1&…

C++模版初阶

泛型编程 如下的交换函数中&#xff0c;它们只有类型的不同&#xff0c;应该怎么实现一个通用的交换函数呢&#xff1f; void Swap(int& left, int& right) {int temp left;left right;right temp; }void Swap(double& left, double& right) {double temp…

资产设备管理系统

dtAsset 是一个固定资产设备管理系统&#xff0c;它专为中小企业的需求而设计。该软件提供了对常用资产设备进行信息化管理的功能&#xff0c;并支持自定义设备类型、导入导出数据、维护工作统计、采购管理、文档管理、运维监控 (使用 Zabbix)、知识库等功能。 主要模块 1.系统…