作者:欧新宇(Xinyu OU)
当前版本:Release v2.0
开发平台:Paddle 2.5.2, PaddleOCR
运行环境:Intel Core i7-7700K CPU 4.2GHz, nVidia GeForce GTX 1080 Ti
本教案所涉及的数据集仅用于教学和交流使用,请勿用作商用。
最后更新:2024年5月23日
通信大数据行程卡,俗称“行程码”,是在2020年3月6日由中国信息通信研究院联合中国电信、中国移动、中国联通三家基础电信企业推出的服务。这一服务基于手机“信令数据”,通过用户手机所处的基站位置获取,为全国超过16亿手机用户免费提供查询服务。在疫情防控期间,该服务在锁定感染源、密切接触人群以及防控疫情传播方面发挥了重要作用。使用AI对通信大数据卡进行识别是一种简单的应用,相比传统的人工处理,大大提高了数据的处理效率,并且该方法具有广泛的应用场景,可以推广到各种基于图像的文本识别和统计应用中。
手机号码
、更新时间
、途径
、星号状态
、是否为绿码
等信息,样本以姓名
命名。实验难度:简单
实验摘要:根据任务需求安装和配置实验环境,本项目涉及Python基本编程环境、Paddle深度学习基础环境、PaddleOCR光学字符识别和OpenCV图像处理技术和Pandas数据结构的使用。
实验目标:
实验建议:
> pip install paddleocr -i https://pypi.tuna.tsinghua.edu.cn/simple
PaddleOCR-2.6.0
文件夹%cd ~/PaddleOCR-2.6.0/
%pip install -r requirements.txt
实验难度:一般
实验摘要:根据任务和代码需要载入相关的库文件
实验目标:
实验建议:
lang=ch|en
可以实现中英文识别的切换,超参数show_log=True|False
可以配置是否打印初识化过程中的日志信息。root_path
或者根目录root_path
来进行绝对路径的定位(路径变量名可根据习惯自行定义),以防止引用错误。在后续的输入输出时,均使用os.path.join()函数将工作路径匹配到操作路径。import os
import cv2
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
import pandas as pd
from paddleocr import PaddleOCR,draw_ocr
# 1. 初始化PaddleOCR
# 通过配置参数'lang'可以实现,英文'en'和中文'ch'字符识别的切换。
ocr = PaddleOCR(use_angle_cls=True, lang='ch', show_log=False) # (只需要运行一次)下载预训练模型,并将模型载入系统内存, 'show_log:True|False':显示运行日志
# 2. 这设置工作路径,'root_path' 指向本项目根路径,可根据实际情况进行修改
# Q1: 根据本地实际情况进行根目录和工作目录的定义
# 2.1 Windows
root_path = 'D:\Workspace\DeepLearning\WebsiteV2'
projcet_path = os.path.join(root_path, 'Data', 'Projects', 'Project001TravelCard')
# 2.2 Linux/Baidu AIStudio
# root_path = '/home/aistudio'
# projcet_path = os.path.join(root_path, 'work')
# 3. 配置图像获取路径,并获取 'Images' 路径下所有的图像样本。注意,为简化代码,该目录下只能保存待处理样本。
# Q2: 配置图像存储路径,并获取该路径下的所有图片的名称,并使用一个列表进行保存
img_path = # 配置图像路径
files = # 读取图像路径下的所有样本
n = # 获取样本数量
# 4. 设置需要从图像样本中获取的文本信息,并保存在DataFrame数据结构中
# Q3:创建一个DataFrame容器,包含6个列,分别是:姓名, 电话号码, 更新时间, 途经, 是否带星, 色彩。
df =
# 99. 测试并显示部分变量
print('样本总数:{}. \n 分别是:{}。'.format(n, files)) # 显示样本总数和图片列表
display(df) # 显示DataFrame表结构信息
[2024/05/24 20:59:04] ppocr DEBUG: Namespace(help='==SUPPRESS==', use_gpu=True, use_xpu=False, use_npu=False, ...
样本总数:12.
分别是:['刘备.jpeg', '刘达明.png', '张良武.jpeg', '拉丰.jpeg', '步惊风.jpg', '秦始皇.jpeg', '红卡弟.png', '肇八七.jpg', '苏灿.jpeg', '邓阿飞.png', '郭啸天.png', '黄卡哥.png']。
姓名 | 电话号码 | 更新时间 | 途经 | 是否带星 | 色彩 |
---|
实验难度:简单
实验摘要:使用Python的相关图像处理库及命令实现图像的载入和基本预处理
实验目标:
实验建议:
通信大数据行程卡
的采集通常使用中文名进行命名。常见的图像处理库包括OpenCV和PIL,但OpenCV对于中文字符支持不是特别友好,因此建议使用PIL进行图像读取;i = 5 # 读取第6个样本进行处理
# 1. 读取图像,并转换为numpy数组
img = Image.open(os.path.join(img_path, files[i])).convert('RGB') # 使用PIL库读取图像,并转换为RGB文件格式
img = np.array(img) # 将图像转换为numpy数组,便于后续的计算和处理
# 2. 对图像进行尺度规约
img = cv2.resize(img, dsize = [600,int(600*img.shape[0]/img.shape[1])]) # 将图片压缩至宽600像素,高随宽度进行自动缩放(此处宽度可根据情况进行修改定义)
# 99. 测试并显示部分变量
plt.figure(figsize=(8,8)) # 设置打印图的分辨率
plt.imshow(img) # 显示图像
<matplotlib.image.AxesImage at 0x260d8227f40>
实验难度:中等
实验摘要:使用多种图像处理方法实现图像的预处理,并按照需要将感兴趣区域切割出来
实验目标:使用OpenCV工具包,借助于色彩蒙版技术,将行程卡白色框内的有效信息部分分割出来
实验建议:
HSV|HLS
,2).定义感兴趣的色彩色阶范围, 3).创建色彩蒙版,4).生成蒙版图像,5).转换图像为单通道模式。cv2.findcontours()
函数通常会生成所有具有封闭性的区域作为轮廓。因此,需要根据特定任务对轮廓进行一定程度的过滤和筛选,尽量获取有效轮廓。最常见的筛选方法包括定义轮廓的长宽比例及定义轮廓的面积。本项目中对原始输入图像进行尺度规约就是为了方便统一输入图像的尺度从而使得感兴趣区域的面积具有比较明显的尺度。注意对于不同的任务可能会采用不同的过滤方法,并没有严格的通用规范。# Q5. 对读入的图像进行预处理,仅保留白色行程卡部分,并将这部分数据提取出来。目的是减少轮廓生成的数量,排除无用的信息
img_hls = # 将OpenCV默认颜色空间BGR转换为HLS
white_low = np.array([0,250,0]) # 定义白色色阶下限(需要查寻相关色谱表)
white_high = np.array([255,255,255]) # 定义白色色阶上限(需要查寻相关色谱表)
mask = # 根据色阶范围创建图像蒙版
img_mask = # 利用图像蒙版分割原始图像的白色区域,去除蒙版以外的部分
img_bin = # 将匹配获得的区域转换为灰度图用于后续生成轮廓,即8bit三通道整型数据CV_8UC3转换为8bit单通道整型数据CV_8UC1
# 2. 根据提取出来的白色行程卡区域图提取轮廓
contours, hierarchy = cv2.findContours(img_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 生成轮廓
# 3. 排除预处理后的区域中依然属于噪声的轮廓,并将符合条件的轮廓的外接矩形保存到感兴趣区域列表`rois`中。一般会排除面积较小,或长宽比不符合规定的。此处仅排除面积过小区域。注意,排除指定面积区域需要在前面进行尺度归一化的基础上进行处理。
rois = [] # 定义并初始化感兴趣区域列表,对符条件的轮廓区域保存其外接矩形信息
for c in range(len(contours)): # 遍历所有轮廓
x, y, w, h = cv2.boundingRect(contours[c]) # 输出轮廓的外接矩形的起点坐标、高度和宽度
area = cv2.contourArea(contours[c]) # 获取轮廓的面积
if area < 200000: # 测试轮廓的面积,小于指定面积的轮廓将被排除
continue
x_t, y_t, w_t, h_t = x, y, w, h
rois.append([x_t, y_t, w_t, h_t]) # 将符合条件的轮廓添加到rois列表中
# 3. 绘制轮廓框(只运行一次)
img = cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 10, 80, 0) # 绘制轮廓的外接矩形
img_ret = cv2.drawContours(img, contours, c, (0, 255, 0), 10, 8) # 绘制轮廓
# Q6:根据轮廓提取的结果,从roi列表种获取被切割出来的感兴趣区域,获得样本白色框区域内
print('第{}副图片:{},轮廓数:{}。)'.format(i, files[i],len(rois))) # 输出指定样本符合条件的轮廓数量(一般只应存在一个符合条件的轮廓)
roi = # 按照轮廓的外接矩形框将感兴趣区域切割出来用于后续的OCR
roi = # 将图像进行尺度归一化,宽度为500像素,高度按比例跟随变动
# 99. 可视化部分关键步骤
# 99.1 初始化图像显示框参数,配置分辨率参数
plt.figure(figsize=(6,6))
# 99.2 可视化图像处理后的各种图像
# plt.imshow(img_hls) # 可视化转换为hls色彩通道的原始图像
# plt.imshow(mask, cmap='gray') # 可视化蒙版图像
# plt.imshow(img_mask) # 可视化蒙版处理后的图像,此时为三通道图像
# plt.imshow(img_bin, cmap='gray') # 可视化二值化后的图像,此时为单通道图像(视觉上和三通道图像可能比较像)
# 99.3 可视化
# plt.imshow(img) # 显示绘制轮廓框后的原始图例(需要执行 3.绘制轮廓框/轮廓框外接矩形,此命令才有意义,否则将显示未处理前的图像)
plt.imshow(roi) # 显示轮廓切割后的感兴趣区域roi
# x = roi[150:450,100:400]
# plt.imshow(x) # 获取并显示带颜色的行程码图例包括绿色箭头, 黄色盾牌/黄色飞机和红色红心
第5副图片:秦始皇.jpeg,轮廓数:1。
<matplotlib.image.AxesImage at 0x260f8fd9640>
实验难度:困难
实验摘要:按照任务要求从图像中提取相关信息,包括姓名, 电话号码, 更新时间,途经,是否带星,色彩,并进行适当的处理提高适应性及抗样本错误能力。
实验目标:
实验建议:
通信大数据行程卡
中没有姓名信息,因此需要要求提交数据时以姓名对文件进行命名。若文件命名有其他格式,则此处需要做相应的处理。本项目以姓名命名为例。全角字符“:”
和半角字符“:”
之间的差异,需要进行统一,本项目统一为半角字符":"。“更新于:”
字段,并分别将日期和时间提取出来后,再进行组合成 [yyyy-mm-dd hh:mm:ss]
格式。到达或途经
字段,如果只输出地址信息,则需要排除前面的提示语和后面的备注(在存在星号时,后面有备注信息),我们可以通过查找前面的途经:
和后面的(注
来定位这些切割点,并利用字符串的索引方法将前后的无用信息去除。值得注意的是,在本例中,由于图像源清晰度不同,OCR识别可能出现问题。对于起点位置,可能会存在途经:
,途径:
和途经
等识别差异,因此需要进行一定的采样以获得可能出现的情况,并进行手动处理。对于终点位置,若为带星号,则会跟随备注信息,并以(注
开头;若无星号,则信息结束,可直接进行输出。对于行程字段,由于还可能同时存在多个地点,此时行程字段会被分成多行进行显示。因此,此时需要将多个字段的行程信息进行组合汇总,才能进行后续的处理。此外,由于我们已经使用颜色蒙版对信息框进行了事先分割处理,因此行程字段应该是处于切割出来的roi区域的最底部,换句话说OCR识别出来的列表的最后的几个元素都是行程信息。所以我们只要找到第一个条途经
信息,就可以顺序将列表后续的元素进行拼接获得完整的行程信息。*
匹配来说实现,若匹配成功则说明带星号,匹配失败则说明不带星号。# 本段代码用于从图像中获取姓名, 电话号码, 更新时间,途经,是否带星,色彩等信息。
# Q7:使用PaddleOCR库对roi区域进行文本识别
ocr_result = # 调用PaddleOCR库实现对感兴趣区域图片roi中的字符识别
# Q8. 根据输出要求处理相关字段
out_name = # 姓名字段,从图片的文件名中直接获取
for j in range(len(ocr_result)):
matching = ocr_result[j][1][0] # 获取第i副图像的第j个字段,用于匹配待输出的信息
if '动态行程卡' in matching: # 电话字段,半隐藏字段,且有后缀文字,需要将后缀文字去除
out_tel =
elif '更新于' in matching: # 时间字段,包含提示信息(“更新于”)及日期和时间,需要分别提取并组合成 [yyyy-mm-dd hh:mm:ss] 格式
out_date = matching.replace(':',':') # 替换所有全角字符的冒号为半角
out_date = out_date[4:14] + ' ' + out_date[14:] # 组合规定的时间格式
elif '到达' in matching: # 行程字段,匹配OCR识别出来的第一条行程信息
out_journey = ''
start = j
for k in range(start, len(ocr_result)): # 将OCR识别出来的第一条行程信息与后续的列表字段进行拼接,获得完整的行程信息
out_journey =
out_journey = out_journey.replace(':',':') # 替换行程信息中的全角引号为半角引号,解决识别中出现的错误
if out_journey.find('途经:') != -1: # 查找行程信息中地址信息的起点索引。
startid = out_journey.find('途经:') + 3
elif out_journey.find('途径:') != -1:
startid = out_journey.find('途径:') + 3
elif out_journey.find('途经') != -1:
startid = out_journey.find('途经') + 2
else:
startid = 0
endid = out_journey.find('(注') # 查找行程信息中地址信息的终点索引。
if endid != -1:
out_journey = out_journey[startid:endid]
else:
out_journey = out_journey[startid::]
out_isStar = # 根据行程信息中是否存在星号进行判断,并输出判断结果:是|否
# roi_sign = roi[150:430,100:400]
out_color = '未识别' # 颜色字段,本例未给出,有兴趣的同学可以在此次添加判断代码
# Q9. 将输出处理好的识别结果写入DataFrame列表中
df.loc[i] =
# 99. 数据表可视化
display(df)
姓名 | 电话号码 | 更新时间 | 途经 | 是否带星 | 色彩 | |
---|---|---|---|---|---|---|
5 | 秦始皇 | 138****5210 | 2021.09.28 16:24:03 | 辽宁省阜新市,天津市,吉林省长春市吉林省四平市,辽宁省锦州市,浙江省杭州市 | 否 | 未识别 |
实验难度:简单
实验摘要:将保存到DataFrame数据结构的信息输出到Excel电子表格
实验目标:学会将DataFrame的数据输处到Excel电子表格
实验建议:无
# Q10:将保存有识别信息的DataFrame表格保存到电子表格,路径为项目根目录
print('结果保存至{},完毕。'.format(projcet_path))
结果保存至D://Workspace//DeepLearning//Websitev2\Data\Projects\Project001TravelCard,完毕。
实验难度:简单
实验摘要:将指定文件夹中所有待处理的样本图片,经过处理后输出到Excel电子表格
实验目标:学会批量处理数据文件
实验建议:一般来说,批量处理数据只需要进行循环操作即可,在本例中我们可以完成基本环境的设置,包括OCR模型准备、路径定义等,然后使用for循环去遍历整个样本文件夹,并依次进行处理,处理后的文本数据先保存到DataFrame列表中,最后将DataFrame列表中的数据输出到Excel电子表格中。
# Q11:完成如下批量输出代码
开始打印文本提取结果...
已完成:[0/12] 刘备: 西藏自治区山南市,陕西省西安市,西藏自治区拉萨市,北京市,西藏自治区林芝市
已完成:[1/12] 刘达明: 江西省赣州市
已完成:[2/12] 张良武: 河南省郑州市河南省周口市,河南省驻马店市,湖北省武汉市,湖南省长沙市,广东省深圳市
已完成:[3/12] 拉丰: 天津市,美国
已完成:[4/12] 步惊风: 北京市,四川省成都市*
已完成:[5/12] 秦始皇: 辽宁省阜新市,天津市,吉林省长春市,吉林省四平市,辽宁省锦州市,浙江省杭州市
已完成:[6/12] 红卡弟: 湖北黄网
已完成:[7/12] 肇八七: 云南省昆明市
已完成:[8/12] 苏灿: 江苏省南京市*
已完成:[9/12] 邓阿飞: 江西省南昌市,江西省宜春市,江西省吉安市,江西省赣州市
已完成:[10/12] 郭啸天: 江西省赣州市
已完成:[11/12] 黄卡哥: 日本
姓名 | 电话号码 | 更新时间 | 途经 | 是否带星 | 色彩 | |
---|---|---|---|---|---|---|
0 | 刘备 | 138****1537 | 2020.06.19 00:23:30 | 西藏自治区山南市,陕西省西安市,西藏自治区拉萨市,北京市,西藏自治区林芝市 | 否 | 未识别 |
0 | 刘备 | 138****1537 | 2020.06.19 00:23:30 | 西藏自治区山南市,陕西省西安市,西藏自治区拉萨市,北京市,西藏自治区林芝市 | 否 | 未识别 |
1 | 刘达明 | 181****2855 | 2020.05.12 13:43:04 | 江西省赣州市 | 否 | 未识别 |
2 | 张良武 | 188****5333 | 2020.04.16 11:12:26 | 河南省郑州市河南省周口市,河南省驻马店市,湖北省武汉市,湖南省长沙市,广东省深圳市 | 否 | 未识别 |
3 | 拉丰 | 188****3980 | 2020.07.02 16:22:15 | 天津市,美国 | 否 | 未识别 |
4 | 步惊风 | 186****0023 | 2022.09.03 17:44:39 | 北京市,四川省成都市* | 是 | 未识别 |
5 | 秦始皇 | 138****5210 | 2021.09.28 16:24:03 | 辽宁省阜新市,天津市,吉林省长春市,吉林省四平市,辽宁省锦州市,浙江省杭州市 | 否 | 未识别 |
6 | 红卡弟 | 188****1880 | 2020.07.02 16:22:15 | 湖北黄网 | 否 | 未识别 |
7 | 肇八七 | 186****0023 | 2022.09.03 17:44:39 | 云南省昆明市 | 否 | 未识别 |
8 | 苏灿 | 133****9346 | 2022.06.28 11:04:26 | 江苏省南京市* | 是 | 未识别 |
9 | 邓阿飞 | 150****7181 | 2020.05.12 11:56:03 | 江西省南昌市,江西省宜春市,江西省吉安市,江西省赣州市 | 否 | 未识别 |
10 | 郭啸天 | 180****5615 | 2020.05.12 11:46:57 | 江西省赣州市 | 否 | 未识别 |
11 | 黄卡哥 | 188****1880 | 2020.07.02 16:22:15 | 日本 | 否 | 未识别 |
结果保存至D://Workspace//DeepLearning//Websitev2\Data\Projects\Project001TravelCard,完毕。