【PaddleOCR实战指南:图像文字识别、实时摄像头与PyQt5 GUI开发】

配置环境

在终端输入这些密令:

bash 复制代码
 pip install paddlepaddle==2.6.2
 pip install paddleocr==2.8.1

PaddlePaddle/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引擎
python 复制代码
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':设置识别英文文本

  1. 图像处理流程
python 复制代码
frame=cv2.imread('img.png')
result = ocr.ocr(frame)

通过OpenCV读取img.png图像文件

调用OCR引擎进行文字检测与识别,返回包含文本位置和内容的结果

  1. 结果可视化
python 复制代码
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))绘制多边形文本框

  1. 结果展示
python 复制代码
cv2.imshow('x', frame)
cv2.waitKey(0)

原图img.png

根据结果图看出,对于图片文字能进行基础的英文识别

改进代码:

python 复制代码
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摄像头:

python 复制代码
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 识别软件:

代码:

导入库:

python 复制代码
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

中文绘制函数:

python 复制代码
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)

界面设计

python 复制代码
# 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 识别,实现实时处理

python 复制代码
# 主逻辑入口:摄像头 + 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()

主程序运行

python 复制代码
# 主程序运行
if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = PyQtMainEntry()
    window.show()
    sys.exit(app.exec_())

运行结果:

四、正则判断:

从一串文本中筛选出符合规则的「有效编码」,比如产品编号、设备码、序列号等,自动过滤掉普通英文单词。

代码:

python 复制代码
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 位)

满足任意一条就保留,否则丢弃。

运行结果:

bash 复制代码
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. 定义装饰器工具
python 复制代码
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 decorator
  1. 定义被触发的函数 bb ()
python 复制代码
def bb():
    print('b')
  1. 给 aa () 加上装饰器
python 复制代码
@execute_after_n_calls(3, bb)
def aa():
    print('a')
  1. 测试调用 6 次
python 复制代码
aa()
aa()
aa()
aa()
aa()
aa()

5.运行结果

python 复制代码
a
a
a
b
a
a
a
b

六、threading 库

实现并发执行任务,让程序可以同时做多件事。

python 复制代码
# 导入线程库 和 时间库
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()

运行结果:

bash 复制代码
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 的实时颜色识别系统 ,用于从摄像头画面中检测棕色牛皮纸箱

代码

python 复制代码
# 导入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

运行结果:

相关推荐
m0_747854521 小时前
CSS如何让响应式图片在容器内居中_利用background-position
jvm·数据库·python
han_hanker1 小时前
下拉模糊搜索多选, 编辑,详情问题
开发语言·javascript·ecmascript
2401_871696522 小时前
CSS如何优化移动端CSS选择器性能_遵循BEM规范避免过长嵌套
jvm·数据库·python
invicinble2 小时前
java集合的设计思路
java·开发语言·python
源码之家2 小时前
计算机毕业设计:Python股票交易管理可视化系统 Django框架 requests爬虫 数据分析 可视化 大数据 大模型(建议收藏)✅
爬虫·python·深度学习·信息可视化·数据分析·django·课程设计
jiayong232 小时前
第 33 课:任务看板视图(按状态分列)与本地持久化
开发语言·前端·javascript·学习
SunnyDays10112 小时前
使用 Python 高效提取 Word 文档的特定页 (连续页、不连续页、按页拆分)
python·提取 word 文档页面·拆分 word 文档
2401_883600252 小时前
Cgo 回调中处理 const char- 参数的正确方法
jvm·数据库·python
A_aspectJ2 小时前
【Java基础开发】 基于Swing GUI 组件实现图书管理系统
java·开发语言