【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

运行结果:

相关推荐
FreakStudio4 小时前
硬件版【Cursor】?aily blockly IDE尝鲜封神,实战硬伤尽显
python·单片机·嵌入式·大学生·面向对象·并行计算·电子diy·电子计算机
郝学胜-神的一滴6 小时前
Qt 入门 01-01:从零基础到商业级客户端实战
开发语言·c++·qt·程序人生·软件构建
测试员周周6 小时前
【Appium 系列】第06节-页面对象实现 — LoginPage 实战
开发语言·前端·人工智能·python·功能测试·appium·测试用例
摇滚侠6 小时前
@Autowired 和 @Resource 的区别
java·开发语言
2301_783848656 小时前
优化文本分类中堆叠模型的网格搜索性能:避免训练卡顿的实战指南
jvm·数据库·python
Wy_编程6 小时前
go语言中的结构体
开发语言·后端·golang
SeaTunnel6 小时前
(八)收官篇 | 数据平台最后一公里:数据集成开发设计与上线治理实战
java·大数据·开发语言·白鲸开源
CLX05057 小时前
如何安装Oracle 12c Cloud Control_OMS服务端组件与Agent部署
jvm·数据库·python
大卡片7 小时前
C++的基础知识点
开发语言·c++
郑同学的笔记8 小时前
【Qt教程29】Qt5和Qt6版本对比
开发语言·qt