# 一种基于PaddleOCR的产品包装生产日期识别模型 - [1. 项目介绍](#1-项目介绍) - [2. 环境搭建](#2-环境搭建) - [3. 数据准备](#3-数据准备) - [4. 直接使用PP-OCRv3模型评估](#4-直接使用PPOCRv3模型评估) - [5. 基于合成数据finetune](#5-基于合成数据finetune) - [5.1 Text Renderer数据合成方法](#51-TextRenderer数据合成方法) - [5.1.1 下载Text Renderer代码](#511-下载TextRenderer代码) - [5.1.2 准备背景图片](#512-准备背景图片) - [5.1.3 准备语料](#513-准备语料) - [5.1.4 下载字体](#514-下载字体) - [5.1.5 运行数据合成命令](#515-运行数据合成命令) - [5.2 模型训练](#52-模型训练) - [6. 基于真实数据finetune](#6-基于真实数据finetune) - [6.1 python爬虫获取数据](#61-python爬虫获取数据) - [6.2 数据挖掘](#62-数据挖掘) - [6.3 模型训练](#63-模型训练) - [7. 基于合成+真实数据finetune](#7-基于合成+真实数据finetune) ## 1. 项目介绍 产品包装生产日期是计算机视觉图像识别技术在工业场景中的一种应用。产品包装生产日期识别技术要求能够将产品生产日期从复杂背景中提取并识别出来,在物流管理、物资管理中得到广泛应用。 ![](https://ai-studio-static-online.cdn.bcebos.com/d9e0533cc1df47ffa3bbe99de9e42639a3ebfa5bce834bafb1ca4574bf9db684) - 项目难点 1. 没有训练数据 2. 图像质量层次不齐: 角度倾斜、图片模糊、光照不足、过曝等问题严重 针对以上问题, 本例选用PP-OCRv3这一开源超轻量OCR系统进行包装产品生产日期识别系统的开发。直接使用PP-OCRv3进行评估的精度为62.99%。为提升识别精度,我们首先使用数据合成工具合成了3k数据,基于这部分数据进行finetune,识别精度提升至73.66%。由于合成数据与真实数据之间的分布存在差异,为进一步提升精度,我们使用网络爬虫配合数据挖掘策略得到了1k带标签的真实数据,基于真实数据finetune的精度为71.33%。最后,我们综合使用合成数据和真实数据进行finetune,将识别精度提升至86.99%。各策略的精度提升效果如下: | 策略 | 精度| | :--------------- | :-------- | | PP-OCRv3评估 | 62.99| | 合成数据finetune | 73.66| | 真实数据finetune | 71.33| | 真实+合成数据finetune | 86.99| AIStudio项目链接: [一种基于PaddleOCR的包装生产日期识别方法](https://aistudio.baidu.com/aistudio/projectdetail/4287736) ## 2. 环境搭建 本任务基于Aistudio完成, 具体环境如下: - 操作系统: Linux - PaddlePaddle: 2.3 - PaddleOCR: Release/2.5 - text_renderer: master 下载PaddlleOCR代码并安装依赖库: ```bash git clone -b dygraph https://gitee.com/paddlepaddle/PaddleOCR # 安装依赖库 cd PaddleOCR pip install -r PaddleOCR/requirements.txt ``` ## 3. 数据准备 本项目使用人工预标注的300张图像作为测试集。 部分数据示例如下: ![](https://ai-studio-static-online.cdn.bcebos.com/39ff30e0ab0442579712255e6a9ea6b5271169c98e624e6eb2b8781f003bfea0) 标签文件格式如下: ```txt 数据路径 标签(中间以制表符分隔) ``` |数据集类型|数量| |---|---| |测试集| 300| 数据集[下载链接](https://aistudio.baidu.com/aistudio/datasetdetail/149770),下载后可以通过下方命令解压: ```bash tar -xvf data.tar mv data ${PaddleOCR_root} ``` 数据解压后的文件结构如下: ```shell PaddleOCR ├── data │ ├── mining_images # 挖掘的真实数据示例 │ ├── mining_train.list # 挖掘的真实数据文件列表 │ ├── render_images # 合成数据示例 │ ├── render_train.list # 合成数据文件列表 │ ├── val # 测试集数据 │ └── val.list # 测试集数据文件列表 | ├── bg # 合成数据所需背景图像 │ └── corpus # 合成数据所需语料 ``` ## 4. 直接使用PP-OCRv3模型评估 准备好测试数据后,可以使用PaddleOCR的PP-OCRv3模型进行识别。 - 下载预训练模型 首先需要下载PP-OCR v3中英文识别模型文件,下载链接可以在https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.5/doc/doc_ch/ppocr_introduction.md#6 获取,下载命令: ```bash cd ${PaddleOCR_root} mkdir ckpt wget -nc -P ckpt https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_rec_train.tar pushd ckpt/ tar -xvf ch_PP-OCRv3_rec_train.tar popd ``` - 模型评估 使用以下命令进行PP-OCRv3评估: ```bash python tools/eval.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml \ -o Global.checkpoints=ckpt/ch_PP-OCRv3_rec_train/best_accuracy \ Eval.dataset.data_dir=./data \ Eval.dataset.label_file_list=["./data/val.list"] ``` 其中各参数含义如下: ```bash -c: 指定使用的配置文件,ch_PP-OCRv3_rec_distillation.yml对应于OCRv3识别模型。 -o: 覆盖配置文件中参数 Global.checkpoints: 指定评估使用的模型文件路径 Eval.dataset.data_dir: 指定评估数据集路径 Eval.dataset.label_file_list: 指定评估数据集文件列表 ``` ## 5. 基于合成数据finetune ### 5.1 Text Renderer数据合成方法 #### 5.1.1 下载Text Renderer代码 首先从github或gitee下载Text Renderer代码,并安装相关依赖。 ```bash git clone https://gitee.com/wowowoll/text_renderer.git # 安装依赖库 cd text_renderer pip install -r requirements.txt ``` 使用text renderer合成数据之前需要准备好背景图片、语料以及字体库,下面将逐一介绍各个步骤。 #### 5.1.2 准备背景图片 观察日常生活中常见的包装生产日期图片,我们可以发现其背景相对简单。为此我们可以从网上找一下图片,截取部分图像块作为背景图像。 本项目已准备了部分图像作为背景图片,在第3部分完成数据准备后,可以得到我们准备好的背景图像,示例如下: ![](https://ai-studio-static-online.cdn.bcebos.com/456ae2acb27d4a94896c478812aee0bc3551c703d7bd40c9be4dc983c7b3fc8a) 背景图像存放于如下位置: ```shell PaddleOCR ├── data | ├── bg # 合成数据所需背景图像 ``` #### 5.1.3 准备语料 观察测试集生产日期图像,我们可以知道如下数据有如下特点: 1. 由年月日组成,中间可能以“/”、“-”、“:”、“.”或者空格间隔,也可能以汉字年月日分隔 2. 有些生产日期包含在产品批号中,此时可能包含具体时间、英文字母或数字标识 基于以上两点,我们编写语料生成脚本: ```python import random from random import choice import os cropus_num = 2000 #设置语料数量 def get_cropus(f): # 随机生成年份 year = random.randint(0, 22) # 随机生成月份 month = random.randint(1, 12) # 随机生成日期 day_dict = {31: [1,3,5,7,8,10,12], 30: [4,6,9,11], 28: [2]} for item in day_dict: if month in day_dict[item]: day = random.randint(0, item) # 随机生成小时 hours = random.randint(0, 24) # 随机生成分钟 minute = random.randint(0, 60) # 随机生成秒数 second = random.randint(0, 60) # 随机生成产品标识字符 length = random.randint(0, 6) file_id = [] flag = 0 my_dict = [i for i in range(48,58)] + [j for j in range(40, 42)] + [k for k in range(65,90)] # 大小写字母 + 括号 for i in range(1, length): if flag: if i == flag+2: #括号匹配 file_id.append(')') flag = 0 continue sel = choice(my_dict) if sel == 41: continue if sel == 40: if i == 1 or i > length-3: continue flag = i my_ascii = chr(sel) file_id.append(my_ascii) file_id_str = ''.join(file_id) #随机生成产品标识字符 file_id2 = random.randint(0, 9) rad = random.random() if rad < 0.3: f.write('20{:02d}{:02d}{:02d} {}'.format(year, month, day, file_id_str)) elif 0.3 < rad < 0.5: f.write('20{:02d}年{:02d}月{:02d}日'.format(year, month, day)) elif 0.5 < rad < 0.7: f.write('20{:02d}/{:02d}/{:02d}'.format(year, month, day)) elif 0.7 < rad < 0.8: f.write('20{:02d}-{:02d}-{:02d}'.format(year, month, day)) elif 0.8 < rad < 0.9: f.write('20{:02d}.{:02d}.{:02d}'.format(year, month, day)) else: f.write('{:02d}:{:02d}:{:02d} {:02d}'.format(hours, minute, second, file_id2)) if __name__ == "__main__": file_path = '/home/aistudio/text_renderer/my_data/cropus' if not os.path.exists(file_path): os.makedirs(file_path) file_name = os.path.join(file_path, 'books.txt') f = open(file_name, 'w') for i in range(cropus_num): get_cropus(f) if i < cropus_num-1: f.write('\n') f.close() ``` 本项目已准备了部分语料,在第3部分完成数据准备后,可以得到我们准备好的语料库,默认位置如下: ```shell PaddleOCR ├── data │ └── corpus #合成数据所需语料 ``` #### 5.1.4 下载字体 观察包装生产日期,我们可以发现其使用的字体为点阵体。字体可以在如下网址下载: https://www.fonts.net.cn/fonts-en/tag-dianzhen-1.html 本项目已准备了部分字体,在第3部分完成数据准备后,可以得到我们准备好的字体,默认位置如下: ```shell PaddleOCR ├── data │ └── fonts #合成数据所需字体 ``` 下载好字体后,还需要在list文件中指定字体文件存放路径,脚本如下: ```bash cd text_renderer/my_data/ touch fonts.list ls /home/aistudio/PaddleOCR/data/fonts/* > fonts.list ``` #### 5.1.5 运行数据合成命令 完成数据准备后,my_data文件结构如下: ```shell my_data/ ├── cropus │ └── books.txt #语料库 ├── eng.txt #字符列表 └── fonts.list #字体列表 ``` 在运行合成数据命令之前,还有两处细节需要手动修改: 1. 将默认配置文件`text_renderer/configs/default.yaml`中第9行enable的值设为`true`,即允许合成彩色图像。否则合成的都是灰度图。 ```yaml # color boundary is in R,G,B format font_color: + enable: true #false ``` 2. 将`text_renderer/textrenderer/renderer.py`第184行作如下修改,取消padding。否则图片两端会有一些空白。 ```python padding = random.randint(s_bbox_width // 10, s_bbox_width // 8) #修改前 padding = 0 #修改后 ``` 运行数据合成命令: ```bash cd /home/aistudio/text_renderer/ python main.py --num_img=3000 \ --fonts_list='./my_data/fonts.list' \ --corpus_dir "./my_data/cropus" \ --corpus_mode "list" \ --bg_dir "/home/aistudio/PaddleOCR/data/bg/" \ --img_width 0 ``` 合成好的数据默认保存在`text_renderer/output`目录下,可进入该目录查看合成的数据。 合成数据示例如下 ![](https://ai-studio-static-online.cdn.bcebos.com/d686a48d465a43d09fbee51924fdca42ee21c50e676646da8559fb9967b94185) 数据合成好后,还需要生成如下格式的训练所需的标注文件, ``` 图像路径 标签 ``` 使用如下脚本即可生成标注文件: ```python import random abspath = '/home/aistudio/text_renderer/output/default/' #标注文件生成路径 fout = open('./render_train.list', 'w', encoding='utf-8') with open('./output/default/tmp_labels.txt','r') as f: lines = f.readlines() for item in lines: label = item[9:] filename = item[:8] + '.jpg' fout.write(abspath + filename + '\t' + label) fout.close() ``` 经过以上步骤,我们便完成了包装生产日期数据合成。 数据位于`text_renderer/output`,标注文件位于`text_renderer/render_train.list`。 本项目提供了生成好的数据供大家体验,完成步骤3的数据准备后,可得数据路径位于: ```shell PaddleOCR ├── data │ ├── render_images # 合成数据示例 │ ├── render_train.list #合成数据文件列表 ``` ### 5.2 模型训练 准备好合成数据后,我们可以使用以下命令,利用合成数据进行finetune: ```bash cd ${PaddleOCR_root} python tools/train.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml \ -o Global.pretrained_model=./ckpt/ch_PP-OCRv3_rec_train/best_accuracy \ Global.epoch_num=20 \ Global.eval_batch_step='[0, 20]' \ Train.dataset.data_dir=./data \ Train.dataset.label_file_list=['./data/render_train.list'] \ Train.loader.batch_size_per_card=64 \ Eval.dataset.data_dir=./data \ Eval.dataset.label_file_list=["./data/val.list"] \ Eval.loader.batch_size_per_card=64 ``` 其中各参数含义如下: ```txt -c: 指定使用的配置文件,ch_PP-OCRv3_rec_distillation.yml对应于OCRv3识别模型。 -o: 覆盖配置文件中参数 Global.pretrained_model: 指定finetune使用的预训练模型 Global.epoch_num: 指定训练的epoch数 Global.eval_batch_step: 间隔多少step做一次评估 Train.dataset.data_dir: 训练数据集路径 Train.dataset.label_file_list: 训练集文件列表 Train.loader.batch_size_per_card: 训练单卡batch size Eval.dataset.data_dir: 评估数据集路径 Eval.dataset.label_file_list: 评估数据集文件列表 Eval.loader.batch_size_per_card: 评估单卡batch size ``` ## 6. 基于真实数据finetune 使用合成数据finetune能提升我们模型的识别精度,但由于合成数据和真实数据之间的分布可能有一定差异,因此作用有限。为进一步提高识别精度,本节介绍如何挖掘真实数据进行模型finetune。 数据挖掘的整体思路如下: 1. 使用python爬虫从网上获取大量无标签数据 2. 使用模型从大量无标签数据中构建出有效训练集 ### 6.1 python爬虫获取数据 - 推荐使用[爬虫工具](https://github.com/Joeclinton1/google-images-download)获取无标签图片。 图片获取后,可按如下目录格式组织: ```txt sprider ├── file.list ├── data │ ├── 00000.jpg │ ├── 00001.jpg ... ``` ### 6.2 数据挖掘 我们使用PaddleOCR对获取到的图片进行挖掘,具体步骤如下: 1. 使用 PP-OCRv3检测模型+svtr-tiny识别模型,对每张图片进行预测。 2. 使用数据挖掘策略,得到有效图片。 3. 将有效图片对应的图像区域和标签提取出来,构建训练集。 首先下载预训练模型,PP-OCRv3检测模型下载链接:https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_det_infer.tar 如需获取svtr-tiny高精度中文识别预训练模型,请扫码填写问卷,加入PaddleOCR官方交流群获取全部OCR垂类模型下载链接、《动手学OCR》电子书等全套OCR学习资料🎁