PaddleOCR #使用PaddleOCR进行光学字符识别 - OCR模型对比

PaddleOCR 在其工具包中提供了多种模型,并且非常易于应用。根据准确性和速度比较模型始终是一个好习惯。在本节中,我们将比较 PaddleOCR 提供的四种模型,即 SRN、PP-OCRv2、PP-OCRv3 和 NRTR。比较将在 COCO-text 数据集上进行,该数据集是基于MSCOCO 的场景文本数据集,使用 Google Colab 上的 Tesla K80 GPU。这些模型将使用称为 Levenshtein 距离的字符串相似性度量来测试。Levenshtein 距离是一种距离度量,通过比较一个字符串中实现另一个字符串所需的更改来计算。在开始比较之前,让我们先大致了解一下数据集。

 

一、OCR模型对比

1.1 数据准备

COCO-文本数据集 :COCO-text 数据集是 ICDAR2017 的一部分,是基于 MSCOCO 数据集的数据集,包含日常场景的复杂图像。该数据集包含超过 63,686 张图像中超过 173,589 个标记的文本区域。该数据集可用于文本检测和文本识别的训练和评估。

如前所述,该数据集包含超过 63,686 张图像,其中 10,000 张分配给验证集,10,000 张分配给测试集。COCO-text 提供了 3 种不同的挑战和数据类型。

  • 文本本地化
  • 裁剪词识别
  • 端到端识别

准备训练用的图像数据集。对于我们的任务,我们将下载裁剪词识别的数据集。实况标签包含在单个文本文件中,其中图像名称后跟新行中每个图像的标签。例如,
img1,label1
img2,label2
……

验证集包含大约 10,000 张图像,但我们将从该集中随机提取 500 张图像。通过在此处注册下载 数据集。如果从 Git 仓库获取的项目中已经包含或做好了随机图像数据集的抽取,则此步可跳过。本节我们所用到的图片皆来自于源码项目目录:Optical-Character-Recognition-using-PaddleOCR\COCO-text\COCO_test
ocr-03-01
 

1.2 脚本准备

有了训练数据集,我们将创建一个名为 display() 的辅助函数来显示图像及其标签。
脚本位置:.\PaddleOCR\applications\ocr_coco_disp.py

# Importing required libraries.
import os
import sys
import matplotlib.pyplot as plt
import matplotlib.image as img# Function to display images along with labels.
# 显示图像和标签的功能。
def disp(pth, gt_annot = '', gt = False, out = False, num = 10):# 用于存储图像数组的列表img_arr = []# 用于存储注释的列表annot_arr = []# Appending image array into a list.# 将图像数组添加到列表中for fimg in sorted((os.listdir(pth))):# 如果是jpg 或 png 图像文件if fimg.endswith('.jpg') or fimg.endswith('.png'):# 读取图像demo = img.imread(pth+fimg) img_arr.append(demo)# Appending dataset output into a list (OCR outputs are stored in different text files for every image).# 将数据集输出附加到列表中(OCR 输出存储在每个图像的不同文本文件中)if out:with open(pth + ''.join(fimg.split())[:-8]+ '.txt') as f:# 读取 OCR 输出out = f.read()f.close()annot_arr.append(out.lower())# Appending ground truth annotations into a list (Ground truth of all images are stored in a single text file).# 将真实标签添加到列表中(所有图像的真实标签存储在单个文本文件中)if gt:with open(gt_annot) as f:for line in f:if line.split(',')[0] == fimg.split('.')[0]: # 读取真实标签gt = line.split(',')[1].lower()annot_arr.append(gt)breakif len(img_arr) == num:break# Displaying the images along with labels.# 显示图像及其标签_, axs = plt.subplots(2, 5, figsize=(25, 14))axs = axs.flatten()for cent, ax,val  in zip(img_arr, axs, annot_arr):ax.imshow(cent)ax.set_title(val,fontsize=25)plt.show()

调用 disp() 函数来显示测试图片和正确值:

# 调用 disp() 函数来显示测试图片和正确值
input_org = '../COCO-text/COCO_test/'
annot = '../COCO-text/gt-test.txt'
disp(input_org, annot, gt = True, num = 10)

执行脚本,可以看到我们已经将抽样的原始图像和其原本的标签(值)做了一对一显示:
ocr-03-03
准备模型训练结果输出。PP-OCR 是一系列高质量的预训练 OCR 模型,提供端到端的文本识别管道。为了比较,我们将比较 PP-OCRv3 和 PP-OCRv2 这两个超轻量级模型,支持英文和中文。

注:
(1) 如果本地之前还未安装依赖项和库,现在可 CMD 执行如下命令,进行依赖项和库安装。

pip install -r requirements.txt

(2) 如果代码提示 Levenshtein 包找不到,需要先用 CMD 手动下载一下包:

pip install python-Levenshtein

ocr-03-04

 

1.3 开始训练

1)PP-OCRv3

PaddleOCR 最近推出了其旗舰 PP-OCR 的新版本,即第 3 版。PP-OCRv3 声称比其先前版本的英语 PP-OCRv2 准确 11%。这是一个超轻量级的模型,大小接近 17Mb。使用浏览器打开下面地址即可下载:

https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_rec_infer.tar

下载后,将文件解压到目标:.\PaddleOCR\inference\ch_PP-OCRv3_rec_infer
注:文件夹 \inference 的名称无要求,可自定义,如果没有可自行创建。

是时候在 COCO 文本数据集上测试旗舰 PP-OCR 了。
完整案例脚本位置:.\PaddleOCR\applications\pp_ocr_v3.py

# Importing required libraries.
import os
import numpy as np
import sysimport matplotlib.pyplot as plt
import time# 将当前脚本文件所在的目录路径添加到Python的模块搜索路径中,以便能够导入同一目录下的其他模块。
# # 获取当前脚本文件的所在目录路径,并将其赋值给变量 __dir__。
# __dir__ = os.path.dirname(__file__)
# # 将当前脚本文件所在的目录路径添加到Python的模块搜索路径中。os.path.join(__dir__, '') 用于获取完整的目录路径。
# sys.path.append(os.path.join(__dir__, ''))# 获取当前脚本文件的绝对路径所在的目录路径,并将其赋值给变量 __dir__。
__dir__ = os.path.dirname(os.path.abspath(__file__))
# 将当前脚本文件的绝对路径所在的目录路径添加到Python的模块搜索路径中。
sys.path.append(__dir__)
# 将当前脚本文件的上一级目录路径添加到Python的模块搜索路径中。os.path.join(__dir__, '..') 用于获取上一级目录的路径,os.path.abspath() 用于获取绝对路径。
sys.path.insert(0, os.path.abspath(os.path.join(__dir__, '..')))import importlib
tools = importlib.import_module('.', 'tools')
ppocr = importlib.import_module('.', 'ppocr')import tools.infer.utility as utility
from tools.infer.predict_rec import *from ppocr.utils.utility import check_and_read_gif, get_image_file_list
from ppocr.utils.logging import get_logger
logger = get_logger()from ppocr.postprocess import build_post_process# 通过获取多个参数并输出 OCR 结果
def rec(args, out_path, input, rec_model_dir, rec_image_shape="3, 32, 320", rec_char_type="ch", rec_algorithm="CRNN", show=True, save=True):# 为args赋值,因为代码不是从控制台运行的args.rec_model_dir = rec_model_dirargs.rec_image_shape = rec_image_shapeargs.rec_char_type = rec_char_typeargs.rec_algorithm = rec_algorithm# 初始化一些辅助变量t1 = 0t2 = 0tot = []os.chdir('../PaddleOCR')# 将所需的值传递给args变量if rec_algorithm == "SRN":print('yes')args.rec_char_dict_path = './ppocr/utils/ic15_dict.txt'args.use_space_char = Falseif rec_algorithm == 'NRTR':args.rec_char_dict_path = './ppocr/utils/EN_symbol_dict.txt'args.rec_image_shape = "1,32,100"# 初始化识别器image_file_list = get_image_file_list(input)text_recognizer = TextRecognizer(args)valid_image_file_list = []img_list = []# 预热GPU,以充分发挥其性能if args.warmup:image = np.random.uniform(0, 255, [32, 320, 3]).astype(np.uint8)for i in range(10):res = text_recognizer([image])# 读取并将所有图像的数组添加到列表中for image_file in image_file_list:image, flag = check_and_read_gif(image_file)if not flag:image = cv2.imread(image_file)if image is None:logger.info("error in loading image:{}".format(image_file))continuevalid_image_file_list.append(image_file)img_list.append(image)# 对图像应用OCRt1 = time.time()try:rec_res, _ = text_recognizer(img_list)except Exception as E:logger.info(traceback.format_exc())logger.info(E)exit()# 计算FPS并打印信息t2 = time.time()fps = str(t2 - t1)for ino in range(len(img_list)):logger.info("Predicts of {}:{}".format(valid_image_file_list[ino], rec_res[ino]))if save:cv2.imwrite(os.path.join(out_path, valid_image_file_list[ino].split('/')[-1].split('.')[0] + '_rec' + '.jpg'), img_list[ino])with open(os.path.join(out_path, valid_image_file_list[ino].split('/')[-1].split('.')[0] + '.txt'), 'w') as f:f.write(str(rec_res[ino]))logger.info("Time taken recognize all images : {}".format(fps))print(len(image_file_list))logger.info("Average fps : {}".format(1 / (float(fps) / len(image_file_list))))# 显示和保存输出,根据设置的参数if show:plt.figure(figsize=(25, 14))plt.imshow(image)plt.show()# 计算与输出和真实文本的编辑距离的度量
def score_calc(pth, annot):# 导入距离度量方法from Levenshtein import distancescore_all = []# 循环遍历输出文本文件,并将OCR输出存储在变量中for out_file in os.listdir(pth):if out_file.endswith('.txt'):with open(os.path.join(pth, out_file), 'rb') as f:out = f.read()f.close()# 清理OCR输出文本try:out = str(out).split(',')[1].split(',')[0].replace("'", '').lower()except:print('OCR output does not exist')# 打开真实标签文件并计算真实标签与OCR输出之间的距离with open(annot) as f:for line in f:if line.split(',')[0] == out_file.split('.')[0]:gt = line.split(',')[1].lower()score = distance(str(out), str(gt))/len(gt)score_all.append(score)break# 打印平均得分print("final score:", sum(score_all)/len(score_all))# --- 实验测试 -------------------------------------------------------------------------------------------
input_org = '../COCO-text/COCO_test'
out_path = './inference_results/result_ppocrv3/'
rec_model_dir = './inference/ch_PP-OCRv3_rec_infer'
sys.argv = ['']start_time = time.time()
logger.info('开始 ...')
rec(utility.parse_args(), out_path, input_org, rec_model_dir, show = False)
end_time = time.time()execution_time = end_time - start_time
logger.info('结束,[PP-OCRv3] 实验 500 张图像耗时 %s 秒', execution_time)from ocr_coco_disp import disp# 调用 disp() 函数来显示测试图片和正确值
# pth_org = '../COCO-text/COCO_test/'
annot = '../COCO-text/gt-test.txt'
# disp(input_org, annot, gt = True, num = 10)# 调用 disp() 函数来显示测试图片和检测识别值
pth_rst = '../PaddleOCR/inference_results/result_ppocrv3/COCO_test/'
disp(pth_rst, out = True, num = 10) # 显示得分
score_calc(pth_rst, annot)

脚本中有2个函数:
(1) 一个 rec() 函数,该函数将负责通过获取多个参数并输出 OCR 结果。
(2) 一个 score_calc() 函数,计算与输出和真实文本的编辑距离的度量,也叫置信度。

开始实验测试吧。执行上述脚本。
速度非常惊人。该管道以 15.41 的 FPS 运行,并在将近 32.44 秒钟内识别出所有 500 张图像。输出图像和预测保存在 out_path 下指定的路径中。它将在文本文件中包含输出图像及其相应的预测。
ocr-03-05

[2023/06/09 16:10:13] ppocr INFO: Predicts of ../COCO-text/COCO_test\1239241.jpg:('Crieket', 0.8044114112854004)
[2023/06/09 16:10:13] ppocr INFO: Predicts of ../COCO-text/COCO_test\1239554.jpg:('', 0.0)
[2023/06/09 16:10:13] ppocr INFO: Predicts of ../COCO-text/COCO_test\1239559.jpg:('', 0.0)
[2023/06/09 16:10:13] ppocr INFO: Predicts of ../COCO-text/COCO_test\1239825.jpg:('', 0.0)
[2023/06/09 16:10:13] ppocr INFO: Predicts of ../COCO-text/COCO_test\1240486.jpg:('koppdelney', 0.70953768491745)
[2023/06/09 16:10:13] ppocr INFO: Predicts of ../COCO-text/COCO_test\1240603.jpg:('MICEVERSA', 0.521608829498291)
[2023/06/09 16:10:13] ppocr INFO: Time taken recognize all images : 32.43732690811157
500
[2023/06/09 16:10:13] ppocr INFO: Average fps : 15.41434044230585

ocr-03-06
准确性与速度同样重要。让我们看看模型在准确性方面的表现。
ocr-03-07
从上面的代码片段中,我们可以得到指标来判断我们的 PP-OCRv3 在 COCO-text 数据集上的表现。PP-OCRv3 的表现非常惊人,得分为 2.39,而且速度也非常快。在以下部分中,我们将了解其他模型的表现。

 

2)PP-OCRv2

PP-OCRv2 也是一个非常准确的模型,但理论上不如最新的版本3。我们来验证一下,在下面的代码片段中,我们将计算 PP-OCRv2 的分数并查看它的表现。
浏览器打开 URL 下载模型:

https://paddleocr.bj.bcebos.com/dygraph_v2.1/chinese/ch_PP-OCRv2_rec_infer.tar

解压后位置:.\PaddleOCR\inference\ch_PP-OCRv2_rec_infer

脚本内容与基本类似,但有个地方需要注意,如果出现异常:
UnicodeEncodeError: ‘gbk’ codec can’t encode character ‘\xae’ in position 2: illegal multibyte sequence
侧需要对 open() 函数加个入参:encoding=‘utf-8’

本地脚本位置:.\PaddleOCR\applications\pp_ocr_v3.py。完整代码如下:

import os
import numpy as np
import sys
import matplotlib.pyplot as plt
import time# 将当前脚本文件所在的目录路径添加到Python的模块搜索路径中,以便能够导入同一目录下的其他模块。
# # 获取当前脚本文件的所在目录路径,并将其赋值给变量 __dir__。
# __dir__ = os.path.dirname(__file__)
# # 将当前脚本文件所在的目录路径添加到Python的模块搜索路径中。os.path.join(__dir__, '') 用于获取完整的目录路径。
# sys.path.append(os.path.join(__dir__, ''))# 获取当前脚本文件的绝对路径所在的目录路径,并将其赋值给变量 __dir__。
__dir__ = os.path.dirname(os.path.abspath(__file__))
# 将当前脚本文件的绝对路径所在的目录路径添加到Python的模块搜索路径中。
sys.path.append(__dir__)
# 将当前脚本文件的上一级目录路径添加到Python的模块搜索路径中。os.path.join(__dir__, '..') 用于获取上一级目录的路径,os.path.abspath() 用于获取绝对路径。
sys.path.insert(0, os.path.abspath(os.path.join(__dir__, '..')))import importlib
tools = importlib.import_module('.', 'tools')
ppocr = importlib.import_module('.', 'ppocr')import tools.infer.utility as utility
from tools.infer.predict_rec import *from ppocr.utils.utility import check_and_read_gif, get_image_file_list
from ppocr.utils.logging import get_logger
logger = get_logger()from ppocr.postprocess import build_post_process# 通过获取多个参数并输出 OCR 结果
def rec(args, out_path, input, rec_model_dir, rec_image_shape="3, 32, 320", rec_char_type="ch", rec_algorithm="CRNN", show=True, save=True):# 为args赋值,因为代码不是从控制台运行的args.rec_model_dir = rec_model_dirargs.rec_image_shape = rec_image_shapeargs.rec_char_type = rec_char_typeargs.rec_algorithm = rec_algorithm# 初始化一些辅助变量t1 = 0t2 = 0tot = []os.chdir('../PaddleOCR')# 将所需的值传递给args变量if rec_algorithm == "SRN":print('yes')args.rec_char_dict_path = './ppocr/utils/ic15_dict.txt'args.use_space_char = Falseif rec_algorithm == 'NRTR':args.rec_char_dict_path = './ppocr/utils/EN_symbol_dict.txt'args.rec_image_shape = "1,32,100"# 初始化识别器image_file_list = get_image_file_list(input)text_recognizer = TextRecognizer(args)valid_image_file_list = []img_list = []# 预热GPU,以充分发挥其性能if args.warmup:image = np.random.uniform(0, 255, [32, 320, 3]).astype(np.uint8)for i in range(10):res = text_recognizer([image])# 读取并将所有图像的数组添加到列表中for image_file in image_file_list:image, flag = check_and_read_gif(image_file)if not flag:image = cv2.imread(image_file)if image is None:logger.info("error in loading image:{}".format(image_file))continuevalid_image_file_list.append(image_file)img_list.append(image)# 对图像应用OCRt1 = time.time()try:rec_res, _ = text_recognizer(img_list)except Exception as E:logger.info(traceback.format_exc())logger.info(E)exit()# 计算FPS并打印信息t2 = time.time()fps = str(t2 - t1)for ino in range(len(img_list)):logger.info("Predicts of {}:{}".format(valid_image_file_list[ino], rec_res[ino]))if save:cv2.imwrite(os.path.join(out_path, valid_image_file_list[ino].split('/')[-1].split('.')[0] + '_rec' + '.jpg'), img_list[ino])with open(os.path.join(out_path, valid_image_file_list[ino].split('/')[-1].split('.')[0] + '.txt'), 'w', encoding='utf-8') as f:f.write(str(rec_res[ino]))logger.info("Time taken recognize all images : {}".format(fps))print(len(image_file_list))logger.info("Average fps : {}".format(1 / (float(fps) / len(image_file_list))))# 显示和保存输出,根据设置的参数if show:plt.figure(figsize=(25, 14))plt.imshow(image)plt.show()# 计算与输出和真实文本的编辑距离的度量
def score_calc(pth, annot):# 导入距离度量方法from Levenshtein import distancescore_all = []# 循环遍历输出文本文件,并将OCR输出存储在变量中for out_file in os.listdir(pth):if out_file.endswith('.txt'):with open(os.path.join(pth, out_file), 'rb') as f:out = f.read()f.close()# 清理OCR输出文本try:out = str(out).split(',')[1].split(',')[0].replace("'", '').lower()except:print('OCR output does not exist')# 打开真实标签文件并计算真实标签与OCR输出之间的距离with open(annot) as f:for line in f:if line.split(',')[0] == out_file.split('.')[0]:gt = line.split(',')[1].lower()score = distance(str(out), str(gt))/len(gt)score_all.append(score)break# 打印平均得分print("final score:", sum(score_all)/len(score_all))# --- 实验测试 -------------------------------------------------------------------------------------------
input_org = '../COCO-text/COCO_test'
out_path = './inference_results/result_ppocrv2/'
rec_model_dir = './inference/ch_PP-OCRv2_rec_infer'
sys.argv = ['']start_time = time.time()
logger.info('开始 ...')
rec(utility.parse_args(), out_path, input_org, rec_model_dir, show = False)
end_time = time.time()execution_time = end_time - start_time
logger.info('结束,[PP-OCRv3] 实验 500 张图像耗时 %s 秒', execution_time)from ocr_coco_disp import disp# 调用 disp() 函数来显示测试图片和正确值
# pth_org = '../COCO-text/COCO_test/'
annot = '../COCO-text/gt-test.txt'
# disp(input_org, annot, gt = True, num = 10)# 调用 disp() 函数来显示测试图片和检测识别值
pth_rst = '../PaddleOCR/inference_results/result_ppocrv2/COCO_test/'
disp(pth_rst, out = True, num = 10) # 显示得分
score_calc(pth_rst, annot)

ocr-03-08

[2023/06/12 15:00:43] ppocr INFO: Time taken recognize all images : 35.80784869194031
500
[2023/06/12 15:00:43] ppocr INFO: Average fps : 13.963419145941065
final score: 3.1595520470270504

哇!!整个数据集在 35.8 秒内处理完毕,平均 FPS 为 13.96。
我们得到了指标,上面的代码片段输出了 3.16 的置信度分数,这意味着 500 张图像的平均 Levenshtein 距离为 3.16。两相对比,PP-OCRv2 在速度和准确性方面稍逊于 PP-OCRv3。

 

3)SRN

SRN 是 PaddleOCR 支持的另一种模型。它代表语义推理网络,它克服了类似 RNN 结构的缺点。SRN 是一个非常庞大的模型,大小超过 900 MB。SRN 声称非常准确,但以速度为代价。让我们在数据集上对其进行测试,看看它的表现如何。
先下载模型:

https://paddleocr.bj.bcebos.com/dygraph_v2.0/en/rec_r50_vd_srn_train.tar

解压后位置:.\PaddleOCR\inference\rec_r50_vd_srn_train

使用 CMD 执行如下命令,将保存的模型转换为推理模型:

python tools/export_model.py -c configs/rec/rec_r50_fpn_srn.yml -o Global.pretrained_model=./inference/rec_r50_vd_srn_train/best_accuracy  Global.save_inference_dir=./inference/rec_r50_vd_srn_train

这一步是将保存的模型转换为推理模型"Converting saved model to inference model" )。

在机器学习和深度学习中,训练模型和推理模型是不同的。训练模型是在训练阶段使用训练数据进行模型的训练和参数优化,以便模型能够学习并适应数据的模式和特征。而推理模型则是在训练完成后,用于对新的输入数据进行预测或推理的模型。

当你训练完成一个模型后,通常会将其保存为一个文件或目录,包含了模型的参数、权重以及其他必要的信息。这个保存的模型可以被加载到程序中,用于进行预测任务。

“Converting saved model to inference model” 的过程就是将保存的训练模型进行一些处理或转换,以便它可以被用于推理任务。这可能涉及到模型的格式转换、优化、裁剪或其他必要的操作,以确保模型在推理阶段具有更高的效率和性能。
ocr-03-09
这样,我们就得到了一个从训练模型 rec_r50_vd_srn_train 转换过来的 推理模型(运行成功后,存放训练模型的目录会多三个推理模型文件):
ocr-03-10
SRN 在不同的图像尺寸上进行训练,因此,输入图像需要调整到该尺寸,即“1, 64, 256”。因此,我们需要传递一些参数来获得 SRN 所需的功能。

  • rec_image_shape = ‘1, 64, 256’
  • rec_char_type = ‘en’,
  • rec_algorithm = ‘SRN’

这里可以使用 PP-OCRv3的脚本,只是我将输出目录做了调整。
脚本位置:\PaddleOCR\applications\pp_ocr_srn.py,完整脚本如下:

# Importing required libraries.
import os
import numpy as np
import sys
import matplotlib.pyplot as plt
import time# 将当前脚本文件所在的目录路径添加到Python的模块搜索路径中,以便能够导入同一目录下的其他模块。
# # 获取当前脚本文件的所在目录路径,并将其赋值给变量 __dir__。
# __dir__ = os.path.dirname(__file__)
# # 将当前脚本文件所在的目录路径添加到Python的模块搜索路径中。os.path.join(__dir__, '') 用于获取完整的目录路径。
# sys.path.append(os.path.join(__dir__, ''))# 获取当前脚本文件的绝对路径所在的目录路径,并将其赋值给变量 __dir__。
__dir__ = os.path.dirname(os.path.abspath(__file__))
# 将当前脚本文件的绝对路径所在的目录路径添加到Python的模块搜索路径中。
sys.path.append(__dir__)
# 将当前脚本文件的上一级目录路径添加到Python的模块搜索路径中。os.path.join(__dir__, '..') 用于获取上一级目录的路径,os.path.abspath() 用于获取绝对路径。
sys.path.insert(0, os.path.abspath(os.path.join(__dir__, '..')))import importlib
tools = importlib.import_module('.', 'tools')
ppocr = importlib.import_module('.', 'ppocr')import tools.infer.utility as utility
from tools.infer.predict_rec import *from ppocr.utils.utility import check_and_read_gif, get_image_file_list
from ppocr.utils.logging import get_logger
logger = get_logger()from ppocr.postprocess import build_post_process
# from ppocr.utils.logging import get_logger
# from PaddleOCR.ppocr.utils.utility import get_image_file_list, check_and_read_gifdef rec(args, out_path, input, rec_model_dir, rec_image_shape="3, 32, 320", rec_char_type="ch", rec_algorithm="CRNN", show=True, save=True):# 为args赋值,因为代码不是从控制台运行的args.rec_model_dir = rec_model_dirargs.rec_image_shape = rec_image_shapeargs.rec_char_type = rec_char_typeargs.rec_algorithm = rec_algorithm# 初始化一些辅助变量t1 = 0t2 = 0tot = []os.chdir('../PaddleOCR')# 将所需的值传递给args变量if rec_algorithm == "SRN":print('yes')args.rec_char_dict_path = './ppocr/utils/ic15_dict.txt'args.use_space_char = Falseif rec_algorithm == 'NRTR':args.rec_char_dict_path = './ppocr/utils/EN_symbol_dict.txt'args.rec_image_shape = "1,32,100"# 初始化识别器image_file_list = get_image_file_list(input)text_recognizer = TextRecognizer(args)valid_image_file_list = []img_list = []# 预热GPU,以充分发挥其性能if args.warmup:image = np.random.uniform(0, 255, [32, 320, 3]).astype(np.uint8)for i in range(10):res = text_recognizer([image])# 读取并将所有图像的数组添加到列表中for image_file in image_file_list:image, flag = check_and_read_gif(image_file)if not flag:image = cv2.imread(image_file)if image is None:logger.info("error in loading image:{}".format(image_file))continuevalid_image_file_list.append(image_file)img_list.append(image)# 对图像应用OCRt1 = time.time()try:rec_res, _ = text_recognizer(img_list)except Exception as E:logger.info(traceback.format_exc())logger.info(E)exit()# 计算FPS并打印信息t2 = time.time()fps = str(t2 - t1)for ino in range(len(img_list)):logger.info("Predicts of {}:{}".format(valid_image_file_list[ino], rec_res[ino]))if save:cv2.imwrite(os.path.join(out_path, valid_image_file_list[ino].split('/')[-1].split('.')[0] + '_rec' + '.jpg'), img_list[ino])with open(os.path.join(out_path, valid_image_file_list[ino].split('/')[-1].split('.')[0] + '.txt'), 'w') as f:f.write(str(rec_res[ino]))logger.info("Time taken recognize all images : {}".format(fps))print(len(image_file_list))logger.info("Average fps : {}".format(1 / (float(fps) / len(image_file_list))))# 显示和保存输出,根据设置的参数if show:plt.figure(figsize=(25, 14))plt.imshow(image)plt.show()def score_calc(pth, annot):# 导入距离度量方法from Levenshtein import distancescore_all = []# 循环遍历输出文本文件,并将OCR输出存储在变量中for out_file in os.listdir(pth):if out_file.endswith('.txt'):with open(os.path.join(pth, out_file), 'rb') as f:out = f.read()f.close()# 清理OCR输出文本try:out = str(out).split(',')[1].split(',')[0].replace("'", '').lower()except:print('OCR output does not exist')# 打开真实标签文件并计算真实标签与OCR输出之间的距离with open(annot) as f:for line in f:if line.split(',')[0] == out_file.split('.')[0]:gt = line.split(',')[1].lower()score = distance(str(out), str(gt))/len(gt)score_all.append(score)break# 打印平均得分print("final score:", sum(score_all)/len(score_all))# --- 实验测试 -------------------------------------------------------------------------------------------
input_org = '../COCO-text/COCO_test'
out_path = './inference_results/result_srn/'
rec_model_dir = './inference/rec_r50_vd_srn_train'
sys.argv = ['']start_time = time.time()
logger.info('开始 ...')
rec(utility.parse_args(), out_path, input_org, rec_model_dir, rec_image_shape = '1, 64, 256', rec_char_type = 'en', rec_algorithm = 'SRN', show = False)end_time = time.time()execution_time = end_time - start_time
logger.info('结束,[PP-OCRv3] 实验 500 张图像耗时 %s 秒', execution_time)from ocr_coco_disp import disp# 调用 disp() 函数来显示测试图片和正确值
# pth_org = '../COCO-text/COCO_test/'
annot = '../COCO-text/gt-test.txt'
# disp(input_org, annot, gt = True, num = 10)# 调用 disp() 函数来显示测试图片和检测识别值
pth_rst = '../PaddleOCR/inference_results/result_srn/COCO_test/'
disp(pth_rst, out = True, num = 10) # 显示得分
score_calc(pth_rst, annot)

执行脚本,跑起来了,但运行速度有点慢,整个检测过程耗时137.35 秒,大约 3.64 FPS。
ocr-03-11
ocr-03-12
置信度分数得分为 3.05,与之前看到的 PP-OCRv2 非常接近。因此,PP-OCRv3 仍然是测试算法中最好的。

 

4)NRTR

NRTR 是 PaddleOCR 支持的最准确的模型之一。NRTR 代表无重复序列到序列文本识别器。根据其论文,NRTR 遵循编码器-解码器方法,其中编码器使用堆叠式自注意力来提取图像特征,解码器使用堆叠式自注意力来识别基于编码器输出的文本。是时候看看它的实际应用了。
下载模型,大小 372M 左右:

https://paddleocr.bj.bcebos.com/dygraph_v2.0/en/rec_mtb_nrtr_train.tar

解压后目录:.\PaddleOCR\inference\rec_mtb_nrtr_train
使用 CMD 执行如下命令,将保存的模型转换为推理模型:

python tools/export_model.py -c configs/rec/rec_mtb_nrtr.yml -o Global.pretrained_model=./inference/rec_mtb_nrtr_train/best_accuracy Global.save_inference_dir=./inference/rec_mtb_nrtr_train

但是遗憾的是,这个算法未能成功转换成推理模型。这个问题可能是由于 PaddlePaddle 版本不兼容或代码中的某些错误导致的。尝试后目前未能成功解决。

按官方的分析,NRTR 的距离度量(置信度得分)可与 PP-OCRv3 相媲美,但速度也是所有速度中最低的。这种准确性是以速度为代价实现的,这是不值得的,因为我们有 PP-OCRv3,它可以更好地工作并且速度更快。

 

二、结果分析

从上面的实验我们可以得出结论,PP-OCR 在速度和准确性方面都是一种非常强大的算法。PP-OCRv3 在所有实施的算法中表现最好,在速度和准确性方面都表现出色。作为轻量级模型,PP-OCRv2 和 v3 的性能与最新的大型模型(如 SRN 和 NRTR)相当甚至更好。整个实验总结在下表中。

ModelAverage FPStime(second)Distance scoreResult
PP-OCRv315.4132.442.39速度非常快,置信度高
PP-OCRv213.9635.83.16较PP-OCRv3,置信度稍低
SRN3.64137.353.05重量级算法,置信度与PP-OCRv2相差接近,但速度较慢
NRTR---重量级算法,置信度与PP-OCRv3相差不太,但速度较慢

在速度和准确性方面与官方实验结果一致:
ocr-03-14

 

三、实验结论

在这篇博文中,我们看到了 PaddleOCR 的强大功能。从其旗舰 PP-OCR 到最新的高级算法,PaddleOCR 表现出色。在某些情况下,PP-OCR 表现不佳,例如小文本、弯曲文本和手写文本。别担心,如果使用适当的数据进行训练,这些问题是可以解决的。

我们还测试了 PaddleOCR 提供的一些模型。总之,我们已经看到,PP-OCRv3 是一种非常强大的算法,可以提供与 NRTR 相当的结果,但速度非常快。SRN 是一种重量级算法,但与 PP-OCR 相比表现不佳。PaddleOCR 还提供了许多其他算法,如 SAR、RARE 等,你也可以自己尝试。

 

四、参考文献

opencv开源项目:https://github.com/spmallick/learnopencv/tree/master/Optical-Character-Recognition-using-PaddleOCR
opencv官方文档:https://learnopencv.com/optical-character-recognition-using-paddleocr/
paddlepaddle官方文档:https://www.paddlepaddle.org.cn/documentation/docs/zh/install/pip/windows-pip.html

系列攻略:
PaddleOCR #hello paddle: 从普通程序走向机器学习程序 - 初识机器学习
PaddleOCR #使用PaddleOCR进行光学字符识别(PP-OCR文本检测识别)

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

神经网络初谈

文章目录 简介神经网络的发展历程神经网络的初生神经网络的第一次折戟神经网络的新生,Hinton携BP算法登上历史舞台命途多舛,神经网络的第二次寒冬神经网络的重生,黄袍加身,一步封神神经网络的未来,众说纷纭其他时间点 …

vscode超炫酷的编码特效详解

1.在扩展中搜索 插件:Power Mode 2.在设置里搜索Code Actions On Save 3.点击在settings.json中编辑 {"powermode.enabled": true, //启动// "powermode.presets": "flames", // 火花效果 // 炸裂// "powermode.presets&quo…

uniapp项目或者vue项目 封装弹框组件

baseDialog组件代码: <template><view class"base-dialog" v-if"show"><view class"mask"></view><view class"Popmenu" :style"{ width }"><view class"header">{{ title …

【性能测试】Jenkins+Ant+Jmeter自动化框架的搭建思路

前言 前面讲了Jmeter在性能测试中的应用及扩展。随着测试的深入&#xff0c;我们发现在性能测试中也会遇到不少的重复工作。 比如某新兴业务处于上升阶段&#xff0c;需要在每个版本中&#xff0c;对某些新增接口进行性能测试&#xff0c;有时还需要在一天中的不同时段分别进行…

Objective-C 父元素和子元素的点击事件

场景&#xff1a; &#xff08;需求1&#xff09;pageA一开始是【默认模式】&#xff0c;点击父元素view&#xff08;包括【搜索】文字&#xff09;&#xff0c;进入【搜索模式】&#xff1b; &#xff08;需求2&#xff09;在pageA中&#xff0c;点击【取消】文字时&#xff…

随机数检测(二)

随机数检测&#xff08;二&#xff09;- 扑克检测、重叠子序列、游程总数、游程分布 3.4 扑克检测方法3.5 重叠子序列检测方法3.6 游程总数检测3.7 游程分布检测 3.4 扑克检测方法 扑克检测方法如下图。 以下实现代码供参考。 def alterOffsetBit(m, offset, listSub:list)…

浏览器基础原理-安全: HTTPS

HTTP协议的历史: HTTP协议的目的很单纯, 就是为了传输超文本文件, 所以早期的 HTTP 一直保持着明文传输数据的特征, 但是中间很有可能会被截取或者篡改, 即收到中间人攻击. 解析HTTP协议栈层面: HTTPS往里面加入了安全层, 它的指责是: 对发起HTTP请求的数据进行加密和对接收…

jupyter-notebook使用指南

jupyter-notebook使用指南 jupyter-notebook安装[python版][anaconda版] jupyter-notebook如何导出PDF&#xff1f;【没解决&#xff0c;直接看最后&#xff0c;不要跟着操作&#xff01;】正常导出步骤安装Pandoc安装Xelatex问题没解决&#xff0c;懒得安装了&#xff0c;放弃…

【Python】PIL.Image转QPixmap后运行异常的个人解决方法

问题场景&#xff1a; PIL.Image图片&#xff0c;直接调用PIL.Image.toqpixmap()转成QPixmap后&#xff0c;不会立即报错&#xff0c;   但后续使用该QPixmap时(包括但不仅限于使用QLabel.setPximap()、QPixmap.save())将立即出现异常 不知道是我关键词不对&#xff0c;还是只…

Linux中tail命令的使用

tail 命令可用于查看文件的内容&#xff0c;有一个常用的参数 -f 常用于查阅正在改变的日志文件。 tail -f filename 会把 filename 文件里的最尾部的内容显示在屏幕上&#xff0c;并且不断刷新&#xff0c;只要 filename 更新就可以看到最新的文件内容。 tail [参数] [文件] …

Leetcode 剑指 Offer II 033. 变位词组

题目难度: 中等 原题链接 今天继续更新 Leetcode 的剑指 Offer&#xff08;专项突击版&#xff09;系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~ 题目描述 给定一个字符串数组 strs &#xff0c;将 变位词 组合在一起。 可…

如何学习PHP语法和基本概念? - 易智编译EaseEditing

学习PHP语法和基本概念是成为一个合格的PHP开发者的第一步。以下是一些学习PHP语法和基本概念的建议&#xff1a; 官方文档&#xff1a; PHP官方提供了详细的文档&#xff0c;包括语言参考、函数参考和示例等。阅读官方文档是学习PHP语法和基本概念的最佳途径。你可以访问PHP…