前言
OCR,即 Optical Character Recognition,是光学字符识别的简称。它是指电子设备(例如扫描仪或数码相机)检查纸上打印的字符,通过检测暗、亮的模式确定其形状,然后用字符识别方法将形状翻译成计算机文字的过程。简言之,OCR 技术可以将纸质文档中的文字转换成为黑白点阵的图像文件,并通过识别软件将图像中的文字转换成文本格式,供文字处理软件进一步编辑加工。
一、PaddleOCR简介
基于飞桨的OCR工具库,该项目名叫 PaddleOCR,是 Paddle 的一个分支;PaddleOCR 基于深度学习技术实现的, 所以使用时需要训练好的权重文件,但这个不需要我们担心,因为官方提供的有。包含总模型仅8.6M的超轻量级中文OCR,单模型支持中英文数字组合识别、竖排文本识别、长文本识别。同时支持多种文本检测、文本识别的训练算法。
二、环境搭建
1.安装pycharm
进入jetbrains官方网站,下载pycharm安装包,这里安装的是community社区版
https://www.jetbrains.com/pycharm/download/
安装的过程比较简单,网上的安装详细步骤有很多,这里不再赘述,基本上一路next即可,最后安装成功的效果如下图所示
2.安装QT designer,pyuic等工具包
在Python中使用PyQt这一工具包,它是Python编程语言和Qt库的成功融合。在pycharm IDE中,内置的UI界面设计工具QT designer和文件转换工具PYUIC(主要功能是将Qt Designer生成的.ui文件转换成相应的代码文件.py文件,十分高效!!),可以帮助用户更高效的基于python,开发相应的图形化界面。安装步骤网上也有很多,最终安装成功的效果如下图所示,即右击工程文件,在外部工具栏中可以看到已经安装好的插件
3.安装pyinstaller
pyinstaller是一个在python中用于将工程文件打包成软件的插件,打包后的软件可以复现出工程文件中实现的功能,具体安装步骤可以参考https://blog.youkuaiyun.com/qq_43703185/article/details/119342713来进行
三.代码实现
接下来进入正题,代码实现,主要分为以下几个部分
1.摄像头基本功能
这里调用的是笔记本自带的摄像头,实时拍摄画面,主要分为添加按钮,通过按钮打开摄像头,摄像头画面展示,展示图像实时更新四个部分,代码如下:
#摄像头传入图像实时更新
def updateFrame(self):
ret, frame = self.cap.read()
if ret:
self.show_cv_img(frame)
#开启摄像头按键功能设置
def video_button(self,status):
#self.flag = 0
if(status):
#if (self.flag == 0):
# self.cap_video = cv2.VideoCapture(0)
self.cap.open(0)
self.pushButton.setEnabled(True)
#self.flag += 1
ret, frame = self.cap.read()
if not ret:
self.cap.release()
else:
self.video.setText("Close")
self.timer.start(50)
else:
self.pushButton.setEnabled(False)
if self.cap.isOpened():
if self.timer.isActive():
self.timer.stop()
self.cap.release()
self.label.clear()
self.label.setText('<font color=red>摄像头未开启</font>')
self.video.setText('Open')
def show_cv_img(self,img):
shrink = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
QtImg = QtGui.QImage(shrink.data,
shrink.shape[1],
shrink.shape[0],
shrink.shape[1] * 3,
QtGui.QImage.Format_RGB888)
jpg_out = QtGui.QPixmap(QtImg).scaled(self.label.width(),self.label.height())
self.label.setPixmap(jpg_out)
2.导入PaddleOCR文字识别模型
这一步是整个过程的核心,调用现成的文字识别模型来对文字进行识别,这里调用的是百度的PaddleOCR模型。值得一提的是,本人在整个实践的过程中遇到过联网和离线两种状态的情况。如果是联网状态,可以先申请百度云文字识别ID和密钥,然后直接调用OCR模型即可;如果是离线状态,则可以在github上下载PaddleOCR接口文件,然后在工程中实现调用(下载链接:https://github.com/hiroi-sora/PaddleOCR-json/releases)。两种方法均可实现,代码如下:
联网方法:
#对图片文字进行提取
from aip import AipOcr #baidu-aip
config = {
'appId':'自己的ID',
'apiKey':'自己的key',
'secretKey':'自己的key'
}
client = AipOcr(**config) #创建客户类调用百度api接口
def get_file_content(file): #获取图像内容,传入参数为图片文件
with open(file,'rb') as f: #二进制形式打开文件
return f.read()
def img_to_str(image_path): #将图片里的文字识别出来,传入参数为图片路径
image = get_file_content(image_path)
result = client.basicAccurate(image) #调用百度云库以提取图像中的文字
#print(result)
if 'words_result' in result: #把图片里的文字提取出来放到一个字符串里
return '\n'.join([w['words'] for w in result['words_result']])
res = img_to_str(r'自己对应的图片路径') #写入图片路径,r为取消转义字符以用来表示文件路径
print(res)
#print(a) #此步为打印图片二进制数据
离线方法:
from PPOCR_api import GetOcrApi
import os
import PPOCR_api
from PyQt5.QtWidgets import *
from PyQt5 import QtCore,QtGui,QtWidgets
from PyQt5.QtWidgets import QMainWindow, QApplication
ocr = GetOcrApi(r"C:\Users\20605\Downloads\PaddleOCR-json_v.1.3.0\PaddleOCR-json.exe") #调用PaddleOCR接口,这里需要换成自己下载的路径
print(f'初始化OCR成功,进程号为{ocr.ret.pid}')
def img_to_str(image_path): #将图片里的文字识别出来,传入参数为图片路径
with open(image_path, 'rb') as f: # 获取图片字节流
imageBytes = f.read() # 实际使用中,可以联网下载或者截图获取字节流,直接送入OCR,无需保存到本地中转。
result = ocr.runBytes(imageBytes) #调用paddle-ocr库以识别提取文字
ocr.printResult(result)
#print(result)
if 'data' in result: # 把图片里的文字提取出来放到一个字符串里,注意参数‘data','text'是由result原始打印结果所填写
return '\n'.join([w['text'] for w in result['data']])
res = img_to_str(r'C:\Users\20605\Desktop\1.jpg') #写入图片路径,r为取消转义字符以用来表示文件路径
#print(res)
#print(a) #此步为打印图片二进制数据
3.采集图片
这一步是调用之前的功能函数,实现图片拍摄后的文字识别代码如下
def take_picture(self):
ret, frame = self.cap.read()
filename = 'log'
text_create(filename) #创建txt文本并命名
output = sys.stdout
outputfile = open("C:\\Users\\20605\\Desktop\\" + filename + '.txt', 'a') #以权限a的方式写入文件,不会覆盖掉之前的内容
sys.stdout = outputfile
if ret:
# filename = "frame.jpg" #调用百度云部分上位机打印文字代码
# cv2.imwrite(filename, frame)
# s = demo_recognition.img_to_str(filename)
# print(s)
# self.textBrowser.append(s)
cv2.imwrite(TestImagePath, frame)
s = demo_recognition.img_to_str(TestImagePath) #img_to_str函数通过return返回值赋值给s
self.textBrowser.append(s) #将识别出的文字输出到上位机上
print(file=outputfile) #将识别出的文字输出到txt中
outputfile.close() # close后才能看到写入的数据
四.将工程打包成可执行文件并测试
最后一步,将之前实现好的工程,调用pyinstaller工具库将其打包,打包的时间可能有点长,需要耐心等待一下,最终打包后的效果以及文字识别效果展示如图
可以看到,文字识别的效果还是挺不错,并且可以识别大部分字体。
总结
以上就是本篇博客的全部内容。当然,需要改进的地方还有很多。比如说文字识别后文字在介面框中的排版,需要做文字拼接等后处理工作;再比方说,如果摄像头帧率过高,图片在镜头前晃动过大,可能导致软件卡崩,这需要在软件打包以及算法优化上做处理。并且,这里只是调用现成的文字识别模型,工程总体来说难度不大,还是比较容易实现,后续对于OCR模型本身的研究才是重点。总的来说,第一次写博客,肯定有许多不足之处,希望各位大佬批评指正,多多交流。
附: 部分源代码,单独创建demo_recognition脚本并添加“导入PaddleOCR文字识别模型”部分代码即可
import base64
import requests
import os
from read_img import PPOCR_api
import sys
from read_img import read_image_ui
from PyQt5.QtWidgets import *
import cv2
from PyQt5 import QtCore,QtGui,QtWidgets
from PyQt5.QtWidgets import QMainWindow, QApplication
from read_img import demo_recognition
from read_img.output_txt import text_create
from read_img.PPOCR_api import GetOcrApi
# 测试图片路径
TestImagePath = f"{os.path.dirname(os.path.abspath(__file__))}\\test.jpg"
class test_ui(QMainWindow,read_image_ui.Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.timer = QtCore.QTimer()
self.cap = cv2.VideoCapture() #打开摄像头
self.timer.timeout.connect(self.updateFrame) #更新摄像头图片
self.video.clicked.connect(self.video_button) #初始化开启摄像头按键功能
self.video.setCheckable(True)
self.pushButton.clicked.connect(self.take_picture) #初始化拍照按键功能
self.cap_video = 0
self.count = 0 #计数标志位
self.img = []
#摄像头传入图像实时更新
def updateFrame(self):
ret, frame = self.cap.read()
if ret:
self.show_cv_img(frame)
#开启摄像头按键功能设置
def video_button(self,status):
#self.flag = 0
if(status):
#if (self.flag == 0):
# self.cap_video = cv2.VideoCapture(0)
self.cap.open(0)
self.pushButton.setEnabled(True)
#self.flag += 1
ret, frame = self.cap.read()
if not ret:
self.cap.release()
else:
self.video.setText("Close")
self.timer.start(50)
else:
self.pushButton.setEnabled(False)
if self.cap.isOpened():
if self.timer.isActive():
self.timer.stop()
self.cap.release()
self.label.clear()
self.label.setText('<font color=red>摄像头未开启</font>')
self.video.setText('Open')
#self.timer.stop()
#self.cap_video.release()
#self.label.clear()
#self.video.setText("Open")
# def show_video(self):
# ret, self.img = self.cap_video.read()
# if ret:
# self.show_cv_img(self.img)
def show_cv_img(self,img):
shrink = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
QtImg = QtGui.QImage(shrink.data,
shrink.shape[1],
shrink.shape[0],
shrink.shape[1] * 3,
QtGui.QImage.Format_RGB888)
jpg_out = QtGui.QPixmap(QtImg).scaled(self.label.width(),self.label.height())
self.label.setPixmap(jpg_out)
def take_picture(self):
ret, frame = self.cap.read()
filename = 'log'
text_create(filename) #创建txt文本并命名
output = sys.stdout
outputfile = open("C:\\Users\\20605\\Desktop\\" + filename + '.txt', 'a') #以权限a的方式写入文件,不会覆盖掉之前的内容
sys.stdout = outputfile
if ret:
# filename = "frame.jpg" #调用百度云部分上位机打印文字代码
# cv2.imwrite(filename, frame)
# s = demo_recognition.img_to_str(filename)
# print(s)
# self.textBrowser.append(s)
cv2.imwrite(TestImagePath, frame)
s = demo_recognition.img_to_str(TestImagePath) #img_to_str函数通过return返回值赋值给s
self.textBrowser.append(s) #将识别出的文字输出到上位机上
print(file=outputfile) #将识别出的文字输出到txt中
outputfile.close() # close后才能看到写入的数据
if __name__ == "__main__":
app = QApplication(sys.argv)
win = test_ui()
win.show()
sys.exit(app.exec_())
参考链接:
OCR介绍部分
https://blog.youkuaiyun.com/xhmico/article/details/137671583
https://blog.youkuaiyun.com/weixin_45897172/article/details/131406224
摄像头读图部分
https://www.bilibili.com/video/BV1Pa4y147LY/?spmidfrom=333.337.search-card.all.click&vd_source=c4f360981aa4bb15debb8ab108d9956d
paddleocr接口部分
https://github.com/hiroi-sora/Umi-OCR
PYQT5上位机部分
https://www.bilibili.com/video/BV1nu411b72B/?spmidfrom=333.788&vd_source=c4f360981aa4bb15debb8ab108d9956d