【PaddleOCR实战指南:图像文字识别、实时摄像头与PyQt5 GUI开发】
配置环境
在终端输入这些密令:
pip install paddlepaddle==2.6.2 pip install paddleocr==2.8.1PaddlePaddle/PaddleOCR有关代码参考链接:
https://gitee.com/paddlepaddle/PaddleOCR/tree/v2.6.0
paddleocr快速使用及参数详解参考如下文章:
https://blog.csdn.net/qq_41273999/article/details/135868038?ops_request_misc=%257B%2522request%255Fid%2522%253A%252299FC8A79-771C-4692-BE83-3F3E23AE64AB%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=99FC8A79-771C-4692-BE83-3F3E23AE64AB&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_click~default-1-135868038-null-null.142
一、使用PaddleOCR库实现了图像中的文字检测与识别功能,并在原图上可视化识别结果
1. 初始化OCR引擎
from paddleocr import PaddleOCR import cv2 import numpy as np ocr = PaddleOCR(use_angle_cls=True, use_gpu=False,show_log=False, lang='en')use_angle_cls=True:启用文本方向分类(检测倾斜文字)
use_gpu=False:使用CPU运算
show_log=False:关闭日志输出
lang='en':设置识别英文文本
2. 图像处理流程
frame=cv2.imread('img.png') result = ocr.ocr(frame)通过OpenCV读取img.png图像文件
调用OCR引擎进行文字检测与识别,返回包含文本位置和内容的结果
3. 结果可视化
if not None in result: for line in result[0]: # 转换为整数坐标 pts_int = np.array(line[0], dtype=np.int32) # 确保坐标数组的形状是 (n, 1, 2) 以符合 OpenCV 函数的要求 pts = pts_int.reshape((-1, 1, 2)) cv2.polylines(frame, [pts], True, (147, 20, 255),2) cv2.putText(frame, line[1][0], (pts_int[0][0], pts_int[0][1]-10),cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 3)遍历每个检测到的文本行:
line[0]:文本包围框的4个顶点坐标
line[1][0]:识别出的文本内容
使用红色($(R=0, G=0, B=255)$)绘制文本标签
使用品红色($(R=147, G=20, B=255)$)绘制多边形文本框
4. 结果展示
cv2.imshow('x', frame) cv2.waitKey(0)原图img.png
根据结果图看出,对于图片文字能进行基础的英文识别
改进代码:
from paddleocr import PaddleOCR import cv2 import numpy as np from PIL import Image, ImageDraw, ImageFont新增了 PIL 相关库 #新增了中文绘制函数 def cv2AddChineseText(img, text, position, textColor=(0, 255, 0), textSize=30): """ 向图片中添加中文 """ if (isinstance(img, np.ndarray)): # 判断是否OpenCV图片类型 img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))#实现array到image的转换 draw = ImageDraw.Draw(img) # 在img图片上创建一个绘图的对象 # 字体的格式 fontStyle = ImageFont.truetype( "simsun.ttc", textSize, encoding="utf-8") draw.text(position, text, textColor, font=fontStyle) # 绘制文本 return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)# 转换回OpenCV格式 #lang='en' → lang='ch'(从英文识别 → 改为中文识别) ocr = PaddleOCR(use_angle_cls=True,use_gpu=True,show_log=False,lang='ch') #'ch'就是识别中文 frame=cv2.imread('img.png') result = ocr.ocr(frame, cls=True) if not None in result: for line in result[0]: # 转换为整数坐标 pts_int = np.array(line[0], dtype=np.int32) # 确保坐标数组的形状是 (n, 1, 2) 以符合 OpenCV 函数的要求 pts = pts_int.reshape((-1, 1, 2)) zi=line[1][0] x,y=pts_int[0] cv2.polylines(frame, [pts], isClosed=True, color=(147, 20, 255), thickness=2) frame = cv2AddChineseText(frame, zi, (x,y-30)) cv2.imshow( 'x',frame) cv2.waitKey(0)运行结果:能识别出中文打印并且将中文框起来。
二、OCR摄像头:
from paddleocr import PaddleOCR import cv2 import numpy as np from PIL import Image, ImageDraw, ImageFont def cv2AddChineseText(img, text, position, textColor=(0, 255, 0), textSize=30): """ 向图片中添加中文 """ if (isinstance(img, np.ndarray)): # 判断是否OpenCV图片类型 img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))#实现array到image的转换 draw = ImageDraw.Draw(img) # 在img图片上创建一个绘图的对象 # 字体的格式 fontStyle = ImageFont.truetype( "simsun.ttc", textSize, encoding="utf-8") draw.text(position, text, textColor, font=fontStyle) # 绘制文本 return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)# 转换回OpenCV格式 ocr = PaddleOCR(use_angle_cls=True,use_gpu=True,show_log=False,lang='ch') #'ch'就是识别中文 cap=cv2.VideoCapture(0) while True: _,frame=cap.read() # frame=cv2.imread('img.png') result = ocr.ocr(frame, cls=True) if not None in result: for line in result[0]: # 转换为整数坐标 pts_int = np.array(line[0], dtype=np.int32) # 确保坐标数组的形状是 (n, 1, 2) 以符合 OpenCV 函数的要求 pts = pts_int.reshape((-1, 1, 2)) zi=line[1][0] x,y=pts_int[0] cv2.polylines(frame, [pts], isClosed=True, color=(147, 20, 255), thickness=2) frame = cv2AddChineseText(frame, zi, (x,y-30)) cv2.imshow( 'x',frame) if cv2.waitKey(1)==27: break结果:能用摄像头实时识别画面中的文字并将它们打印输出
三、PyQt5 前端和 PaddleOCR 实现的实时中文 OCR 识别软件:
代码:
导入库:
import sys import cv2 import numpy as np from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5.QtWidgets import QMainWindow, QApplication from paddleocr import PaddleOCR from PIL import Image, ImageDraw, ImageFont中文绘制函数:
def cv2AddChineseText(img, text, position, textColor=(0, 255, 0), textSize=30): if isinstance(img, np.ndarray): img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) draw = ImageDraw.Draw(img) try: fontStyle = ImageFont.truetype("simsun.ttc", textSize, encoding="utf-8") except: fontStyle = ImageFont.load_default() draw.text(position, text, textColor, font=fontStyle) return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)界面设计
# GUI前端页面设计 class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(900, 600) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") # 图像显示区域 self.label = QtWidgets.QLabel(self.centralwidget) self.label.setGeometry(QtCore.QRect(30, 30, 640, 480)) self.label.setText("") self.label.setScaledContents(True) # 文本结果显示区域 self.textEdit = QtWidgets.QTextEdit(self.centralwidget) self.textEdit.setGeometry(QtCore.QRect(690, 30, 180, 480)) self.textEdit.setReadOnly(True) # 打开/关闭按钮 self.pushButton = QtWidgets.QPushButton(self.centralwidget) self.pushButton.setGeometry(QtCore.QRect(400, 530, 100, 40)) self.pushButton.setText("打开") MainWindow.setCentralWidget(self.centralwidget) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "OCR实时识别"))主逻辑类
连接 GUI、摄像头、OCR 识别,实现实时处理
# 主逻辑入口:摄像头 + OCR + 界面刷新 class PyQtMainEntry(QMainWindow, Ui_MainWindow): def __init__(self): super().__init__() self.setupUi(self) # 打开摄像头 self.camera1 = cv2.VideoCapture(0, cv2.CAP_DSHOW) self.is_camera_opened = False # 加载PaddleOCR模型 self.ocr = PaddleOCR(lang='ch', use_textline_orientation=True, show_log=False) # 定时器:每30ms抓取一帧 self._timer = QtCore.QTimer(self) self._timer.timeout.connect(self._queryFrame) self._timer.setInterval(30) self.pushButton.clicked.connect(self.slot1) # 按钮开关控制 def slot1(self): self.is_camera_opened = not self.is_camera_opened if self.is_camera_opened: self.pushButton.setText("关闭") self._timer.start() else: self.pushButton.setText("打开") self._timer.stop() # ======================= # 核心:实时帧处理 + OCR识别 # ======================= def _queryFrame(self): ret1, frame = self.camera1.read() if not ret1: return frame = cv2.resize(frame, (640, 480)) # OCR识别 result = self.ocr.ocr(frame, cls=True) text_list = [] if result is not None and result[0] is not None: for line in result[0]: pts_int = np.array(line[0], dtype=np.int32) pts = pts_int.reshape((-1, 1, 2)) zi = line[1][0] text_list.append(zi) x, y = pts_int[0] # 绘制文字框 cv2.polylines(frame, [pts], isClosed=True, color=(147, 20, 255), thickness=2) # 绘制中文 frame = cv2AddChineseText(frame, zi, (x, y - 30)) # 右侧文本框显示结果 if text_list: self.textEdit.setText("\n".join(text_list)) # 图像转为Qt格式显示 rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, ch = rgb.shape bytes_per_line = ch * w qimage = QtGui.QImage(rgb.data, w, h, bytes_per_line, QtGui.QImage.Format_RGB888) self.label.setPixmap(QtGui.QPixmap.fromImage(qimage)) # 关闭窗口时释放资源 def closeEvent(self, event): if self.camera1.isOpened(): self.camera1.release() self._timer.stop() event.accept()主程序运行
# 主程序运行 if __name__ == "__main__": app = QApplication(sys.argv) window = PyQtMainEntry() window.show() sys.exit(app.exec_())运行结果:
四、正则判断:
从一串文本中筛选出符合规则的「有效编码」,比如产品编号、设备码、序列号等,自动过滤掉普通英文单词。
代码:
import re def process_string(input_string): aa = [] # 用空格切分字符串 parts = input_string.split() # 正则表达式1:包含数字和字母 pattern_alphanumeric = re.compile(r'(?=.*[a-zA-Z])(?=.*\d)[a-zA-Z\d-]{2,8}$') # 正则表达式2:至少四个以上数字的纯数字 pattern_at_least_two_digits = re.compile(r'\d{4,7}$') # 遍历每个切分后的部分 for part in parts: # 检查是否包含数字和字母或者纯数字 if pattern_alphanumeric.match(part) or pattern_at_least_two_digits.match(part): aa.append(part) return aa a = 'Aceite p04476' b = 'sdighsg' c = 's4967xl' d = 'v0-4985' e = 'shfsf v0-4985' f = '123' g = '1234568956' h = '45825' ylist = [] llist = [a, b, c, d, e, f, g, h] for i in llist: ma = process_string(i) ylist.extend(ma) print(ylist)核心过滤函数 process_string
功能:输入一句话 → 输出筛选后的有效编码列表
内部两条规则:
• 规则 1:字母 + 数字组合(2–8 位)
• 规则 2:纯数字(4–7 位)
满足任意一条就保留,否则丢弃。
运行结果:
C:\Users\Dell\AppData\Local\Programs\Python\Python39\python.exe D:\software\Pycharm\pyqt5库\2.正则判断.py ['p04476', 's4967xl', 'v0-4985', 'v0-4985', '45825']五、三进一:
这段代码实现了一个可复用的周期触发装饰器。它可以让任意函数每执行 N 次,就自动执行一次指定操作
1. 定义装饰器工具
import re # 定义一个“每调用n次就触发一次任务”的装饰器 def execute_after_n_calls(n, w2set): # 真正的装饰器 def decorator(func): # 包装函数:用来计数+执行 def wrapper(*args, **kwargs): wrapper.count += 1 # 每次调用都 +1 result = func(*args, **kwargs) # 执行原来的函数 if wrapper.count % n == 0: # 每满 n 次 w2set() # 自动执行传入的函数 return result wrapper.count = 0 # 初始化计数器 return wrapper return decorator2. 定义被触发的函数 bb ()
def bb(): print('b')3. 给 aa () 加上装饰器
@execute_after_n_calls(3, bb) def aa(): print('a')4. 测试调用 6 次
aa() aa() aa() aa() aa() aa()5.运行结果
a a a b a a a b六、threading 库
实现并发执行任务,让程序可以同时做多件事。
# 导入线程库 和 时间库 import threading import time # ====================== # 案例1:最简单的线程(无参数) # ====================== def worker(): print("线程开始执行") # 循环5次模拟工作 for i in range(5): print(f"线程正在工作:{i}") print("线程执行完毕") # 创建线程:target=要执行的函数名 thread = threading.Thread(target=worker) # 启动线程 thread.start() # 主线程不会等待子线程,会直接往下执行 print("****主线程继续执行*****") print("-"*50) # 分割线 # ====================== # 案例2:带参数的多线程(两个线程同时跑) # ====================== def worker(name): print(f"{name}线程开始执行") for i in range(5): print(f"{name}正在工作:{i}") time.sleep(0.5) # 暂停0.5秒,让切换效果更明显 print(f"{name}线程执行完毕") # 创建线程1,传入参数 args=("线程1",) thread1=threading.Thread(target=worker,args=("线程1",)) # 创建线程2 thread2=threading.Thread(target=worker,args=("线程2",)) # 启动两个线程 → 同时运行、交替打印 thread1.start() thread2.start() print("****主线程继续执行******") print("-"*50) # ====================== # 案例3:带延时的线程(演示并发等待) # ====================== def run(t): time.sleep(t) # 暂停 t 秒 print(f'我等了{t}秒') # 创建线程:3秒后输出 t1 = threading.Thread(target=run,args=(3,)) # 创建线程:6秒后输出 t2 = threading.Thread(target=run,args=(6,)) # 启动后两个线程同时计时,不是先后执行! t1.start() print('开始计时') t2.start()运行结果:
C:\Users\Dell\AppData\Local\Programs\Python\Python39\python.exe D:\software\Pycharm\pyqt5库\threading库.py 线程开始执行 线程正在工作:0****主线程继续执行***** -------------------------------------------------- 线程正在工作:1 线程正在工作:2 线程正在工作:3 线程正在工作:4 线程执行完毕 线程1线程开始执行 线程1正在工作:0 线程2线程开始执行****主线程继续执行****** 线程2正在工作:0 -------------------------------------------------- 开始计时 线程2正在工作:1 线程1正在工作:1 线程2正在工作:2线程1正在工作:2 线程1正在工作:3 线程2正在工作:3 线程2正在工作:4 线程1正在工作:4 线程2线程执行完毕 线程1线程执行完毕 我等了3秒 我等了6秒 进程已结束,退出代码0七、基于 OpenCV 的实时颜色识别系统,用于从摄像头画面中检测棕色牛皮纸箱。
代码
# 导入OpenCV库和数值计算库numpy import cv2 import numpy as np # 打开默认摄像头(0表示系统默认摄像头) cap = cv2.VideoCapture(0) # 持续循环读取摄像头画面 while True: try: # 读取一帧图像 # ret:是否读取成功 # frame3:读取到的画面 ret, frame3 = cap.read() # 将图像从BGR格式转换为HSV颜色空间 # HSV更适合做颜色识别 hsv_image = cv2.cvtColor(frame3, cv2.COLOR_BGR2HSV) # 定义棕色在HSV空间中的下限范围 lower_brown = np.array([10, 30, 30]) # 定义棕色在HSV空间中的上限范围 upper_brown = np.array([30, 255, 255]) # 根据颜色范围生成掩码 # 棕色区域变成白色(255),其他区域变成黑色(0) mask = cv2.inRange(hsv_image, lower_brown, upper_brown) # 显示掩码图像(黑白二值图) cv2.imshow('mask', mask) # 统计掩码中白色像素的数量(即棕色区域像素数) white_pixels = np.sum(mask == 255) # 计算整张图像的总像素数 total_pixels = mask.shape[0] * mask.shape[1] # 计算棕色区域占整个画面的百分比 color_percentage = (white_pixels / total_pixels) * 100 # 如果棕色区域占比 >= 20%,判定为牛皮纸箱 if color_percentage >= 20: print("检测到牛皮纸箱") # 显示原始摄像头画面 cv2.imshow('Filtered Image1', frame3) # 按下ESC键退出循环 if cv2.waitKey(1) == 27: break # 出现异常时跳过(防止画面卡顿/崩溃) except: pass运行结果:
