OpenCV实例(八)车牌字符识别技术(三)汉字识别

news2024/11/25 20:31:02

车牌字符识别技术(三)汉字识别

  • 1.代码实例
  • 2.遇到问题
  • 3.汉字识别代码实例

相较于数字和英文字符的识别,汽车牌照中的汉字字符识别的难度更大,主要原因有以下4个方面:

(1)字符笔画因切分误差导致非笔画或笔画流失。

(2)汽车牌照被污染导致字符上出现污垢。

(3)采集所得车辆图像分辨率低导致多笔画的汉字较难分辨。

(4)车辆图像采集时所受光照影响的差异导致笔画较淡。

综合汉字识别时的这些难点来看,很难被直接提取的是字符的局部特征。笔画作为最重要的特征而仅存在于汉字中,这由先验知识可知。一旦捺、横、竖、撇这些笔画特征被提取到,对于汉字字符识别的工作就完成了许多。在水平方向上,横笔画的灰度值的波动表现为低频,竖笔画的灰度变化表现为低频;在垂直方向上,横笔画的灰度变化表现为高频,竖笔画的灰度变化表现为高频。在汉字字符特征的提取过程中,对于小波的多分辨率特性的利用显然是一个不错的选择。

对于汉字进识别的相关工作,在一系列对图像进行预处理以及对图像的特征进行提取等相关操作后就可以进行了。第一步是预处理原始图像;第二步是对字符的原始特征进行提取(主要通过小波变换进行),并降维处理原始特征(主要采用线性判别式分析(LDA)变换矩阵进行),获取字符的最终特征;第三步是在特征模板匹配和最小距离分类器中读入获取所得到的最终特征,得到字符的最终识别结果。

1.代码实例

中文车牌的识别(包括新能源汽车)

import cv2 as cv
from PIL import Image
import pytesseract as tess


def recoginse_text(image):
    """
    步骤:
    1、灰度,二值化处理
    2、形态学操作去噪
    3、识别
    :param image:
    :return:
    """

    # 灰度 二值化
    gray = cv.cvtColor(image,cv.COLOR_BGR2GRAY)
    # 如果是白底黑字 建议 _INV
    ret,binary = cv.threshold(gray,0,255,cv.THRESH_BINARY_INV| cv.THRESH_OTSU)


    # 形态学操作 (根据需要设置参数(1,2))
    kernel = cv.getStructuringElement(cv.MORPH_RECT,(1,2))  #去除横向细线
    morph1 = cv.morphologyEx(binary,cv.MORPH_OPEN,kernel)
    kernel = cv.getStructuringElement(cv.MORPH_RECT, (2, 1)) #去除纵向细线
    morph2 = cv.morphologyEx(morph1,cv.MORPH_OPEN,kernel)
    cv.imshow("Morph",morph2)

    # 黑底白字取非,变为白底黑字(便于pytesseract 识别)
    cv.bitwise_not(morph2,morph2)
    textImage = Image.fromarray(morph2)

    # 图片转文字
    text=tess.image_to_string(textImage)
    n=10 #根据不同国家车牌固定数目进行设置
    print("识别结果:")
    print(text[1:n])
   


def main():
    # 读取需要识别的数字字母图片,并显示读到的原图
    src = cv.imread("cp.jpg")
    cv.imshow("src",src)

    # 识别
    recoginse_text(src)

    cv.waitKey(0)
    cv.destroyAllWindows()

if __name__=="__main__":
    main()





2.遇到问题

在这里插入图片描述

No module named ‘pytesseract’

缺少pytesseract 模块。

在环境中安装该模块

在这里插入图片描述
安装完成运行程序,结果又出现了一堆问题:

在这里插入图片描述
原因是没有安装pytesseract需要的Tesseract-OCR工具,Windows版本的安装包的下载路径为https://github.com/UB-Mannheim/tesseract/wiki

在这里插入图片描述

直接双击该文件进行安装即可。这里的安装位置(这个路径要记住,后面要用)采用默认值:

     C:\Program Files\Tesseract-OCR

配置pytesseract.py打开“我的计算机”,进入\Users==\AppData\Local\Programs\Python\Python38\Lib\site-packages\pytesseract\,找到pytesseract.py文件,用文本编辑器打开这个文件,找到"tesseract_cmd"关键字

在这里插入图片描述

至此,字符识别开发环境准备好了,下面就可以编写代码了。

代码实例:

import cv2 as cv
from PIL import Image
import pytesseract as tess


def recoginse_text(image):
    """
    步骤:
    1、灰度,二值化处理
    2、形态学操作去噪
    3、识别
    :param image:
    :return:
    """

    # 灰度 二值化
    gray = cv.cvtColor(image,cv.COLOR_BGR2GRAY)
    # 如果是白底黑字 建议 _INV
    ret,binary = cv.threshold(gray,0,255,cv.THRESH_BINARY_INV| cv.THRESH_OTSU)


    # 形态学操作 (根据需要设置参数(1,2))
    kernel = cv.getStructuringElement(cv.MORPH_RECT,(1,2))  #去除横向细线
    morph1 = cv.morphologyEx(binary,cv.MORPH_OPEN,kernel)
    kernel = cv.getStructuringElement(cv.MORPH_RECT, (2, 1)) #去除纵向细线
    morph2 = cv.morphologyEx(morph1,cv.MORPH_OPEN,kernel)
    cv.imshow("Morph",morph2)

    # 黑底白字取非,变为白底黑字(便于pytesseract 识别)
    cv.bitwise_not(morph2,morph2)
    textImage = Image.fromarray(morph2)

    # 图片转文字
    text=tess.image_to_string(textImage)
    n=10 #根据不同国家车牌固定数目进行设置
    print("识别结果:")
    print(text[1:n])
   


def main():
    # 读取需要识别的数字字母图片,并显示读到的原图
    src = cv.imread("cp.jpg")
    cv.imshow("src",src)

    # 识别
    recoginse_text(src)

    cv.waitKey(0)
    cv.destroyAllWindows()

if __name__=="__main__":
    main()



在这里插入图片描述

3.汉字识别代码实例

代码实例

import tkinter as tk
from tkinter.filedialog import *
from tkinter import ttk
import predict
import cv2
from PIL import Image, ImageTk
import threading
import time



class Surface(ttk.Frame):
	pic_path = ""
	viewhigh = 600
	viewwide = 600
	update_time = 0
	thread = None
	thread_run = False
	camera = None
	color_transform = {"green":("绿牌","#55FF55"), "yello":("黄牌","#FFFF00"), "blue":("蓝牌","#6666FF")}
		
	def __init__(self, win):
		ttk.Frame.__init__(self, win)
		frame_left = ttk.Frame(self)
		frame_right1 = ttk.Frame(self)
		frame_right2 = ttk.Frame(self)
		win.title("车牌识别")
		win.state("zoomed")
		self.pack(fill=tk.BOTH, expand=tk.YES, padx="5", pady="5")
		frame_left.pack(side=LEFT,expand=1,fill=BOTH)
		frame_right1.pack(side=TOP,expand=1,fill=tk.Y)
		frame_right2.pack(side=RIGHT,expand=0)
		ttk.Label(frame_left, text='原图:').pack(anchor="nw") 
		ttk.Label(frame_right1, text='车牌位置:').grid(column=0, row=0, sticky=tk.W)
		
		from_pic_ctl = ttk.Button(frame_right2, text="来自图片", width=20, command=self.from_pic)
		from_vedio_ctl = ttk.Button(frame_right2, text="来自摄像头", width=20, command=self.from_vedio)
		self.image_ctl = ttk.Label(frame_left)
		self.image_ctl.pack(anchor="nw")
		
		self.roi_ctl = ttk.Label(frame_right1)
		self.roi_ctl.grid(column=0, row=1, sticky=tk.W)
		ttk.Label(frame_right1, text='识别结果:').grid(column=0, row=2, sticky=tk.W)
		self.r_ctl = ttk.Label(frame_right1, text="")
		self.r_ctl.grid(column=0, row=3, sticky=tk.W)
		self.color_ctl = ttk.Label(frame_right1, text="", width="20")
		self.color_ctl.grid(column=0, row=4, sticky=tk.W)
		from_vedio_ctl.pack(anchor="se", pady="5")
		from_pic_ctl.pack(anchor="se", pady="5")
		self.predictor = predict.CardPredictor()
		self.predictor.train_svm()
		
	def get_imgtk(self, img_bgr):
		img = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
		im = Image.fromarray(img)
		imgtk = ImageTk.PhotoImage(image=im)
		wide = imgtk.width()
		high = imgtk.height()
		if wide > self.viewwide or high > self.viewhigh:
			wide_factor = self.viewwide / wide
			high_factor = self.viewhigh / high
			factor = min(wide_factor, high_factor)
			
			wide = int(wide * factor)
			if wide <= 0 : wide = 1
			high = int(high * factor)
			if high <= 0 : high = 1
			im=im.resize((wide, high), Image.ANTIALIAS)
			imgtk = ImageTk.PhotoImage(image=im)
		return imgtk
	
	def show_roi(self, r, roi, color):
		if r :
			roi = cv2.cvtColor(roi, cv2.COLOR_BGR2RGB)
			roi = Image.fromarray(roi)
			self.imgtk_roi = ImageTk.PhotoImage(image=roi)
			self.roi_ctl.configure(image=self.imgtk_roi, state='enable')
			self.r_ctl.configure(text=str(r))
			self.update_time = time.time()
			try:
				c = self.color_transform[color]
				self.color_ctl.configure(text=c[0], background=c[1], state='enable')
			except: 
				self.color_ctl.configure(state='disabled')
		elif self.update_time + 8 < time.time():
			self.roi_ctl.configure(state='disabled')
			self.r_ctl.configure(text="")
			self.color_ctl.configure(state='disabled')
		
	def from_vedio(self):
		if self.thread_run:
			return
		if self.camera is None:
			self.camera = cv2.VideoCapture(0)
			if not self.camera.isOpened():
				mBox.showwarning('警告', '摄像头打开失败!')
				self.camera = None
				return
		self.thread = threading.Thread(target=self.vedio_thread, args=(self,))
		self.thread.setDaemon(True)
		self.thread.start()
		self.thread_run = True
		
	def from_pic(self):
		self.thread_run = False
		self.pic_path = askopenfilename(title="选择识别图片", filetypes=[("jpg图片", "*.jpg")])
		if self.pic_path:
			img_bgr = predict.imreadex(self.pic_path)
			self.imgtk = self.get_imgtk(img_bgr)
			self.image_ctl.configure(image=self.imgtk)
			resize_rates = (1, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4)
			for resize_rate in resize_rates:
				print("resize_rate:", resize_rate)
				try:
					r, roi, color = self.predictor.predict(img_bgr, resize_rate)
				except:
					continue
				if r:
					break
			#r, roi, color = self.predictor.predict(img_bgr, 1)
			self.show_roi(r, roi, color)

	@staticmethod
	def vedio_thread(self):
		self.thread_run = True
		predict_time = time.time()
		while self.thread_run:
			_, img_bgr = self.camera.read()
			self.imgtk = self.get_imgtk(img_bgr)
			self.image_ctl.configure(image=self.imgtk)
			if time.time() - predict_time > 2:
				r, roi, color = self.predictor.predict(img_bgr)
				self.show_roi(r, roi, color)
				predict_time = time.time()
		print("run end")
		
		
def close_window():
	print("destroy")
	if surface.thread_run :
		surface.thread_run = False
		surface.thread.join(2.0)
	win.destroy()
	
	
if __name__ == '__main__':
	win=tk.Tk()
	
	surface = Surface(win)
	win.protocol('WM_DELETE_WINDOW', close_window)
	win.mainloop()
	

输出结果:

在这里插入图片描述

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

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

相关文章

VARIATIONAL IMAGE COMPRESSION WITH A SCALE HYPERPRIOR

文章目录 VARIATIONAL IMAGE COMPRESSION WITH A SCALE HYPERPRIORABSTRACT1 INTRODUCTION2 COMPRESSION WITH VARIATIONAL MODELS3 INTRODUCTION OF A SCALE HYPERPRIOR 个人总结动机流程思路 VARIATIONAL IMAGE COMPRESSION WITH A SCALE HYPERPRIOR ABSTRACT We describe …

【单片机】DS2431,STM32,EEPROM读取与写入

芯片介绍&#xff1a; https://qq742971636.blog.csdn.net/article/details/132164189 接线 串口结果&#xff1a; 部分代码&#xff1a; #include "sys.h" #include "DS2431.h"unsigned char serialNb[8]; unsigned char write_data[128]; unsigned cha…

服务器安装JDK

三种方法 方法一&#xff1a; 方法二&#xff1a; 首先登录到Oracle官网下载JDK JDK上传到服务器中&#xff0c;记住文件上传的位置是在哪里&#xff08;我放的位置在/www/java&#xff09;&#xff0c;然后看下面指示进行安装 方法三&#xff1a; 首先登录到Oracle官网下载…

线性回归学习总结

一 、引文 1 回归分析 回归是统计学上用来分析数据的方法&#xff0c;以了解两个或多个变量之前的关系。通常是建立被解释变量Y和解释变量X之间关系的模型。回归分析的最早形式是最小二乘法。 勒让德和高斯都将该方法应用于从天文观测中确定关于太阳的物体的轨道&#xff08;…

SpringBoot复习:(34)@EnableWebMvc注解为什么让@WebMvcAutoconfiguration失效?

它导入了DelegatingWebMvcConfiguration 它会把容器中的类型为WebMvcConfigurer的bean注入到类型为WebMvcConfigurerComposite的成员变量configurers中。 可以看到它继承了WebMvcConfigurerSupport类 而WebMvcConfigureAutoConfiguration类定义如下 可以看到一个Conditional…

LeetCode98. 验证二叉搜索树

98. 验证二叉搜索树 文章目录 [98. 验证二叉搜索树](https://leetcode.cn/problems/validate-binary-search-tree/)一、题目二、题解方法一&#xff1a;区间划分递归方法二&#xff1a;中序遍历递归迭代 一、题目 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有…

冒泡排序(超详细!)(C语言)

大家好&#xff01;欢迎来到Mr.kanglong的CSDN博文&#xff0c;今天来讨论一下冒泡排序&#xff0c;在百度百科中&#xff0c;关于为什么叫冒泡排序是这样解释的&#xff1a;因为越小的元素会经由交换慢慢“浮”到数列的顶端&#xff08;升序或降序排列&#xff09;&#xff0c…

移动云操作系统改造技术实践分享,跨操作系统云主机迁移优化(一)

近年来&#xff0c;Linux 操作系统在技术、社区和商业化方案均取得了快速发展&#xff0c;移动云先后发布了新一代天元操作系统和易行迁移工具&#xff0c;保障了移动云全场景业务高效迁移。在移动云 CentOS 迁移实践过程中&#xff0c;跨操作系统虚机迁移是改造中的一个重要环…

IP 协议的相关特性和数据链路层相关知识总结

目录 IP 协议的相关特性 一、IP协议的特性 二、 IP协议数据报格式 三、 IP协议的主要功能 1. 地址管理 动态分配 IP地址 NAT机制 NAT背景下的通信 IPV6 2. 路由控制​​​​​​​ 3.IP报文的分片与重组 数据链路层相关知识 1、以太网协议&#xff08;Ethernet&#xff09; 2.M…

“掌握类与对象,点亮编程之路“(下)

White graces&#xff1a;个人主页 &#x1f649;专栏推荐:《C语言入门知识》&#x1f649; &#x1f649; 内容推荐:“掌握类与对象&#xff0c;点亮编程之路“(上)&#x1f649; &#x1f439;今日诗词:春风得意马蹄疾&#xff0c;一日看尽长安花&#x1f439; 目录 &…

【十】PageHelper 插件源码分析

PageHelper 插件源码分析 简介&#xff1a; 在开发中经常使用到pagehelper分页插件&#xff0c;一直也只是使用没有深入去分析&#xff0c;今天花时间来研究一下pagehelper的实现原理的&#xff0c;阅读优秀的开源项目总是能有很多收获。 一、源码的获取 我们在git仓库中搜索可…

AI语音助理来了,我们还需要手机吗?

你是如何召唤苹果手机的语音助手Siri的&#xff1f; 已经12岁高龄的Siri&#xff0c;它主要提供了三个类型的“辅助功能”。 1、调动声音、闹钟、备忘录等系统基础应用的控制能力。比如&#xff1a;Hi Siri,明早两点我有个2亿美金的合同要签&#xff0c;记得提醒我。 2、调用第…

AT89C51单片机实现单片机串口互动(中断方式,单片机--单片机,应答)

说一下功能&#xff1a;客户机发送0x01到服务机 2服务单片机应答0xf2到客户机 3客户机接收到0xf2,发送信息153432这6个数字到服务机 4client发送完信息后发送0xaa结束通信 5server接收到0xaa后回复0xaa结束通信&#xff0c;从此老死不相往来 看代码&#xff1a; //发送端…

Arraylist集合

保存数据会经常使用到数组&#xff0c;但数组存在以下几个缺陷: 长度固定&#xff1b;保存的必须为同一类型的元素&#xff0c;&#xff08;基本数据类型&#xff0c;或引用数据类型&#xff09;&#xff1b;使用数组进行增加元素的步骤比较麻烦&#xff1b; 这个时候就需要用一…

24届近3年南京信息工程大学自动化考研院校分析

今天给大家带来的是南京信息工程大学控制考研分析 满满干货&#xff5e;还不快快点赞收藏 一、南京信息工程大学 学校简介 南京信息工程大学位于南京江北新区&#xff0c;是一所以大气科学为特色的全国重点大学&#xff0c;由江苏省人民政府、中华人民共和国教育部、中国气…

【AI理论学习】手把手利用PyTorch实现扩散模型DDPM

手把手利用PyTorch实现扩散模型DDPM DDPM代码实现神经网络定义辅助函数位置嵌入ResNet block注意力模块分组归一化Conditional U-Net 定义前向扩散过程定义PyTorch数据集DataLoader采样训练模型采样后续阅读 参考链接 上一篇博文已经手把手推导了扩散模型DDPM&#xff0c;本文利…

1. 消息队列

消息队列 1.1. MQ 的相关概念 1.1.1. 什么是 MQ MQ(message queue)&#xff0c;从字面意思上看&#xff0c;本质是个队列&#xff0c;FIFO 先入先出&#xff0c;只不过队列中存放的内容是message 而已&#xff0c;还是一种跨进程的通信机制&#xff0c;用于上下游传递消息。在…

性能测试—Jmeter工具

文章目录 性能测试1. 术语介绍2. 方法3. 应用场景4. 工具&#xff08;Jmeter&#xff09;4.1 介绍4.2 元件和组件4.2.2 元件4.2.1 组件 4.3 作用域4.4 参数化4.5 执行脚本 性能测试 1. 术语介绍 响应时间(Response time)&#xff1a;对请求作出响应所需要的时间。 在互联网上对…

Tik Tok娱乐+电商MCN怎么做?

在美国外的热门市场中&#xff0c;TikTok 主要做的区域市场包括中东、拉美、欧洲和东亚&#xff0c;而这里面适合做电商的其实并不多。 欧洲、东亚都属于成熟市场&#xff0c;且 TikTok 本身在欧洲面临 DSA 法案更严格的审查&#xff0c;与在英国相同&#xff0c;欧洲各市场消…

【二分+贪心】CF1622 C

Problem - 1622C - Codeforces 题意&#xff1a; 思路&#xff1a; 首先&#xff0c;观察样例可知&#xff0c;肯定是把原本的最小值减到某个值&#xff0c;然后再复制几次 复制的时候肯定是从大到小复制 那把最小值减到哪个值是不确定的&#xff0c;考虑枚举这个值&#x…